Skip to content
Public template

About

Attempt to develop a universal fastapi template, trying to stick to a clean architecture.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

FastAPI Clean/DDD Template

English | Русский

Production-oriented backend template: FastAPI + Clean/DDD + SQLAlchemy + Postgres + Redis + Alembic + JWT.

GitHub Actions CI GitHub Release make check required

Contents / Содержание

Quick Start / Быстрый старт

Release / Релиз: https://github.com/gorodtx/fastapi-template/releases/latest

Option A: Local build / Локальная сборка

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 --build

Option B: Release images (no server build) / Релизные образы (без сборки)

export 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 -d

Option C: Core + Observability / Core + Observability

docker compose -f compose/data.yaml -f compose/app.yaml -f compose/obs.yaml up -d --build

compose/obs.yaml (и compose/obs.hostnet.yaml) автоматически включает OBS_OTEL_ENABLED=true для app, чтобы метрики/трейсы начинали поступать сразу после поднятия observability-скоупа.

Technology Stack / Стек технологий

Runtime

FastAPI Pydantic Uvicorn Dishka

PostgreSQL PgBouncer SQLAlchemy asyncpg Alembic

Redis Nginx Docker Docker Compose

PyJWT Argon2 msgspec environs

Tooling & Quality

uv Ruff ty Pytest

GitHub Actions CI GitHub Release make check required

Navigation by Task / Навигация по задачам

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 Scopes / Скоупы compose

  • compose/data.yaml -> Postgres + PgBouncer + Redis
  • compose/migrate.yaml -> one-shot migrations/bootstrap
  • compose/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/VictoriaMetrics
  • compose/core.hostnet.yaml, compose/app.hostnet.yaml, compose/migrate.hostnet.yaml, compose/obs.hostnet.yaml -> Linux host-network fallback
  • compose/obs.hostnet.yaml uses a hostnet-specific Grafana provisioning set (Prometheus/Loki only). Tempo datasource and Tempo scrape are intentionally disabled in hostnet mode to avoid false down/EOF states on this runtime path; full trace UI is available in standard compose/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-ingester
  • tempo-querier
  • tempo-query-frontend (Grafana datasource endpoint)
  • tempo-compactor (backend-scheduler target)
  • tempo-metrics-generator (span-metrics + service-graphs)

Object storage for traces:

  • Local default: MinIO (minio + minio-init bucket 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 metrics
  • pgbouncer-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

Release and CI / Релиз и CI

  • .github/workflows/ci.yml -> lint/format/type/tests
  • .github/workflows/release-images.yml -> builds and publishes app/migrate/nginx to GHCR on v* tags
  • .github/workflows/release.yml -> creates GitHub Release object automatically on v* tags

Recommended release flow / Рекомендуемый релизный поток:

git checkout prod
git pull
git tag vX.Y.Z
git push origin prod
git push origin vX.Y.Z

Detailed Guides / Подробные руководства

These guides include full runtime matrix, env catalog, observability details, RBAC migration procedure, API list, and quality commands.

Smoke Checks / Быстрые проверки

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/docs

Quality Gates / Контроль качества

make check

Optional 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

Q&A

curl returns 000 from host / curl возвращает 000 с хоста

  1. 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
  1. 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/system

Note: in host-network mode nginx listens on :8080 only (the upstream default vhost that binds :80 is removed).

OBS_OTEL_ENABLED=true and app fails on startup

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.

Live e2e matrix returns 429 via nginx

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

Migration safety policy (expand/contract)

  • Non-bootstrap migrations must use postgresql_concurrently=True for op.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:
    1. expand: nullable/new columns, concurrent indexes, NOT VALID constraints.
    2. Backfill in controlled batches.
    3. Cutover application reads/writes.
    4. contract: drop legacy structures only after stabilization.

DB connection routing / Маршрут DB-подключений

  • 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.

thks :)

For complete technical details docs/guide.en.md. Все подробности - docs/guide.ru.md.

About

Attempt to develop a universal fastapi template, trying to stick to a clean architecture.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages