# Backend — FastAPI + PostGIS ## Stack - FastAPI (async), asyncpg connection pool, Pydantic v2 settings - PostGIS via GeoAlchemy2, spatial queries with Shapely - Auth: python-jose + passlib (JWT/bcrypt) ## Structure ``` backend/ main.py # App entry, CORS, router registration database.py # asyncpg pool, Settings from .env models.py # Pydantic response/request models routers/ # One file per domain (risk, alerts, cases, grid, etc.) app/ # Legacy code (routers/cases.py, routers/grid.py, performance.py) ``` ## Patterns - Routers: `APIRouter()` with prefix, registered in `main.py` via `app.include_router()` - DB access: `async with db.get_connection()` context manager (global `db` singleton) - Settings: `pydantic_settings.BaseSettings` loaded from `.env` at module level - Endpoints return Pydantic models, not raw dicts ## Running ```bash cd backend source venv/bin/activate uvicorn main:app --reload --port 8000 ``` ## Anti-Patterns - Don't use sync database drivers — always asyncpg - Don't put business logic in routers — delegate to service functions - Don't hardcode DB credentials — use Settings from environment - Don't skip Pydantic validation on request/response bodies - Don't import from `app/` — it's legacy, prefer top-level modules