[Service Name]
A single-purpose FastAPI service. Async by default. Postgres for state. Dockerized.
Source of truth
Production runs as a container on Fly or Railway. The Dockerfile + locked requirements.txt define what runs. Local mirrors via docker compose up.
Tech stack
Python 3.13 + FastAPI 0.115 + Uvicorn. Pydantic v2 for request and response schemas. SQLAlchemy 2.x with the async API. Alembic for migrations. structlog for JSON logs. pytest + httpx for tests (real ASGI calls, no test client wrapping). uv for dependency management (way faster than pip).
Deploy
Build the Docker image, push to Fly or Railway. Health check at /healthz. Graceful shutdown via SIGTERM (FastAPI handles it).
File map
app/main.pyFastAPI app + route mountingapp/api/routers, one per resourceapp/schemas/Pydantic models (request, response)app/models/SQLAlchemy ORM modelsapp/db.pyengine + session factoryapp/deps.pyreusable dependencies (auth, db session)app/settings.pyPydantic Settings (env loading)alembic/migration historytests/pytest specsDockerfileslim Python image, multi-stage
.env keys
DATABASE_URLpostgresql+asyncpg://...API_KEYshared secret for inbound auth (if no JWT)LOG_LEVELSENTRY_DSNoptional
Hard rules
- Every endpoint declares response_model. No untyped JSON dicts.
- DB sessions via FastAPI
Depends. Never instantiateAsyncSessionin a handler. - Migrations via Alembic auto-generate + manual review. Never edit applied migrations.
- Settings via Pydantic Settings class. No
os.environ.getin business code. pytestruns against a throwaway Postgres in CI. No mocks for the DB layer.- All structured logs include
request_idset in middleware.
Recent significant changes
- 2026-05-06: Scaffolded. Locked: Pydantic v2 (faster), SQLAlchemy 2.x async (not Tortoise), uv (not poetry).
Next session: start here
uv venv && uv syncto install.- Create Postgres locally with
docker compose up db. alembic upgrade headto apply schema.uvicorn app.main:app --reload.- Test
/healthz, then implement the first business route.