Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=lessongen
POSTGRES_USER=lessongen
POSTGRES_PASSWORD=lessongen
DATABASE_URL=postgresql+psycopg2://lessongen:lessongen@localhost:5432/lessongen
SECRET_KEY=change_me
APP_VERSION=0.1.0
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
OPENAI_API_KEY=
GC_API_SCOPES=https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/documents
40 changes: 40 additions & 0 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Node CI

on:
push:
paths:
- "frontend/**"
- ".github/workflows/node-ci.yml"
pull_request:
paths:
- "frontend/**"
- ".github/workflows/node-ci.yml"

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install dependencies
working-directory: frontend
run: npm install

- name: Lint
working-directory: frontend
run: npm run lint

- name: Typecheck
working-directory: frontend
run: npm run build -- --mode development

- name: Tests
working-directory: frontend
run: npm test -- --run
45 changes: 45 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Python CI

on:
push:
paths:
- "backend/**"
- ".github/workflows/python-ci.yml"
pull_request:
paths:
- "backend/**"
- ".github/workflows/python-ci.yml"

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install Poetry
uses: abatilo/actions-poetry@v2
with:
poetry-version: "1.7.1"

- name: Install dependencies
working-directory: backend
run: |
poetry install --no-interaction --no-ansi

- name: Lint
working-directory: backend
run: |
poetry run ruff check .
poetry run black --check .
poetry run mypy app

- name: Tests
working-directory: backend
run: |
poetry run pytest -q
30 changes: 30 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Python
__pycache__/
*.py[cod]
*.sqlite3
.env
.venv/
.poetry/

# Node
node_modules/
dist/
*.log

# OS
.DS_Store
Thumbs.db

# IDE
.vscode/*.log
.vscode/.ropeproject

# Alembic
backend/migrations/__pycache__/

# Coverage
htmlcov/
.coverage

# Misc
*.swp
27 changes: 27 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "FastAPI: Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}/backend",
"remoteRoot": "/app"
}
]
},
{
"name": "Frontend: Chrome",
"request": "launch",
"type": "pwa-chrome",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/frontend/src"
}
]
}
16 changes: 16 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"editor.formatOnSave": true,
"python.formatting.provider": "black",
"python.linting.enabled": true,
"python.linting.mypyEnabled": true,
"python.linting.ruffEnabled": true,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
37 changes: 37 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Docker: Up",
"type": "shell",
"command": "make up"
},
{
"label": "Docker: Down",
"type": "shell",
"command": "make down"
},
{
"label": "API: Dev",
"type": "shell",
"command": "make api",
"problemMatcher": []
},
{
"label": "Web: Dev",
"type": "shell",
"command": "make web",
"problemMatcher": []
},
{
"label": "Tests: API",
"type": "shell",
"command": "cd backend && pytest -q"
},
{
"label": "Tests: Web",
"type": "shell",
"command": "cd frontend && npm test"
}
]
}
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.PHONY: up down api web test fmt lint migrate seed

up:
@docker compose up -d

down:
@docker compose down -v

api:
@cd backend && uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

web:
@cd frontend && npm run dev

test:
@cd backend && pytest -q
@cd frontend && npm test -- --run

fmt:
@cd backend && ruff check --fix . && black .
@cd frontend && npm run format

lint:
@cd backend && ruff check . && mypy app
@cd frontend && npm run lint

migrate:
@cd backend && alembic upgrade head

seed:
@cd backend && python -m app.scripts.seed_demo
20 changes: 20 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3.11-slim AS base

ENV PYTHONUNBUFFERED=1 \
POETRY_VERSION=1.7.1

RUN apt-get update && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*

RUN pip install "poetry==${POETRY_VERSION}"

WORKDIR /app

COPY pyproject.toml /app/
RUN poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-ansi

COPY app /app/app

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
9 changes: 9 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# LessonGen Backend

FastAPI application providing LessonGen APIs. Key commands:

```bash
poetry install
poetry run uvicorn app.main:app --reload
poetry run pytest
```
35 changes: 35 additions & 0 deletions backend/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[alembic]
script_location = migrations
sqlalchemy.url = postgresql+psycopg2://lessongen:lessongen@db:5432/lessongen

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console

[logger_sqlalchemy]
level = WARN
handlers = console
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers = console
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
4 changes: 4 additions & 0 deletions backend/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""LessonGen FastAPI application package."""
from .main import app

__all__ = ["app"]
4 changes: 4 additions & 0 deletions backend/app/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""API package."""
from .routes import api_router

__all__ = ["api_router"]
22 changes: 22 additions & 0 deletions backend/app/api/health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Health check endpoints."""
from __future__ import annotations

from fastapi import APIRouter

from app.core.config import settings

router = APIRouter()


@router.get("/health", summary="Application health check")
def healthcheck() -> dict[str, str]:
"""Return a simple health response."""

return {"status": "ok"}


@router.get("/version", summary="Application version")
def version() -> dict[str, str]:
"""Return the deployed application version."""

return {"version": settings.app_version}
9 changes: 9 additions & 0 deletions backend/app/api/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""API router configuration."""
from __future__ import annotations

from fastapi import APIRouter

from . import health

api_router = APIRouter()
api_router.include_router(health.router, tags=["health"])
4 changes: 4 additions & 0 deletions backend/app/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Core configuration and security utilities."""
from .config import settings

__all__ = ["settings"]
Loading
Loading