Production-oriented backend template: FastAPI + Clean/DDD + SQLAlchemy + Postgres + Redis + Alembic + JWT.
- Quick Start
- Technology Stack
- Navigation by Task
- Compose Scopes
- Release and CI
- Detailed Guides
- Smoke Checks
- Quality Gates
- Q&A
Release / Релиз: https://github.com/gorodtx/fastapi-template/releases/latest
cp .env.example .env
docker compose -f compose/data.yaml up -d
DOCKER_BUILD_NETWORK=host docker compose -f compose/data.yaml -f compose/migrate.yaml run --rm migrate
docker compose -f compose/data.yaml -f compose/app.yaml up -d --buildexport APP_IMAGE=ghcr.io/<owner>/fastapi-template-app:vX.Y.Z
export MIGRATE_IMAGE=ghcr.io/<owner>/fastapi-template-migrate:vX.Y.Z
export NGINX_IMAGE=ghcr.io/<owner>/fastapi-template-nginx:vX.Y.Z
docker compose -f compose/data.yaml up -d
docker compose -f compose/data.yaml -f compose/migrate.yaml -f compose/release.yaml run --rm migrate
docker compose -f compose/data.yaml -f compose/release.yaml up -ddocker compose -f compose/data.yaml -f compose/app.yaml -f compose/obs.yaml up -d --buildcompose/obs.yaml (и compose/obs.hostnet.yaml) автоматически включает
OBS_OTEL_ENABLED=true для app, чтобы метрики/трейсы начинали поступать
сразу после поднятия observability-скоупа.
| Task / Задача | Go to / Ссылка |
|---|---|
| Architecture, layers, transaction model | docs/guide.en.md |
| Архитектура, слои, транзакции | docs/guide.ru.md |
| RBAC contract + migrations | docs/guide.en.md |
| RBAC-контракт + миграции | docs/guide.ru.md |
| Environment variables | docs/guide.en.md |
| Переменные окружения | docs/guide.ru.md |
| Runtime/compose commands | docs/guide.en.md |
| Команды запуска/compose | docs/guide.ru.md |
| Observability details | docs/guide.en.md / docs/guide.ru.md |
| API surface and smoke | docs/guide.en.md / docs/guide.ru.md |
compose/data.yaml-> Postgres + PgBouncer + Rediscompose/migrate.yaml-> one-shot migrations/bootstrapcompose/app.yaml-> app + nginx (build path)compose/release.yaml-> app + migrate + nginx (image-only path)compose/obs.yaml-> OTel/Prometheus/Grafana/Loki/Tempo(distributed)/Alertmanager/VictoriaMetricscompose/core.hostnet.yaml,compose/app.hostnet.yaml,compose/migrate.hostnet.yaml,compose/obs.hostnet.yaml-> Linux host-network fallbackcompose/obs.hostnet.yamluses a hostnet-specific Grafana provisioning set (Prometheus/Loki only). Tempo datasource and Tempo scrape are intentionally disabled in hostnet mode to avoid falsedown/EOFstates on this runtime path; full trace UI is available in standardcompose/obs.yaml.
Observability log flow:
- app logs -> OTLP gRPC -> OTel Collector -> Loki
- container logs -> Alloy
loki.source.docker(Docker API) -> Loki
Tempo distributed topology in compose/obs.yaml:
tempo-distributor(OTLP ingest)tempo-ingestertempo-queriertempo-query-frontend(Grafana datasource endpoint)tempo-compactor(backend-schedulertarget)tempo-metrics-generator(span-metrics + service-graphs)
Object storage for traces:
- Local default: MinIO (
minio+minio-initbucket bootstrap) - Production: set
TEMPO_S3_*to external S3-compatible storage
DB observability in compose/obs.yaml:
postgres-exporter(:9187) for Postgres saturation/locks/temp/deadlocks metricspgbouncer-exporter(:9127) for PgBouncer queue/maxwait/saturation metrics- Grafana dashboard:
Postgres Saturation - Grafana dashboard:
PgBouncer Saturation - Prometheus rules/alerts:
db:postgres_*,db:pgbouncer_*,PostgresConnectionsSaturation,PostgresDeadlocksDetected,PostgresTempBytesSpike,PgBouncerConnectionsSaturation,PgBouncerClientQueueWaiting,PgBouncerClientMaxwaitHigh
.github/workflows/ci.yml-> lint/format/type/tests.github/workflows/release-images.yml-> builds and publishesapp/migrate/nginxto GHCR onv*tags.github/workflows/release.yml-> creates GitHub Release object automatically onv*tags
Recommended release flow / Рекомендуемый релизный поток:
git checkout prod
git pull
git tag vX.Y.Z
git push origin prod
git push origin vX.Y.Z- Full English guide:
docs/guide.en.md - Полное руководство на русском:
docs/guide.ru.md
These guides include full runtime matrix, env catalog, observability details, RBAC migration procedure, API list, and quality commands.
curl -i http://127.0.0.1:8080/system
curl -i http://127.0.0.1:8080/openapi.json
curl -i http://127.0.0.1:8080/docsmake checkOptional live matrix / Опциональная живая матрица:
RUN_LIVE_E2E=1 E2E_BASE_URL=http://127.0.0.1:8080 uv run pytest tests/test_e2e_endpoint_matrix_live.py -q- Verify container-network reachability first:
docker run --rm --network <project>_default curlimages/curl:8.12.1 -s -o /dev/null -w '%{http_code}\n' http://nginx:8080/system- If this is
200, use host-network fallback on this machine:
docker compose -f compose/data.yaml -f compose/app.yaml -f compose/core.hostnet.yaml -f compose/app.hostnet.yaml up -d --build
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/systemNote: in host-network mode nginx listens on :8080 only (the upstream default vhost that binds :80 is removed).
If startup error contains opentelemetry-instrumentation-logging, install this runtime package in your app image/environment. Logging correlation is configured as a hard requirement for observability mode.
tests/test_e2e_endpoint_matrix_live.py has dense auth calls; nginx rate-limits can produce 429.
For deterministic live matrix use app upstream directly:
RUN_LIVE_E2E=1 E2E_BASE_URL=http://127.0.0.1:8000 uv run pytest tests/test_e2e_endpoint_matrix_live.py -q- Non-bootstrap migrations must use
postgresql_concurrently=Trueforop.create_index/op.drop_index. - Bootstrap-only exceptions must be documented in revision header with:
# migration-lint: allow-nonconcurrent-index - CI gate:
tests/test_migration_safety_gate.py. - Release checklist:
expand: nullable/new columns, concurrent indexes,NOT VALIDconstraints.- Backfill in controlled batches.
- Cutover application reads/writes.
contract: drop legacy structures only after stabilization.
appиrelease appпо умолчанию подключаются к БД через PgBouncer:postgresql+asyncpg://...@pgbouncer:5432/...migrateподключается напрямую кpostgres, чтобы DDL-миграции не зависели от режима pooler.- Для asyncpg через PgBouncer включен
prepared_statement_cache_size=0в дефолтном DSN. - SQLAlchemy pool в приложении остаётся включённым (bounded pool) и выступает как client-side лимитер; согласуй
DB_POOL_SIZE/DB_MAX_OVERFLOWс бюджетом PgBouncer, чтобы избежать oversubscription. - Бюджет соединений валидируется на старте приложения:
APP_INSTANCE_COUNT * (DB_POOL_SIZE + DB_MAX_OVERFLOW) <= PGBOUNCER_MAX_CLIENT_CONN,PGBOUNCER_DEFAULT_POOL_SIZE + PGBOUNCER_RESERVE_POOL_SIZE <= PGBOUNCER_MAX_DB_CONNECTIONS. Дополнительно при явной передачеPOSTGRES_MAX_CONNECTIONSпроверяется:PGBOUNCER_MAX_DB_CONNECTIONS <= POSTGRES_MAX_CONNECTIONS - POSTGRES_SUPERUSER_RESERVED_CONNECTIONS. - PgBouncer hardening defaults:
PGBOUNCER_AUTH_TYPE=scram-sha-256, host bind для6432только на127.0.0.1, pin image digest черезPGBOUNCER_IMAGE. - TLS для PgBouncer настраивается env-парами:
PGBOUNCER_CLIENT_TLS_SSLMODE,PGBOUNCER_SERVER_TLS_SSLMODE(+*_KEY_FILE,*_CERT_FILE,*_CA_FILEпри необходимости). - Redis guardrails задаются через:
REDIS_MAX_CONNECTIONS,REDIS_MAXMEMORY,REDIS_MAXMEMORY_POLICY.
For complete technical details docs/guide.en.md.
Все подробности - docs/guide.ru.md.