A full-stack starter with a FastAPI + PostgreSQL backend and a Next.js 16 (App Router) frontend, wired together with Docker Compose and Traefik.
- Backend (
backend/) — FastAPI, SQLModel, PostgreSQL, Alembic, JWT auth, and an AI chat built on LangChain Deep Agents (OpenAI, streamed over AG-UI). - Frontend (
frontend/) — Next.js 16 (App Router), React, TypeScript, Tailwind CSS, shadcn/ui on Base UI, and the AI chat on assistant-ui. - Infra (
infra/) — Docker Compose + Traefik, Mailpit for local email, Playwright for end-to-end tests.
From the project root, run:
./up.shThis resets and rebuilds the stack, runs migrations, and starts it with hot reload. The script prints the app URL and the login to use.
To iterate on one side directly instead, run uv run fastapi dev (from backend/) or bun run dev (from frontend/) against the Compose Postgres.
Settings live in backend/.env, and backend/.env.example lists them. Change the secrets and passwords before deploying anywhere. The AI chat turns on when an OpenAI API key is set.
The backend's Pydantic models are the source of truth. After changing them or any route, regenerate the OpenAPI spec and the typed frontend client:
bash scripts/generate-client.shThe frontend calls the API only through the generated client, and the pre-commit hook, the backend tests and CI fail when it is stale.
./up.sh and bun install (in frontend/) install the git hooks (prek), which run the same checks as the pre-commit workflow. Run them on demand with uv run prek run --all-files.
- Backend:
bash scripts/test.sh(from the project root). - Frontend unit tests:
bun run test:unit(fromfrontend/). - Frontend end-to-end:
docker compose run --rm playwright bunx playwright test.
Production runs behind Traefik with automatic HTTPS via infra/docker-compose.deploy.yml. Set DOMAIN and the secrets as environment variables on the host, then:
docker compose -f infra/docker-compose.yml -f infra/docker-compose.deploy.yml up -dMigrations run automatically before the backend starts. To have a failed migration stop a deploy before anything is replaced, run the prestart service first.
If you put a CDN or load balancer in front, set the trusted proxy settings in infra/docker-compose.deploy.yml, cache only the landing page and static files, and verify the setup with bun run check:headers https://your-domain (from frontend/).