Production-oriented starter kit built with FastAPI + async SQLAlchemy, structured around a Clean Architecture / DDD-inspired layering model.
It is designed like a Django-style startproject baseline: a ready-to-extend foundation with real modules (auth/users/groups/permissions), explicit use-case orchestration, dependency injection, and production-minded defaults.
Production-oriented FastAPI starter kit implementing:
- Clean Architecture / DDD-inspired layering
- JWT authentication + RBAC authorization
- Async SQLAlchemy + PostgreSQL
- Dependency Injection
- Dockerized development workflow
- CI/CD pipelines and quality gates
Designed as a scalable backend foundation instead of a simple CRUD example.
Most CRUD backends become hard to evolve because business logic gets mixed with framework and database details.
This starter kit demonstrates how to keep boundaries explicit from day one:
- Business rules live in
domain - Application workflows live in
application/use_cases - Infrastructure adapters (DB/security) live in
infrastructure - HTTP/API concerns live in
presentation
Result: easier testing, clearer dependencies, and safer long-term refactoring.
Out of the box modules:
- Authentication
POST /v1/auth/login
- Users
GET /v1/users/GET /v1/users/{user_id}POST /v1/users/PATCH /v1/users/{user_id}DELETE /v1/users/{user_id}
- Groups
GET /v1/groups/POST /v1/groups/DELETE /v1/groups/{group_id}
- Permissions
GET /v1/permissions/
- RBAC operations
- assign/remove permission to/from group
- add/remove user to/from group
- under
/v1/rbac/groups/{group_id}/...
Route composition is defined in src/presentation/api/v1/routes.py.
Client
-> FastAPI app (src/main.py, src/core/app.py)
-> Presentation layer (endpoints/schemas/dependencies)
-> Application layer (use cases)
-> Domain contracts (ports/repositories/entities)
<- Infrastructure implementations (UoW, repositories, security services)
-> PostgreSQL (SQLAlchemy async)
-
Domain (
src/domain)- Core entities:
User,Group,Permission - Domain exceptions and enums
- Repository/port contracts
- RBAC permission definitions (
src/domain/rbac/permissions.py)
- Core entities:
-
Application (
src/application)- Use cases for auth/users/groups/permissions/RBAC
- DTOs (
src/application/dtos) - Coordinates domain rules with ports (without HTTP or ORM coupling)
-
Infrastructure (
src/infrastructure)- Async PostgreSQL connection
- SQLAlchemy models/repositories
- Unit of Work implementation
- JWT service + password hashing
- DI container wiring (
src/infrastructure/container.py)
-
Presentation (
src/presentation)- FastAPI endpoints
- Request/response schemas
- Authentication and authorization dependencies
- Middleware + exception translation to HTTP responses
-
Core (
src/core)- App factory
- Environment-driven configuration
- Structured logging bootstrap
- Endpoint receives
LoginRequest(src/presentation/api/v1/endpoints/authentication.py) LoginUseCaseis resolved from DI container- Use case loads user from repository via UoW
- Password is verified with
PasswordHasher JWTServicecreates access/refresh tokens- Response returns token pair
HTTPBearerextracts token (src/presentation/dependencies/auth_dep.py)GetCurrentUserUseCasevalidates/decode JWT and loads user- Permission dependency checks codename via
CheckUserPermissionUseCase - User list use case fetches data through repository
- Response schema maps domain objects to API contract
- Authentication: JWT access/refresh tokens (
src/infrastructure/security/jwt_service.py) - Password storage: bcrypt/passlib hashing (
src/infrastructure/security/password_hasher.py) - Authorization: endpoint-level RBAC dependency (
require_permission(...)) - Permission source: group-permission associations + superuser bypass in domain entity logic
- Error handling: centralized exception mapping with consistent error payloads
- Request observability: request-id middleware for trace-friendly logs
- Python 3.12
- FastAPI
- SQLAlchemy 2 (async)
- asyncpg
- Pydantic v2 + pydantic-settings
- dependency-injector
- PyJWT + passlib + bcrypt
- Alembic
- pytest / pytest-asyncio
- Ruff / pre-commit
- Docker + Docker Compose + Nginx
Dependency pins are in:
dev.requirements.txtprod.requirements.txt
The why behind the major choices (layering, DI, UoW, JWT strategy, RBAC registry, exception contract, logging) lives as ADRs:
docs/adr/— Architecture Decision Records (MADR format)
src/
core/ # app factory, config, logging
domain/ # entities, contracts, business rules
application/ # use cases + DTOs
infrastructure/ # DB/security adapters + DI container
presentation/ # API endpoints/schemas/dependencies/middlewares
main.py # ASGI entrypoint
alembic/ # migrations
tests/ # unit + integration tests
scripts/ # operational scripts (RBAC seed, superuser creation)
docker/ # Dockerfiles
docs/ # API + architecture notes
.github/workflows/ # CI/CD pipelines
- Python 3.12+
- Docker / Docker Compose (recommended)
- PostgreSQL (if running without Docker)
python -m venv .venv
# Linux/macOS
source .venv/bin/activate
# Windows (PowerShell)
# .venv\Scripts\Activate.ps1
pip install -r dev.requirements.txtThis project reads env from .env.dev when APP_ENV=dev.
Minimum keys:
APP_ENV=dev
DATABASE_NAME=auth_db
DATABASE_USER=postgres
DATABASE_PASSWORD=postgres
DATABASE_HOST=localhost
DATABASE_PORT=5432
SERVICE_NAME=auth-service
SERVICE_HOST=0.0.0.0
SERVICE_PORT=8000
OPENAPI_URL=/openapi.json
SECRET_KEY=change-me
ALGORITHM=HS256
ACCESS_TOKEN_LIFETIME_DAYS=1
REFRESH_TOKEN_LIFETIME_DAYS=7docker compose up --buildServices:
- PostgreSQL
- Backend (
uvicorn src.main:app ...) - Nginx reverse proxy
uvicorn src.main:app --reloadAPI docs (custom Swagger path):
http://localhost:8000/my-swagger
Health endpoint:
GET /health
- SQLAlchemy models are under
src/infrastructure/database/postgresql/models - Alembic config:
alembic.ini,alembic/env.py
Common commands:
alembic upgrade head
alembic revision --autogenerate -m "describe change"
alembic downgrade -1Seed permission catalog and admin group:
python scripts/seed_rbac.pyCreate a superuser interactively:
python scripts/create_superuser.pyRun tests:
pytest tests/Coverage:
pytest tests/ --cov=src --cov-report=term --cov-report=xmlLint:
ruff check src/Pre-commit hooks:
pre-commit install
pre-commit run --all-filesCI pipeline (.github/workflows/ci.yml) runs:
- lint
- tests + coverage artifact
- docker build
- security scans (Trivy, Bandit, Safety)
The repository includes a Docker-based CD workflow (.github/workflows/cd.yml) that:
- builds and validates an image
- transfers it to a remote server
- runs the container over SSH
This reflects an end-to-end deployment mindset, including image packaging and remote rollout automation.
This project showcases practical experience in:
- Layered backend architecture (Clean Architecture style)
- Dependency injection and explicit wiring of use cases
- Async API and persistence design
- Repository + Unit of Work patterns
- JWT authentication and RBAC authorization
- Domain-driven module boundaries
- Structured exception contracts
- Logging and request correlation
- Containerized local/dev workflow
- CI quality gates and security scanning
- Migration-driven schema evolution
The current implementation already provides a strong architecture baseline.
Natural next steps for production hardening:
- align migrations and runtime table-creation strategy
- expand integration coverage for groups/permissions/RBAC paths
- tighten CI/CD Dockerfile/env consistency
These are engineering refinements, not blockers for understanding the architecture.
Esmaeil Taheri
- LinkedIn: Esmaeil Taheri
- Email: esi.taheri@yahoo.com