# {{service_name}} {{service_purpose}} Python service built with FastAPI. Dependencies and environments are managed with uv. Source package: `{{package_dir}}`. ## Commands - Install / sync environment: `uv sync` - Run the app locally: `uv run uvicorn {{app_module}} --reload` - Tests: `uv run pytest` (single test: `uv run pytest path/to/test_file.py::test_name -q`) - Lint: `uv run ruff check .` (autofix: `uv run ruff check . --fix`) - Format: `uv run ruff format .` - Type check: `{{type_checker_cmd}}` - Add a dependency: `uv add ` (dev: `uv add --dev `). Ask first. - New migration: `uv run alembic revision --autogenerate -m ""` - Apply migrations locally: `uv run alembic upgrade head` Before finishing a task: format, lint, type check, and run the tests related to the change. ## API conventions - Separate request and response models (Pydantic). Do not return ORM objects directly; set `response_model` on routes. - Response models must not include internal fields (password hashes, internal IDs not meant for clients, tokens). - Use dependencies (`Depends`) for the database session, current user, and permission checks. Do not open sessions inside route bodies. - Authorization is checked in the route or a dependency for every endpoint that touches user-owned data. Scope queries to the current user or tenant. - Use the correct status codes: 201 for create, 204 for delete without body, 404 for missing resources the user may access, 403 for forbidden, 422 is produced by validation. - Raise `HTTPException` with messages safe to show to clients. Log details server-side. - Keep routers thin. Put business logic in service functions that take plain arguments and are testable without HTTP. ## Async rules - Do not call blocking I/O (`requests`, synchronous DB drivers, `time.sleep`, large file reads) inside `async def` routes. Use async libraries (`httpx.AsyncClient`, async DB drivers), or declare the route with plain `def` so FastAPI runs it in a thread pool. - Set timeouts on all outbound HTTP calls. - Reuse HTTP clients and DB engines created at startup (lifespan) instead of creating them per request. ## Database ({{db}}) - Migrations are created with Alembic autogenerate and then reviewed by hand. Autogenerate shows renames as drop plus add; fix those to preserve data. - Never edit a migration that has been merged. Create a new one. - Every migration has a `downgrade()` that works, or a comment explaining why it cannot. - Large data backfills do not go in schema migrations. ## Configuration - Settings come from environment variables through the project's settings module (for example a `pydantic-settings` `BaseSettings` class). Do not read `os.environ` elsewhere. - New settings: add to the settings class with a type and default where safe, and to `.env.example` with a placeholder. ## Tests - pytest with fixtures in `conftest.py`. Use the FastAPI test client or `httpx.AsyncClient` against the app. - Override dependencies with `app.dependency_overrides` for auth and external services; clear overrides after each test. - No real network calls in tests. Use a test database or transactions rolled back per test, following the existing fixtures. - Every bug fix includes a test that fails without the fix. ## Do not do without asking - Add, remove or upgrade dependencies (`pyproject.toml`, `uv.lock`). - Edit `.env` or any secrets. - Run migrations or scripts against shared, staging or production databases. - Change authentication, CORS or middleware configuration.