Skip to content

tien-le/fastapi-production-template

Repository files navigation

FastAPI Social Media POC - Enterprise-Grade Architecture

A Proof of Concept (POC) for a social media application built with FastAPI, featuring Posts, Comments, Likes, User Authentication, Registration, and Email Confirmation. Built on an enterprise-grade architecture template with modular components, observability, resilience, and a scalable development workflow.


🎯 POC Features

This POC demonstrates a complete social media backend with the following core features:

User Management

  • βœ… User Registration - Secure user signup with email and password validation
  • βœ… User Authentication - JWT-based authentication system
  • βœ… Email Confirmation - Email verification workflow for new users
  • βœ… User Profile - User information management (email, full name, status)

Social Media Features

  • βœ… Posts - Create, read, update, and delete user posts (with optional image URLs)
  • βœ… Comments - Add comments to posts with full CRUD operations
  • βœ… Likes - Like/unlike posts with automatic like count tracking
  • βœ… Post Feed - View posts with associated comments and like counts

Technical Features

  • βœ… Clean Architecture - Separation of concerns (API β†’ Service β†’ Data layers)
  • βœ… Multi-Database Support - Supabase, PostgreSQL, SQLite providers
  • βœ… Type Safety - Full type hints with Pydantic v2 and SQLAlchemy 2.0
  • βœ… Modern Dependency Injection - Using Annotated pattern (Pydantic v2 & FastAPI best practices)
  • βœ… Security - JWT authentication, password hashing, email confirmation
  • βœ… Observability - Structured logging, metrics, health checks

πŸ—οΈ Architecture Overview

                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚        API Gateway         β”‚
                        β”‚    (FastAPI Application)   β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
                           HTTP Requests (REST API)
                                       β”‚
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚      API Router Layer       β”‚
                        β”‚                             β”‚
                        β”‚  /api/v1/auth              β”‚
                        β”‚    β”œβ”€ POST /token          β”‚
                        β”‚    └─ GET  /me              β”‚
                        β”‚                             β”‚
                        β”‚  /api/v1/users             β”‚
                        β”‚    β”œβ”€ POST /register       β”‚
                        β”‚    β”œβ”€ GET  /confirm/{token}β”‚
                        β”‚    β”œβ”€ GET  /me             β”‚
                        β”‚    β”œβ”€ GET  /               β”‚
                        β”‚    └─ GET  /{user_id}      β”‚
                        β”‚                             β”‚
                        β”‚  /api/v1/posts             β”‚
                        β”‚    β”œβ”€ GET  /               β”‚
                        β”‚    β”œβ”€ POST /               β”‚
                        β”‚    └─ GET  /{post_id}       β”‚
                        β”‚                             β”‚
                        β”‚  /api/v1/comments          β”‚
                        β”‚    β”œβ”€ GET  /               β”‚
                        β”‚    β”œβ”€ POST /               β”‚
                        β”‚    β”œβ”€ GET  /posts/{post_id}/commentsβ”‚
                        β”‚    β”œβ”€ PATCH /{comment_id}  β”‚
                        β”‚    └─ DELETE /{comment_id} β”‚
                        β”‚                             β”‚
                        β”‚  /api/v1/posts/{post_id}/likesβ”‚
                        β”‚    β”œβ”€ POST /               β”‚
                        β”‚    β”œβ”€ DELETE /             β”‚
                        β”‚    β”œβ”€ GET  /count           β”‚
                        β”‚    └─ GET  /me              β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚   Business Logic Layer      β”‚
                        β”‚   (Domain/Service Layer)   β”‚
                        β”‚                             β”‚
                        β”‚  β€’ User Registration       β”‚
                        β”‚  β€’ Authentication (JWT)     β”‚
                        β”‚  β€’ Email Confirmation       β”‚
                        β”‚  β€’ Post Management          β”‚
                        β”‚  β€’ Comment Operations       β”‚
                        β”‚  β€’ Like Operations          β”‚
                        β”‚  β€’ Authorization Checks     β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚               β”‚             β”‚               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”
β”‚ Data Layer      β”‚ β”‚ Backgroundβ”‚ β”‚ External  β”‚ β”‚ Security  β”‚
β”‚                 β”‚ β”‚ Tasks     β”‚ β”‚ Services  β”‚ β”‚ Layer     β”‚
β”‚ β€’ SQLAlchemy 2.0β”‚ β”‚           β”‚ β”‚           β”‚ β”‚           β”‚
β”‚ β€’ Async ORM     β”‚ β”‚ β€’ Email   β”‚ β”‚ β€’ Mailgun β”‚ β”‚ β€’ JWT     β”‚
β”‚ β€’ Repositories  β”‚ β”‚ β€’ Async   β”‚ β”‚ β€’ Supabaseβ”‚ β”‚ β€’ OAuth2  β”‚
β”‚                 β”‚ β”‚ β€’ Files   β”‚ β”‚ β€’ Auth    β”‚ β”‚ β€’ Passwordβ”‚
β”‚ β€’ Users Table   β”‚ β”‚           β”‚ β”‚           β”‚ β”‚   Hashingβ”‚
β”‚ β€’ Posts Table   β”‚ β”‚           β”‚ β”‚           β”‚ β”‚ β€’ RLS     β”‚
β”‚ β€’ Comments Tableβ”‚ β”‚           β”‚ β”‚           β”‚ β”‚           β”‚
β”‚ β€’ Likes Table   β”‚ β”‚           β”‚ β”‚           β”‚ β”‚           β”‚
β”‚ β€’ Alembic       β”‚ β”‚           β”‚ β”‚           β”‚ β”‚           β”‚
β”‚   Migrations    β”‚ β”‚           β”‚ β”‚           β”‚ β”‚           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚               β”‚             β”‚             β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚             β”‚
                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚    Database Providers          β”‚
                  β”‚                                 β”‚
                  β”‚  β€’ Supabase (PostgreSQL)       β”‚
                  β”‚  β€’ PostgreSQL                  β”‚
                  β”‚  β€’ SQLite (Testing)            β”‚
                  β”‚  β€’ MongoDB (Optional)          β”‚
                  β”‚  β€’ Qdrant (Vector DB, Optional) β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚               β”‚               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”
β”‚ Observability    β”‚ β”‚ Rate     β”‚ β”‚ Config    β”‚
β”‚                  β”‚ β”‚ Limiting β”‚ β”‚ Managementβ”‚
β”‚ β€’ Structured     β”‚ β”‚          β”‚ β”‚           β”‚
β”‚   Logging        β”‚ β”‚ β€’ Per    β”‚ β”‚ β€’ Env     β”‚
β”‚ β€’ Request        β”‚ β”‚   endpointβ”‚ β”‚   Configsβ”‚
β”‚   Correlation IDsβ”‚ β”‚ β€’ Global β”‚ β”‚ β€’ Feature β”‚
β”‚ β€’ Metrics        β”‚ β”‚   rules  β”‚ β”‚   Flags  β”‚
β”‚ β€’ Health Checks  β”‚ β”‚          β”‚ β”‚           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Folder Structure

fastapi-template/
β”œβ”€β”€ app/                          # Main application package
β”‚   β”œβ”€β”€ alembic/                  # Alembic migrations directory
β”‚   β”‚   β”œβ”€β”€ env.py               # Alembic environment configuration
β”‚   β”‚   β”œβ”€β”€ versions/            # Migration files
β”‚   β”‚   β”‚   └── 47984c963225_initial_migration.py
β”‚   β”‚   β”œβ”€β”€ script.py.mako       # Migration template
β”‚   β”‚   └── README               # Alembic documentation
β”‚   β”œβ”€β”€ alembic.ini               # Alembic configuration file
β”‚   β”œβ”€β”€ api/                      # API layer
β”‚   β”‚   └── v1/                  # API version 1
β”‚   β”‚       β”œβ”€β”€ __init__.py      # Router aggregation
β”‚   β”‚       └── routers/         # REST endpoints by domain
β”‚   β”‚           β”œβ”€β”€ auth.py      # Authentication endpoints (POST /token, GET /me)
β”‚   β”‚           β”œβ”€β”€ users.py     # User management endpoints (register, confirm, profile)
β”‚   β”‚           β”œβ”€β”€ posts.py     # Post CRUD endpoints
β”‚   β”‚           β”œβ”€β”€ comments.py  # Comment endpoints
β”‚   β”‚           └── likes.py     # Like/unlike endpoints
β”‚   β”œβ”€β”€ core/                     # Core functionality & configuration
β”‚   β”‚   β”œβ”€β”€ config.py            # Environment-aware configuration (Pydantic Settings)
β”‚   β”‚   β”œβ”€β”€ logging.py           # Structured logging setup (structlog)
β”‚   β”‚   β”œβ”€β”€ auth.py              # JWT authentication, password hashing
β”‚   β”‚   β”œβ”€β”€ deps.py              # FastAPI dependency injection
β”‚   β”‚   β”œβ”€β”€ rate_limit.py        # Rate limiting middleware
β”‚   β”‚   └── tasks.py             # Background tasks (email sending)
β”‚   β”œβ”€β”€ db/                       # Database layer
β”‚   β”‚   β”œβ”€β”€ postgresql.py        # PostgreSQL provider (Supabase/PostgreSQL)
β”‚   β”‚   β”œβ”€β”€ sqlite.py            # SQLite provider (testing)
β”‚   β”‚   β”œβ”€β”€ mongodb.py           # MongoDB provider (optional)
β”‚   β”‚   β”œβ”€β”€ qdrant.py            # Qdrant vector DB provider (optional)
β”‚   β”‚   β”œβ”€β”€ base.py              # Base database classes
β”‚   β”‚   β”œβ”€β”€ session.py           # Database session management
β”‚   β”‚   └── repositories/        # Repository pattern implementation
β”‚   β”‚       β”œβ”€β”€ base_repository.py    # Base repository with common CRUD
β”‚   β”‚       β”œβ”€β”€ user_repository.py    # User data access
β”‚   β”‚       β”œβ”€β”€ post_repository.py    # Post data access
β”‚   β”‚       β”œβ”€β”€ comment_repository.py # Comment data access
β”‚   β”‚       └── like_repository.py    # Like data access
β”‚   β”œβ”€β”€ models/                   # SQLAlchemy 2.0 ORM models
β”‚   β”‚   β”œβ”€β”€ __init__.py          # Model exports (Base, User, Post, etc.)
β”‚   β”‚   β”œβ”€β”€ user.py              # User model (auth, profile, relationships)
β”‚   β”‚   └── post.py              # Post, Comment, Like models
β”‚   β”œβ”€β”€ schemas/                  # Pydantic v2 schemas (request/response)
β”‚   β”‚   β”œβ”€β”€ user.py              # User schemas (create, update, response)
β”‚   β”‚   β”œβ”€β”€ post.py              # Post, Comment, Like schemas
β”‚   β”‚   β”œβ”€β”€ auth.py              # Authentication schemas (token, login)
β”‚   β”‚   └── common.py            # Common schemas (pagination, errors)
β”‚   β”œβ”€β”€ services/                 # Business logic layer
β”‚   β”‚   β”œβ”€β”€ user_service.py      # User registration, confirmation, profile
β”‚   β”‚   β”œβ”€β”€ post_service.py      # Post business logic
β”‚   β”‚   β”œβ”€β”€ comment_service.py   # Comment business logic
β”‚   β”‚   └── like_service.py      # Like business logic
β”‚   β”œβ”€β”€ tools/                    # Utility scripts and tools
β”‚   β”‚   β”œβ”€β”€ backend_pre_start.py # Wait for DB and validate connection
β”‚   β”‚   β”œβ”€β”€ tests_pre_start.py   # Validate test environment setup
β”‚   β”‚   β”œβ”€β”€ initial_data.py      # Create initial database data (superuser)
β”‚   β”‚   └── clear_alembic_version.py  # Clear Alembic version table
β”‚   β”œβ”€β”€ utils/                    # Helper utilities
β”‚   β”‚   └── sanitization.py      # String sanitization utilities
β”‚   β”œβ”€β”€ main.py                  # FastAPI application entry point
β”‚   └── __init__.py
β”œβ”€β”€ tests/                        # Test suite (TDD structure)
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ conftest.py              # Shared pytest fixtures (db_session, client, etc.)
β”‚   β”œβ”€β”€ README.md                # Test documentation and guidelines
β”‚   β”œβ”€β”€ unit/                     # Unit tests (fast, isolated, no DB)
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ conftest.py          # Unit test fixtures
β”‚   β”‚   β”œβ”€β”€ test_user_service.py # Service layer unit tests
β”‚   β”‚   β”œβ”€β”€ test_post_service.py
β”‚   β”‚   β”œβ”€β”€ test_comment_service.py
β”‚   β”‚   β”œβ”€β”€ test_like_service.py
β”‚   β”‚   β”œβ”€β”€ test_user_repository.py # Repository unit tests
β”‚   β”‚   └── test_security.py     # Security unit tests
β”‚   β”œβ”€β”€ integration/              # Integration tests (with DB)
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ conftest.py          # Integration test fixtures
β”‚   β”‚   β”œβ”€β”€ test_dependencies.py # Dependency injection tests
β”‚   β”‚   β”œβ”€β”€ test_routes_posts.py # Post route integration tests
β”‚   β”‚   └── test_routes_users.py # User route integration tests
β”‚   β”œβ”€β”€ e2e/                      # End-to-end tests (full API flow)
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ conftest.py          # E2E test fixtures
β”‚   β”‚   β”œβ”€β”€ test_users_api.py   # User API E2E tests
β”‚   β”‚   └── test_posts_api.py   # Post API E2E tests
β”‚   β”œβ”€β”€ acceptance/               # Acceptance tests (user journeys)
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ conftest.py
β”‚   β”‚   └── test_user_journey.py # Complete user journey tests
β”‚   β”œβ”€β”€ security/                 # Security-focused tests
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ test_auth.py         # Authentication tests
β”‚   β”‚   β”œβ”€β”€ test_authorization.py # Authorization tests
β”‚   β”‚   └── test_input_validation.py # Input validation tests
β”‚   β”œβ”€β”€ schema/                   # OpenAPI schema validation tests
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   └── test_openapi.py      # Schema validation tests
β”‚   └── migrations/               # Migration tests
β”‚       β”œβ”€β”€ __init__.py
β”‚       └── test_alembic_migrations.py # Migration validation tests
β”œβ”€β”€ configs/                      # Environment-specific configuration files
β”‚   β”œβ”€β”€ dev.env.example          # Development environment template
β”‚   β”œβ”€β”€ staging.env.example      # Staging environment template
β”‚   β”œβ”€β”€ prod.env.example         # Production environment template
β”‚   └── test.env.example         # Test environment template
β”œβ”€β”€ scripts/                      # Development and utility scripts
β”‚   β”œβ”€β”€ pre_start.sh             # Pre-start script (DB wait, migrations, initial data)
β”‚   β”œβ”€β”€ tests_start.sh           # Test environment validation and test runner
β”‚   β”œβ”€β”€ lint.sh                  # Run ruff linter with auto-fix
β”‚   β”œβ”€β”€ format.sh                # Format code with ruff
β”‚   β”œβ”€β”€ test.sh                  # Run pytest tests
β”‚   β”œβ”€β”€ fix.sh                   # Fix linting and format code (lint + format)
β”‚   └── check.sh                 # Run all checks without modifying files
β”œβ”€β”€ docs/                         # Comprehensive documentation
β”‚   β”œβ”€β”€ 01-architecture-overview.md
β”‚   β”œβ”€β”€ 02-database-architecture.md
β”‚   β”œβ”€β”€ 00-notes.md              # Development notes
β”‚   └── README.md                # Documentation index
β”œβ”€β”€ .dockerignore                 # Docker ignore patterns
β”œβ”€β”€ .gitignore                    # Git ignore patterns
β”œβ”€β”€ alembic.ini                   # Root Alembic config (legacy, use app/alembic.ini)
β”œβ”€β”€ docker-compose.yml           # Docker Compose configuration
β”œβ”€β”€ docker-compose.sh            # Docker Compose helper script
β”œβ”€β”€ Dockerfile                    # Docker image definition
β”œβ”€β”€ Makefile                     # Makefile with common development tasks
β”œβ”€β”€ main.py                      # Alternative entry point (legacy)
β”œβ”€β”€ pyproject.toml               # Python project configuration
β”œβ”€β”€ pytest.ini                   # Pytest configuration
β”œβ”€β”€ requirements.txt             # Production dependencies
β”œβ”€β”€ requirements-dev.txt         # Development dependencies
β”œβ”€β”€ uv.lock                      # UV lock file (dependency versions)
└── README.md                    # This file

πŸ“ Key Directory Explanations

  • app/alembic/: Database migrations are stored here. Use make migrate or python -m alembic -c app/alembic.ini to manage migrations.
  • app/api/v1/routers/: REST API endpoints organized by domain. Each router handles a specific resource.
  • app/core/: Core functionality including configuration, authentication, logging, and dependencies.
  • app/db/repositories/: Data access layer using the Repository pattern. Abstracts database operations.
  • app/services/: Business logic layer. Contains domain logic and orchestrates between repositories and API.
  • app/models/: SQLAlchemy ORM models. Define database schema and relationships.
  • app/schemas/: Pydantic models for request/response validation and serialization.
  • app/tools/: Utility scripts for database initialization, testing setup, and maintenance.
  • tests/: Comprehensive test suite organized by test type (unit, integration, e2e, acceptance).
  • configs/: Environment-specific configuration templates. Copy .example files and customize.
  • scripts/: Shell scripts for common development tasks. Can be used directly or via Makefile.

⚑ Key Features

Social Media Domain Models

  • User Model - Authentication, profile, email confirmation status
  • Post Model - User-generated content with optional image URLs
  • Comment Model - Comments on posts with user attribution
  • Like Model - User likes on posts with automatic count tracking
  • Full relationships: User β†’ Posts, User β†’ Comments, User β†’ Likes, Post β†’ Comments, Post β†’ Likes

Clean Architecture

  • Clear layer separation (API β†’ Service β†’ Data)
  • Domain-driven design principles
  • Repository pattern for data access
  • Dependency injection throughout

Databases

  • Multi-provider support: PostgreSQL, SQLite, MongoDB, Qdrant
  • Database Provider Selection via DB_PROVIDER configuration (supabase, postgresql, sqlite)
  • Automatic database URL selection based on provider (Supabase uses SUPABASE_DB_URL, PostgreSQL uses DATABASE_URL)
  • SQLAlchemy 2.0 with async support and type safety
  • ORM models (models/) and Pydantic v2 schemas (schemas/)
  • Migration management with Alembic

Security

  • JWT authentication & OAuth2 flows
  • User registration with password validation (min 8 chars, digit, uppercase)
  • Email confirmation workflow
  • Password hashing with bcrypt
  • Supabase Auth integration
  • Row Level Security (RLS) policies
  • Rate limiting (per-endpoint and global)
  • CORS configuration and input validation

Async & Background Tasks

  • FastAPI BackgroundTasks for non-blocking operations
  • Email confirmation sending via Mailgun API
  • Background email tasks in app/core/tasks.py
  • Graceful error handling in dev/test modes
  • HTML and plain text email templates

Observability

  • Structured logging with structlog
  • Request correlation IDs
  • Prometheus metrics
  • Health check endpoints

Environment Management

  • Multi-environment configs (dev, staging, prod, test)
  • Auto-detection via get_environment() in config.py
  • Pydantic Settings for type-safe configuration
  • Feature flags support

Example configs/dev.env

# Application Environment
APP_ENV=dev

# Database Provider (options: supabase, postgresql, sqlite)
DB_PROVIDER=supabase

# Security - Generate with: python -c "import secrets; print(secrets.token_urlsafe(32))"
SECRET_KEY=your-secret-key-here-min-32-chars
JWT_SECRET_KEY=your-jwt-secret-key-here-min-32-chars
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=1440
JWT_CONFIRMATION_TOKEN_EXPIRE_MINUTES=20

# Database Configuration
# For Supabase (when DB_PROVIDER=supabase):
SUPABASE_URL=https://your-project-id.supabase.co
SUPABASE_KEY=your-supabase-anon-key
SUPABASE_DB_URL=postgresql://postgres:password@db.your-project-id.supabase.co:5432/postgres
SUPABASE_DB_PASSWORD=your-db-password

# For PostgreSQL (when DB_PROVIDER=postgresql):
# DATABASE_URL=postgresql+asyncpg://dev_user:dev_pass@localhost:5432/dev_db

# For SQLite (when DB_PROVIDER=sqlite):
# SQLITE_URL=sqlite+aiosqlite:///./test.db

# Email Service (Mailgun)
MAILGUN_API_KEY=your-mailgun-api-key
MAILGUN_DOMAIN=your-domain.mailgun.org

# CORS
CORS_ORIGINS=http://localhost:3000,http://localhost:8080

# Logging
LOG_LEVEL=INFO
LOG_FORMAT=json

# Optional: Sentry for error tracking
# SENTRY_DSN=your-sentry-dsn

Database Provider Configuration

The application supports multiple database providers that can be configured via the DB_PROVIDER environment variable. This allows you to easily switch between Supabase, PostgreSQL, and SQLite without code changes.

Available Providers

  1. supabase - Supabase managed PostgreSQL database
  2. postgresql - Standard PostgreSQL database
  3. sqlite - SQLite database (useful for testing and development)

Configuration Examples

Using Supabase

DB_PROVIDER=supabase
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-supabase-anon-key
SUPABASE_DB_URL=postgresql://postgres:password@db.your-project.supabase.co:5432/postgres
SUPABASE_DB_PASSWORD=your-db-password

Note: When DB_PROVIDER=supabase, the application automatically uses SUPABASE_DB_URL for database connections. DATABASE_URL is optional in this case.

Using PostgreSQL

DB_PROVIDER=postgresql
DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/dbname
DATABASE_POOL_SIZE=20
DATABASE_MAX_OVERFLOW=10

Using SQLite

DB_PROVIDER=sqlite
SQLITE_URL=sqlite+aiosqlite:///./test.db

Note: SQLite is typically used for testing. The application will automatically use SQLite when DB_PROVIDER=sqlite.

How It Works

  1. Configuration Loading: The DB_PROVIDER setting is loaded from your environment config file (configs/{environment}.env)

  2. Database Selection: Based on DB_PROVIDER, the application:

    • Initializes the appropriate database provider during startup
    • Routes database sessions through the selected provider
    • Uses the correct database URL (SUPABASE_DB_URL for Supabase, DATABASE_URL for PostgreSQL)
  3. Migrations: Alembic migrations automatically detect and use the correct database URL based on your DB_PROVIDER setting. The Alembic configuration is located at app/alembic.ini and migrations are in app/alembic/ directory. Always use -c app/alembic.ini when running Alembic commands directly, or use the Makefile commands (e.g., make migrate) which handle this automatically.

Provider Selection Logic

The application selects the database provider in the following order:

  • If DB_PROVIDER=supabase: Uses SUPABASE_DB_URL (falls back to DATABASE_URL if SUPABASE_DB_URL is not set)
  • If DB_PROVIDER=postgresql: Uses DATABASE_URL
  • If DB_PROVIDER=sqlite: Uses SQLITE_URL

Benefits

  • Flexibility: Switch between database providers without code changes
  • Environment-Specific: Different providers for dev, staging, and production
  • Testing: Easy to use SQLite for tests while using PostgreSQL/Supabase in other environments
  • Supabase Integration: Seamless integration with Supabase's managed PostgreSQL service

config.py with get_environment()

import os
from enum import Enum
from pydantic_settings import BaseSettings

class Environment(str, Enum):
    DEV = "dev"
    STAGING = "staging"
    PRODUCTION = "production"
    TEST = "test"

def get_environment() -> Environment:
    match os.getenv("APP_ENV", "dev").lower():
        case "production" | "prod":
            return Environment.PRODUCTION
        case "staging" | "stage":
            return Environment.STAGING
        case "test":
            return Environment.TEST
        case _:
            return Environment.DEV

class Settings(BaseSettings):
    project_name: str = "FastAPI Template"
    database_url: str
    mailgun_api_key: str
    secret_key: str
    environment: Environment = get_environment()

    class Config:
        env_file = f"configs/{environment.value}.env"

settings = Settings()

main.py Example

from contextlib import asynccontextmanager
from typing import AsyncGenerator

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from asgi_correlation_id import CorrelationIdMiddleware

from app.api.v1 import api_v1_router
from app.core.config import settings
from app.core.logging import setup_logging, get_logger
from app.db.postgresql import _postgresql_provider
from app.db.sqlite import _sqlite_provider

@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    """Lifespan context manager for database connections."""
    # Startup
    setup_logging()
    logger = get_logger(__name__)

    if settings.DB_PROVIDER.value == "sqlite":
        await _sqlite_provider.connect()
    elif settings.DB_PROVIDER.value in ("supabase", "postgresql"):
        await _postgresql_provider.connect()

    logger.info("Application startup complete")
    yield

    # Shutdown
    if settings.DB_PROVIDER.value == "sqlite":
        await _sqlite_provider.disconnect()
    elif settings.DB_PROVIDER.value in ("supabase", "postgresql"):
        await _postgresql_provider.disconnect()

    logger.info("Application shutdown complete")

app = FastAPI(
    title=settings.PROJECT_NAME,
    version=settings.VERSION,
    lifespan=lifespan,
    docs_url="/docs" if not settings.is_production else None,
)

# Add middleware
app.add_middleware(CorrelationIdMiddleware)
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.CORS_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include API routers
app.include_router(api_v1_router)

@app.get("/health")
async def health_check():
    return {
        "status": "ok",
        "environment": settings.ENVIRONMENT.value,
        "version": settings.VERSION,
    }

Note: Router prefixes are defined in each router file (e.g., router = APIRouter(prefix="/auth")), and routers are aggregated in app/api/v1/__init__.py. The application uses a lifespan context manager for proper database connection management.

API Endpoints Overview

Authentication (/api/v1/auth)

  • POST /api/v1/auth/token - User login (OAuth2 password flow)
    • Form data: username (email), password
    • Returns: JWT access token (access_token, token_type: "bearer")
    • Requires: Email confirmation before login
  • GET /api/v1/auth/me - Get current authenticated user info with token details
    • Returns: User information with token expiration and issued_at timestamps
    • Requires: JWT authentication token

User Management (/api/v1/users)

  • POST /api/v1/users/register - User registration
    • Body: User information (email, password, full_name, etc.)
    • Returns: User registration response with confirmation URL
    • Background: Sends confirmation email asynchronously
  • GET /api/v1/users/confirm/{token} - Email confirmation
    • Path parameter: token (JWT confirmation token)
    • Returns: Confirmation status
    • Updates: Sets user confirmed status to True
  • GET /api/v1/users/me - Get current user profile
    • Returns: Current authenticated user profile
    • Requires: JWT authentication token
  • PATCH /api/v1/users/me - Update current user profile
    • Requires: JWT authentication token
    • Body: User update data (email, full_name, etc.)
    • Returns: Updated user profile
  • GET /api/v1/users - List all users (paginated)
    • Query parameters: skip (default: 0), limit (default: 100, max: 1000)
    • Returns: List of all users
    • Requires: JWT authentication token
  • GET /api/v1/users/{user_id} - Get user by ID
    • Returns: User information
  • PATCH /api/v1/users/{user_id} - Update user (partial update)
    • Requires: JWT authentication token
    • Authorization: Users can only update their own profile
    • Returns: Updated user information
  • DELETE /api/v1/users/{user_id} - Delete user
    • Requires: JWT authentication token
    • Authorization: Users can only delete their own account

Posts (/api/v1/posts)

  • GET /api/v1/posts - List all posts with sorting options
    • Query parameters:
      • sorting (optional): Sort order - new (default), old, or most_likes
      • skip (optional): Number of records to skip (default: 0)
      • limit (optional): Maximum number of records (default: 100, max: 1000)
    • Returns: List of posts with like counts
  • GET /api/v1/posts/{post_id} - Get post details with comments and likes count
    • Returns: Post with associated comments and like count
  • POST /api/v1/posts - Create a new post (authenticated)
    • Requires: JWT authentication token
    • Body: Post content (body, optional image_url)
    • Returns: Created post
  • PATCH /api/v1/posts/{post_id} - Update post (authenticated)
    • Requires: JWT authentication token
    • Authorization: Users can only update their own posts
    • Body: Updated post content
    • Returns: Updated post
  • DELETE /api/v1/posts/{post_id} - Delete post (authenticated)
    • Requires: JWT authentication token
    • Authorization: Users can only delete their own posts

Comments (/api/v1/comments)

  • GET /api/v1/comments - List all comments (paginated)
    • Query parameters: skip (default: 0), limit (default: 100, max: 1000)
    • Returns: List of all comments
  • GET /api/v1/comments/posts/{post_id}/comments - Get comments for a specific post
    • Query parameters: skip (default: 0), limit (default: 100, max: 1000)
    • Returns: List of comments associated with the post
  • POST /api/v1/comments - Create a comment on a post (authenticated)
    • Requires: JWT authentication token
    • Body: Comment content (post_id, body)
    • Returns: Created comment
  • PATCH /api/v1/comments/{comment_id} - Update comment (authenticated)
    • Requires: JWT authentication token
    • Authorization: Users can only update their own comments
    • Body: Updated comment content
    • Returns: Updated comment
  • DELETE /api/v1/comments/{comment_id} - Delete comment (authenticated)
    • Requires: JWT authentication token
    • Authorization: Users can only delete their own comments

Likes (/api/v1/posts/{post_id}/likes)

  • POST /api/v1/posts/{post_id}/likes - Like a post (authenticated)
    • Requires: JWT authentication token
    • Path parameter: post_id (the ID of the post to like)
    • Returns: Like record created
    • Note: If already liked, returns existing like
  • DELETE /api/v1/posts/{post_id}/likes - Unlike a post (authenticated)
    • Requires: JWT authentication token
    • Path parameter: post_id (the ID of the post to unlike)
    • Returns: 204 No Content on success
  • GET /api/v1/posts/{post_id}/likes/count - Get like count for a post
    • Path parameter: post_id (the ID of the post)
    • Returns: Like count for the post
  • GET /api/v1/posts/{post_id}/likes/me - Check if current user liked a post (authenticated)
    • Requires: JWT authentication token
    • Path parameter: post_id (the ID of the post)
    • Returns: Like status for the current user

Docker & Deployment

Dockerfile

The Dockerfile is configured for production deployment with proper layer caching and security best practices. See Dockerfile in the project root for the complete implementation.

docker-compose.yml

  • Includes PostgreSQL, Qdrant, MongoDB, Redis for local dev environment

Deployment

  • Render.com for app hosting
  • Supabase for managed PostgreSQL + pgvector
  • CI/CD via GitHub Actions
  • Docker containerization for consistent environments

1. Business/Domain Logic (Services)

Location: app/services/ Purpose: Encapsulate core application logic that implements your business rules and domain operations. This layer sits between the API endpoints and the database, acting as a bridge.

Responsibilities:

  1. Enforce business rules

    • Example: when a user registers, check for duplicates, hash the password, and send a confirmation email.
  2. Coordinate multiple operations

    • Example: creating an order might involve updating inventory, logging the action, and notifying a warehouse service.
  3. Abstract away infrastructure details

    • The API router doesn’t need to know how the database works; the service interacts with the Data Layer.
  4. Reusability

    • Multiple endpoints or tasks can reuse the same business logic.
    • Example: a background task and an API endpoint can both call user_service.create_user().
  5. Unit-testable

    • Services can be tested without involving HTTP requests or the database, by mocking the Data Layer.

Example:

# app/services/user_service.py
from app.db.postgresql import get_user_by_email, create_user_in_db
from app.utils.email import send_confirmation_email

class UserService:
    def register_user(self, email: str, password: str, full_name: str | None = None):
        """Register a new user and send confirmation email."""
        if get_user_by_email(email):
            raise ValueError("User already exists")
        user = create_user_in_db(email, password, full_name)
        confirmation_token = generate_confirmation_token(user.id)
        send_confirmation_email(email, token=confirmation_token)
        return user

# app/services/post_service.py
class PostService:
    def create_post(self, user_id: int, body: str, image_url: str | None = None):
        """Create a new post."""
        return create_post_in_db(user_id, body, image_url)

    def get_post_with_details(self, post_id: int):
        """Get post with comments and like count."""
        post = get_post_by_id(post_id)
        comments = get_comments_by_post_id(post_id)
        like_count = get_like_count_by_post_id(post_id)
        return {
            "post": post,
            "comments": comments,
            "likes": like_count
        }

2. Data Layer

Location: app/db/ (and partially app/models/) Purpose: Handle persistence and retrieval of data, abstracting the details of storage systems. It manages all database interactions for the application.

Responsibilities:

  1. Database abstraction

    • Encapsulate the details of SQL, NoSQL, or vector databases.
    • Example: whether you use PostgreSQL, SQLite, MongoDB, or Qdrant, the Service layer doesn’t need to know.
  2. ORM models and sessions

    • Define database schema via ORM (SQLAlchemy, MongoEngine, etc.) in models/.
    • Manage sessions and transactions for consistent database access.
  3. Migrations

    • Track schema changes using Alembic for SQL databases.
  4. Support multiple DB providers

    • Your structure supports swapping or combining multiple databases without changing business logic.

Example:

# app/db/postgresql.py
from sqlalchemy.orm import Session
from app.models.user import User
from app.models.post import Post, Comment, Like

def get_user_by_email(session: Session, email: str):
    return session.query(User).filter(User.email == email).first()

def create_user_in_db(session: Session, email: str, password: str, full_name: str | None = None):
    user = User(email=email, hashed_password=password, full_name=full_name)
    session.add(user)
    session.commit()
    return user

def create_post_in_db(session: Session, user_id: int, body: str, image_url: str | None = None):
    post = Post(user_id=user_id, body=body, image_url=image_url)
    session.add(post)
    session.commit()
    return post

def create_comment_in_db(session: Session, post_id: int, user_id: int, body: str):
    comment = Comment(post_id=post_id, user_id=user_id, body=body)
    session.add(comment)
    session.commit()
    return comment

def create_like_in_db(session: Session, post_id: int, user_id: int):
    like = Like(post_id=post_id, user_id=user_id)
    session.add(like)
    session.commit()
    return like

Key Difference Between the Two Layers

Layer Purpose Focus Examples
Business/Domain Logic (Services) Implement business rules and domain operations What the app does Register user, create post, add comment, like post, send confirmation email
Data Layer Handle persistence and data access How data is stored/retrieved SQLAlchemy queries, MongoDB operations, migrations

Rule of thumb:

The Service layer defines what happens in your application. The Data layer defines how data is stored and retrieved.


πŸ“š Documentation

Comprehensive documentation is available in the docs/ folder:

⭐ Start Here

Detailed Documentation

  1. Architecture Overview - System architecture, layers, and design principles
  2. Database Architecture - Multi-database strategy and SQLAlchemy 2.0 patterns
  3. API Design - REST conventions, versioning, and Pydantic validation
  4. Service Layer Patterns - Business logic and DDD concepts
  5. Security Design - Authentication, authorization, and rate limiting
  6. Configuration Management - Environment handling and settings
  7. Observability - Logging, metrics, and monitoring
  8. Async Tasks - Background processing patterns
  9. Integration Patterns - External service integrations
  10. Deployment - Docker, CI/CD, and production deployment
  11. Development Workflow - Setup, testing, and tooling
  12. Design Patterns & Best Practices - Clean code and SOLID principles

πŸ“– Documentation Index β†’


πŸš€ Quick Start

Prerequisites

  • Python 3.12+
  • Docker & Docker Compose (for local development)
  • Git
  • Virtual environment (venv or similar)

Setup

# 1. Clone repository
git clone https://github.com/your-org/fastapi-template.git
cd fastapi-template

# 2. Create virtual environment
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# 3. Install dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt  # For development tools

# 4. Copy environment config
cp configs/dev.env.example configs/dev.env
# Edit configs/dev.env and set your SECRET_KEY, database URLs, etc.

# 5. Start services with Docker Compose
docker-compose up -d

# 6. Initialize database, format code, lint, and test (RECOMMENDED)
make all ENV=dev

# OR manually:
# 6a. Wait for database and run migrations
# python app/tools/backend_pre_start.py
# python -m alembic -c app/alembic.ini upgrade head
# python app/tools/initial_data.py

# 7. Start development server
make dev
# OR: uvicorn app.main:app --reload

# 8. Open API docs
# http://localhost:8000/api/docs

For detailed setup instructions, see Development Workflow.

🎯 Quick Setup with make all

The fastest way to get started is using the make all command, which automates the entire setup process:

# 1. Install dependencies
make install

# 2. Copy and configure environment
cp configs/dev.env.example configs/dev.env
# Edit configs/dev.env with your settings

# 3. Start Docker services (database, etc.)
docker-compose up -d

# 4. Run everything in one command!
make all ENV=dev

What make all does:

  1. βœ… Waits for database to be ready (backend_pre_start.py)
  2. βœ… Runs database migrations (alembic upgrade head)
  3. βœ… Creates initial data (superuser) (initial_data.py)
  4. βœ… Formats code (ruff format)
  5. βœ… Lints code (ruff check)
  6. βœ… Runs all tests (pytest)

This ensures your environment is fully set up and validated before you start development!

πŸ“š Developer Guide

Understanding the Project Structure

This project follows Clean Architecture principles with clear separation of concerns:

  • API Layer (app/api/): HTTP endpoints and request/response handling
  • Service Layer (app/services/): Business logic and domain rules
  • Repository Layer (app/db/repositories/): Data access abstraction
  • Models (app/models/): Database schema (SQLAlchemy ORM)
  • Schemas (app/schemas/): Request/response validation (Pydantic)

Common Development Tasks

Starting Development:

make dev                    # Start development server with auto-reload

Before Committing Code:

make format                 # Format code
make lint                   # Check for linting issues
make test                   # Run all tests
make check                  # Run lint + type-check

Database Operations:

make init-db ENV=dev        # Initialize database (first time setup)
make migrate ENV=dev         # Run pending migrations
make migrate-revision MESSAGE='description' ENV=dev  # Create new migration
make migrate-current ENV=dev # Check current migration version

Testing:

make test                   # Run all tests
make test-unit              # Fast unit tests only
make test-integration       # Integration tests with DB
make test-e2e               # End-to-end API tests
make test-coverage          # Generate coverage report

Troubleshooting:

# Check database connection
python app/tools/backend_pre_start.py

# Clear Alembic version table (if migrations are stuck)
python app/tools/clear_alembic_version.py

# Validate test environment
python app/tools/tests_pre_start.py

Environment Configuration

The project uses environment-specific configuration files in configs/:

  • Development: configs/dev.env (local development)
  • Staging: configs/staging.env (staging environment)
  • Production: configs/prod.env (production environment)
  • Testing: configs/test.env (automated tests)

Important Settings:

  • APP_ENV: Environment name (dev, staging, prod, test)
  • DB_PROVIDER: Database provider (supabase, postgresql, sqlite)
  • DATABASE_URL or SUPABASE_DB_URL: Database connection string
  • SECRET_KEY: Application secret key (min 32 characters)
  • JWT_SECRET_KEY: JWT token signing key (min 32 characters)

Database Provider Selection

The project supports multiple database providers configured via DB_PROVIDER:

  • Supabase: Managed PostgreSQL with auth (DB_PROVIDER=supabase)
  • PostgreSQL: Standard PostgreSQL (DB_PROVIDER=postgresql)
  • SQLite: File-based database for testing (DB_PROVIDER=sqlite)

The application automatically selects the correct provider based on your configuration.

Alembic Migrations

Migrations are located in app/alembic/ directory. Always use the Makefile commands or specify -c app/alembic.ini:

# βœ… Correct way (via Makefile)
make migrate ENV=dev

# βœ… Correct way (direct command)
python -m alembic -c app/alembic.ini upgrade head

# ❌ Wrong way (will fail)
alembic upgrade head  # Missing config path!

Code Quality Standards

This project enforces high code quality standards:

  • Type Hints: All functions must have type annotations
  • Linting: Ruff enforces style and detects errors
  • Formatting: Ruff formatter ensures consistent style
  • Type Checking: Mypy validates type correctness
  • Testing: Comprehensive test coverage required

Run make check before committing to ensure code quality.


πŸ§ͺ Testing

This project follows Test-Driven Development (TDD) principles with a comprehensive test suite organized into three categories: unit tests, end-to-end tests, and acceptance tests.

Test Structure

Current Implementation (TDD-focused):

tests/
β”œβ”€β”€ __init__.py
β”œβ”€β”€ conftest.py              # Shared pytest fixtures and configuration
β”œβ”€β”€ README.md                # Test documentation
β”œβ”€β”€ unit/                    # Unit tests (fast, isolated)
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ conftest.py          # Unit test fixtures
β”‚   β”œβ”€β”€ test_user_service.py
β”‚   β”œβ”€β”€ test_post_service.py
β”‚   β”œβ”€β”€ test_comment_service.py
β”‚   β”œβ”€β”€ test_like_service.py
β”‚   β”œβ”€β”€ test_user_repository.py
β”‚   └── test_security.py
β”œβ”€β”€ integration/             # Integration tests
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ conftest.py          # Integration test fixtures
β”‚   β”œβ”€β”€ test_dependencies.py
β”‚   β”œβ”€β”€ test_routes_posts.py
β”‚   └── test_routes_users.py
β”œβ”€β”€ e2e/                     # End-to-end tests (API integration)
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ conftest.py          # E2E test fixtures
β”‚   β”œβ”€β”€ test_users_api.py
β”‚   └── test_posts_api.py
β”œβ”€β”€ acceptance/              # Acceptance tests (user journeys)
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ conftest.py
β”‚   └── test_user_journey.py
β”œβ”€β”€ security/                # Security tests
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ test_auth.py
β”‚   β”œβ”€β”€ test_authorization.py
β”‚   └── test_input_validation.py
β”œβ”€β”€ schema/                  # OpenAPI schema tests
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── test_openapi.py
└── migrations/              # Migration tests
    β”œβ”€β”€ __init__.py
    └── test_alembic_migrations.py

Note: See Complete Test Types Reference below for extended structure options including integration, security, performance, and migration tests.

Test Categories

1. Unit Tests (tests/unit/)

Purpose: Test individual components in isolation with mocked dependencies.

Characteristics:

  • ⚑ Fast execution (< 1 second per test)
  • πŸ”’ No external dependencies (database, network)
  • 🎭 Use mocks for repositories and external services
  • βœ… Test business logic, validation, and error handling

Examples:

  • Service layer logic (UserService, PostService, CommentService, LikeService)
  • Repository data access patterns
  • Security utilities (password hashing, JWT tokens)
  • Core utilities

Running Unit Tests:

pytest tests/unit/ -v
pytest tests/unit/ -m unit -v

2. End-to-End Tests (tests/e2e/)

Purpose: Test API endpoints with real database connections.

Characteristics:

  • πŸ—„οΈ Use in-memory SQLite database for fast tests
  • πŸ”„ Test full request/response cycle
  • βœ… Verify HTTP status codes, response schemas, and error handling
  • πŸ” Test authentication and authorization

Examples:

  • User registration and authentication flows
  • CRUD operations on posts, comments, likes
  • Authorization and permission checks
  • Input validation at API level

Running E2E Tests:

pytest tests/e2e/ -v
pytest tests/e2e/ -m e2e -v

3. Acceptance Tests (tests/acceptance/)

Purpose: Test complete user journeys and business scenarios.

Characteristics:

  • πŸ‘€ Test complete workflows from user perspective
  • πŸ”— Multiple API calls in sequence
  • βœ… Verify end-to-end business logic
  • πŸ“ Document expected user behavior

Examples:

  • User registration β†’ email confirmation β†’ login β†’ create post
  • Post creation β†’ receiving likes β†’ receiving comments
  • Profile management workflows

Running Acceptance Tests:

pytest tests/acceptance/ -v
pytest tests/acceptance/ -m acceptance -v

Complete Test Types Reference

Below is a comprehensive list of test types typically used in production FastAPI projects. While not all are required, this serves as a complete reference for enterprise-grade testing strategies.

1. Unit Tests βœ… Currently Implemented

Small, isolated tests that validate individual functions or classes.

What to test:

  • Pure business logic
  • Utility functions
  • Pydantic models (validation)
  • Service-layer functions
  • CRUD repository functions (mocked DB)

Tools:

  • pytest
  • pytest-mock or unittest.mock

Location: tests/unit/


2. Integration Tests ⭐ Recommended

Test multiple components working together, often with actual FastAPI app but mocked external services.

What to test:

  • FastAPI routes (using TestClient or httpx.AsyncClient)
  • Database integration (with real or in-memory DB)
  • Dependency overrides
  • Background tasks
  • Auth + middleware interactions

Tools:

  • pytest
  • httpx.AsyncClient (recommended for async routes)
  • Test database (PostgreSQL / SQLite in-memory / Dockerized)

Location: tests/integration/ (can be added)


3. End-to-End (E2E) Tests βœ… Currently Implemented

Full system tests that run the entire stack as realistically as possible.

Characteristics:

  • Spin up the FastAPI service (e.g., via Docker Compose)
  • Hit real HTTP endpoints
  • Use the real database, queues, etc.

Tools:

  • pytest
  • docker-compose or testcontainers
  • httpx or requests

Location: tests/e2e/


4. Contract Tests ⭐ Nice-to-Have

Ensure API request/response formats remain compatible across services.

What to test:

  • JSON schema validation
  • API compatibility between microservices

Tools:

  • schemathesis
  • pydantic model validation

Location: tests/contract/ (can be added)


5. Schema / OpenAPI Tests ⭐ Nice-to-Have

Verify that the automatically generated FastAPI schema is correct.

What to test:

  • /openapi.json correctness
  • Required fields present
  • Enum + format values correct

Tools:

  • pytest
  • FastAPI's OpenAPI schema validation

Location: tests/schema/ (can be added)

Example:

def test_openapi_schema(client):
    """Test that OpenAPI schema is valid."""
    response = client.get("/openapi.json")
    assert response.status_code == 200
    schema = response.json()
    assert "paths" in schema
    assert "/api/v1/users/register" in schema["paths"]

6. Security Tests ⭐ Recommended

Check authentication, authorization, and access restrictions.

What to test:

  • JWT signature & expiry handling
  • 401 / 403 responses for protected routes
  • Role-based access control (RBAC)
  • Password validation rules
  • SQL injection prevention
  • XSS prevention

Tools:

  • pytest
  • pytest-security (optional)

Location: tests/security/ (can be added)

Example:

def test_protected_route_requires_auth(client):
    """Test that protected routes require authentication."""
    response = client.get("/api/v1/users/me")
    assert response.status_code == 403

def test_invalid_jwt_token(client):
    """Test that invalid JWT tokens are rejected."""
    headers = {"Authorization": "Bearer invalid_token"}
    response = client.get("/api/v1/users/me", headers=headers)
    assert response.status_code == 403

7. Performance / Load Tests ⭐ Nice-to-Have

Benchmark endpoints under load.

What to test:

  • Response time under normal load
  • Throughput (requests per second)
  • Memory usage
  • Database query performance

Tools:

  • locust - Load testing framework
  • k6 - Modern load testing tool
  • pytest-benchmark - Micro-benchmarks

Location: tests/performance/ (can be added)

Example:

import pytest
from locust import HttpUser, task

class APIUser(HttpUser):
    @task
    def get_posts(self):
        self.client.get("/api/v1/posts")

8. Database Migration Tests ⭐ Recommended

Ensure DB migrations work end-to-end.

What to test:

  • Alembic migrations apply cleanly
  • Downgrade/upgrade consistency
  • Migration rollback works
  • Data integrity after migrations

Tools:

  • pytest
  • alembic

Location: tests/migrations/ (can be added)

Example:

def test_migrations_upgrade_downgrade(alembic_runner):
    """Test that migrations can be upgraded and downgraded."""
    alembic_runner.upgrade("head")
    alembic_runner.downgrade("base")
    alembic_runner.upgrade("head")

9. Background Task & Worker Tests ⭐ Nice-to-Have

If using Celery/RQ/FastAPI BackgroundTasks.

What to test:

  • Tasks executed with expected parameters
  • Redis queues interactions
  • Scheduling (if any)
  • Task retry logic
  • Task failure handling

Tools:

  • pytest
  • pytest-celery (if using Celery)
  • Mock Redis for testing

Location: tests/tasks/ (can be added)

Example:

def test_send_email_task(mock_background_tasks):
    """Test that email sending task is queued."""
    # Test that task is added to background tasks
    assert len(mock_background_tasks.tasks) == 1

10. API Regression / Snapshot Tests ⭐ Nice-to-Have

Ensure that API responses don't change unexpectedly.

What to test:

  • Response structure consistency
  • Field names and types
  • Error message formats

Tools:

  • pytest-snapshot
  • JSON snapshot files

Location: tests/snapshots/ (can be added)

Example:

def test_user_response_snapshot(client, snapshot):
    """Test that user response matches snapshot."""
    response = client.get("/api/v1/users/1")
    assert response.json() == snapshot

Recommended Test Stack for FastAPI

Must-Have βœ…

  • βœ” Unit tests - Fast, isolated component testing
  • βœ” Integration tests - Component interaction testing
  • βœ” E2E tests - Full system testing with Docker/testcontainers

Nice-to-Have ⭐

  • ⭐ Security tests - Authentication, authorization, input validation
  • ⭐ Database migration tests - Ensure migrations work correctly
  • ⭐ OpenAPI contract tests - Verify API schema correctness
  • ⭐ Performance tests - Load testing for critical endpoints
  • ⭐ Contract tests - API compatibility (for microservices)

Extended Folder Structure

For a complete production-ready test suite, consider this structure:

tests/
β”‚
β”œβ”€β”€ unit/                      # βœ… Unit tests (fast, isolated)
β”‚   β”œβ”€β”€ test_services.py
β”‚   β”œβ”€β”€ test_utils.py
β”‚   β”œβ”€β”€ test_models.py
β”‚   └── test_repositories.py
β”‚
β”œβ”€β”€ integration/               # ⭐ Integration tests
β”‚   β”œβ”€β”€ test_routes_users.py
β”‚   β”œβ”€β”€ test_routes_posts.py
β”‚   β”œβ”€β”€ test_db.py
β”‚   └── test_dependencies.py
β”‚
β”œβ”€β”€ e2e/                       # βœ… End-to-end tests
β”‚   β”œβ”€β”€ test_full_api_flow.py
β”‚   └── conftest.py
β”‚
β”œβ”€β”€ acceptance/                # βœ… Acceptance tests (user journeys)
β”‚   └── test_user_journey.py
β”‚
β”œβ”€β”€ security/                  # ⭐ Security tests
β”‚   β”œβ”€β”€ test_auth.py
β”‚   β”œβ”€β”€ test_authorization.py
β”‚   └── test_input_validation.py
β”‚
β”œβ”€β”€ performance/               # ⭐ Performance tests
β”‚   └── test_benchmarks.py
β”‚
β”œβ”€β”€ migrations/                # ⭐ Migration tests
β”‚   └── test_alembic_migrations.py
β”‚
β”œβ”€β”€ schema/                    # ⭐ OpenAPI schema tests
β”‚   └── test_openapi.py
β”‚
β”œβ”€β”€ contract/                  # ⭐ Contract tests
β”‚   └── test_api_contracts.py
β”‚
└── conftest.py                # Shared fixtures

Running Tests

Using Scripts (Recommended)

# Run all tests with environment validation
./scripts/tests_start.sh

# Run all tests (without validation)
./scripts/test.sh

# Run specific test file
./scripts/test.sh tests/unit/test_user_service.py

# Run tests with pytest flags
./scripts/test.sh tests/unit -v --cov=app

Run All Tests

# Using script
./scripts/tests_start.sh

# Using make
make test

# Direct command
APP_ENV=test pytest

Run Specific Test Category

# Unit tests only
pytest tests/unit/
./scripts/test.sh tests/unit/

# E2E tests only
pytest tests/e2e/
./scripts/test.sh tests/e2e/

# Acceptance tests only
pytest tests/acceptance/
./scripts/test.sh tests/acceptance/

Run with Coverage

# Terminal output
pytest --cov=app --cov-report=term-missing

# HTML report
pytest --cov=app --cov-report=html
# Open htmlcov/index.html in browser

# XML report (for CI/CD)
pytest --cov=app --cov-report=xml

Run Specific Test File

pytest tests/unit/test_user_service.py

Run Specific Test Function

pytest tests/unit/test_user_service.py::TestUserService::test_get_user_by_id_success

pytest -k test_get_user_by_id_success

Run Tests by Marker

# Run only unit tests
pytest -m unit

# Run only e2e tests
pytest -m e2e

# Skip slow tests
pytest -m "not slow"

# Run tests in parallel (requires pytest-xdist)
pytest -n auto

Test Configuration

Environment Variables

Tests automatically configure:

  • APP_ENV=test
  • DB_PROVIDER=sqlite
  • SQLITE_URL=sqlite+aiosqlite:///:memory:
  • SECRET_KEY=test-secret-key-for-testing-purposes-only-min-32-chars

Fixtures

Main conftest.py provides:

  • db_session: Fresh database session for each test
  • client: FastAPI TestClient with database override
  • async_client: AsyncClient for async endpoint testing

Unit conftest.py provides:

  • mock_user_repository: Mocked UserRepository
  • mock_post_repository: Mocked PostRepository
  • mock_comment_repository: Mocked CommentRepository
  • mock_like_repository: Mocked LikeRepository

E2E conftest.py provides:

  • test_user_data: Sample user data
  • authenticated_user: Pre-created authenticated user
  • auth_headers: Authentication headers for requests

Writing New Tests

Unit Test Example

"""Unit tests for MyService."""

import pytest
from unittest.mock import AsyncMock

from app.services.my_service import MyService

@pytest.fixture
def my_service(mock_repository):
    """Create service with mocked repository."""
    return MyService(mock_repository)

class TestMyService:
    """Test suite for MyService."""

    @pytest.mark.asyncio
    async def test_my_method_success(self, my_service, mock_repository):
        """Test successful method execution."""
        mock_repository.get = AsyncMock(return_value={"id": 1})

        result = await my_service.my_method(1)

        assert result is not None
        mock_repository.get.assert_called_once_with(1)

E2E Test Example

"""E2E tests for MyAPI."""

import pytest
from fastapi import status

class TestMyAPI:
    """Test suite for MyAPI endpoints."""

    def test_create_resource(self, client, auth_headers):
        """Test creating a resource."""
        response = client.post(
            "/api/v1/resources",
            headers=auth_headers,
            json={"name": "Test Resource"},
        )

        assert response.status_code == status.HTTP_201_CREATED
        data = response.json()
        assert data["name"] == "Test Resource"

Acceptance Test Example

"""Acceptance tests for user journey."""

import pytest
from fastapi import status

class TestUserJourney:
    """Test complete user journey."""

    def test_complete_workflow(self, client):
        """Test complete workflow from start to finish."""
        # Step 1: Register
        register_response = client.post("/api/v1/users/register", json={...})
        assert register_response.status_code == status.HTTP_201_CREATED

        # Step 2: Login
        login_response = client.post("/api/v1/auth/token", data={...})
        assert login_response.status_code == status.HTTP_200_OK

        # Step 3: Use authenticated endpoint
        token = login_response.json()["access_token"]
        headers = {"Authorization": f"Bearer {token}"}
        resource_response = client.get("/api/v1/resources", headers=headers)
        assert resource_response.status_code == status.HTTP_200_OK

Test Markers

Tests are organized with pytest markers:

  • @pytest.mark.unit: Unit tests
  • @pytest.mark.e2e: End-to-end tests
  • @pytest.mark.acceptance: Acceptance tests
  • @pytest.mark.slow: Slow-running tests
  • @pytest.mark.integration: Integration tests

Best Practices

  1. Follow TDD: Write tests before implementing features
  2. Isolation: Each test should be independent
  3. Clear Names: Use descriptive test names that explain what is being tested
  4. Arrange-Act-Assert: Structure tests clearly
  5. Mock External Dependencies: Unit tests should not hit real databases or APIs
  6. Test Edge Cases: Include tests for error conditions and boundary cases
  7. Keep Tests Fast: Unit tests should run in milliseconds
  8. Use Fixtures: Reuse common test setup via fixtures
  9. Document Complex Tests: Add docstrings explaining complex test scenarios

Coverage Goals

  • Unit Tests: 90%+ coverage for services and repositories
  • E2E Tests: Cover all API endpoints
  • Acceptance Tests: Cover all major user journeys

Current coverage target: 80% (configured in pytest.ini)

Troubleshooting

Database Connection Issues

  • Ensure APP_ENV=test is set
  • Check that SQLite is available (included in Python standard library)

Import Errors

  • Ensure you're running tests from project root
  • Check that app package is in Python path

Async Test Issues

  • Use @pytest.mark.asyncio for async tests
  • Use pytest-asyncio plugin (already in requirements-dev.txt)

Fixture Not Found

  • Check that fixture is defined in appropriate conftest.py
  • Ensure fixture scope matches test needs

Code Quality

The project includes convenient scripts in the scripts/ folder for code quality checks:

Using Scripts (Recommended)

# Fix linting issues automatically
./scripts/lint.sh

# Format code
./scripts/format.sh

# Fix linting and format in one command
./scripts/fix.sh

# Run all checks without modifying files (useful for CI)
./scripts/check.sh

# Run tests
./scripts/test.sh

# Run tests with environment validation
./scripts/tests_start.sh

Using Make Commands

# Run linters
make lint

# Format code
make format

# Run type checker
make type-check

# Run all checks (lint + type-check)
make check

# Run tests
make test

Using Commands Directly

# Run linters
ruff check app scripts
mypy app/

# Format code
ruff format app scripts

# Run tests
APP_ENV=test pytest

See Development Workflow for more testing patterns and tests/README.md for detailed test documentation.


🐳 Docker & Deployment

Local Development

# Method 1: Using helper script (Recommended)
# Automatically loads the correct config file based on APP_ENV
./docker-compose.sh up -d                    # Uses dev.env (default)
APP_ENV=prod ./docker-compose.sh up -d        # Uses prod.env
APP_ENV=staging ./docker-compose.sh up -d     # Uses staging.env
APP_ENV=test ./docker-compose.sh up -d        # Uses test.env

# Method 2: Using --env-file flag
APP_ENV=prod docker-compose --env-file configs/prod.env up -d

# Method 3: Export variables first (bash/zsh)
export APP_ENV=prod
set -a
source configs/prod.env
set +a
docker-compose up -d

# View logs
docker-compose logs -f

# View logs for specific service
docker-compose logs -f backend

# Stop services
docker-compose down

# Stop and remove volumes
docker-compose down -v

Environment Configuration:

  • The application loads configuration from files in the configs/ folder based on APP_ENV:
    • configs/dev.env when APP_ENV=dev (default)
    • configs/staging.env when APP_ENV=staging
    • configs/prod.env when APP_ENV=production or APP_ENV=prod
    • configs/test.env when APP_ENV=test

Important: When using a specific environment (e.g., prod), you must load the config file before running docker-compose so that environment variables are available to docker-compose itself (for service configuration).

Recommended: Use the helper script ./docker-compose.sh which automatically loads the correct config file:

APP_ENV=prod ./docker-compose.sh up -d

This ensures:

  1. The config file (configs/prod.env) is loaded before docker-compose runs
  2. Environment variables are available for docker-compose variable substitution
  3. APP_ENV is set correctly for the application containers

Production Deployment

Deploy to Render.com with automated CI/CD:

  1. Push to main branch
  2. GitHub Actions runs tests
  3. Builds Docker image
  4. Deploys to Render.com
  5. Runs migrations automatically

See Deployment Architecture for complete deployment guide.


πŸ”„ CI/CD & GitHub Actions

CI

This project includes a comprehensive CI/CD pipeline using GitHub Actions that automatically tests every commit and pull request.

CI Workflow

The CI workflow (.github/workflows/ci.yml) runs on every push to main or develop branches and on all pull requests:

Jobs:

  1. Lint Code - Validates code style with ruff
  2. Type Check - Ensures type safety with mypy
  3. Test (Python 3.12 & 3.13) - Runs comprehensive test suites across multiple Python versions
    • Unit tests (with coverage)
    • Integration tests
    • End-to-end tests
    • Acceptance tests
  4. Test Coverage Report - Generates detailed coverage reports (requires 80% minimum)

Services:

  • PostgreSQL 17 (primary database)
  • MongoDB 7 (document storage)
  • Qdrant (vector database)
  • Redis 7 (caching/task queue)

Duration: ~5-10 minutes per run

Setting Up CI Secrets

The CI workflow supports optional secrets for external services (Supabase, Mailgun, B2, Sentry). To configure:

  1. Go to Repository Settings β†’ Secrets and variables β†’ Actions
  2. Add required secrets (see .github/SETUP_SECRETS.md for quick setup)

Minimum required secrets:

TEST_SECRET_KEY        # Generate: python -c "import secrets; print(secrets.token_urlsafe(32))"
TEST_JWT_SECRET_KEY    # Generate: python -c "import secrets; print(secrets.token_urlsafe(32))"

Optional secrets for full functionality:

  • TEST_SUPABASE_URL, TEST_SUPABASE_KEY, TEST_SUPABASE_DB_PASSWORD
  • TEST_MAILGUN_API_KEY, TEST_MAILGUN_DOMAIN
  • TEST_B2_KEY_ID, TEST_B2_APPLICATION_KEY
  • TEST_SENTRY_DSN

See .github/SECRETS.md for detailed secrets documentation.

Viewing CI Results

  • Actions Tab: View all workflow runs and logs
  • Pull Requests: See CI status checks before merging
  • Coverage Reports: Download HTML coverage reports from workflow artifacts

Local CI Testing

Run the same checks locally before pushing:

# Run all checks (lint, type-check, tests)
make check && make test

# Individual checks
make lint          # Code style check
make type-check    # Type safety check
make test          # Run all tests
make test-coverage # Generate coverage report

πŸ—οΈ Architecture Principles

This template follows:

  • Clean Architecture - Dependency inversion, clear layer boundaries
  • Domain-Driven Design - Business logic at the core
  • SOLID Principles - Single responsibility, open/closed, etc.
  • Type Safety - Full type hints with mypy strict mode
  • RORO Pattern - Receive Object, Return Object for all endpoints
  • Modern Dependency Injection - Using Annotated[Type, Depends(...)] pattern (Pydantic v2 & FastAPI best practices)
  • Testability - Dependency injection enables easy unit testing

Note: All dependencies use the modern Annotated pattern for better type safety and alignment with Pydantic v2 conventions. See API Design Documentation for details.

See Architecture Overview for details.


πŸ› οΈ Technology Stack

Core

  • FastAPI - Modern async web framework
  • Pydantic v2 - Data validation with type safety
  • SQLAlchemy 2.0 - Async ORM with modern patterns
  • Alembic - Database migrations
  • Annotated Dependencies - Modern dependency injection using Annotated[Type, Depends(...)] pattern

Domain Models

  • User - Authentication, profile, email confirmation
  • Post - User-generated content with optional images
  • Comment - Comments on posts
  • Like - Post likes with count tracking

Databases

  • PostgreSQL (Supabase) - Primary relational database
  • Database Provider Selection - Configure via DB_PROVIDER (supabase, postgresql, sqlite)
  • SQLite - Development/testing
  • MongoDB - Document storage
  • Qdrant - Vector database for semantic search

Infrastructure

  • Docker & Docker Compose - Containerization
  • Render.com - Production hosting
  • GitHub Actions - CI/CD pipeline
  • Supabase - Managed PostgreSQL + Auth

Development Tools

  • Pytest - Testing framework with async support
  • Ruff - Linter and formatter
  • Mypy - Static type checker (strict mode)
  • Structlog - Structured logging with correlation IDs
  • asgi-correlation-id - Request correlation tracking

πŸ“– Further Reading


🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass:
    ./scripts/tests_start.sh
    # or
    make test
  5. Run code quality checks:
    ./scripts/fix.sh  # Auto-fix linting and format code
    ./scripts/check.sh  # Verify all checks pass
    # or
    make format  # Format code
    make lint    # Check linting
    make check   # Run all checks (lint + type-check)
  6. Commit your changes (git commit -m 'feat: add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

See Development Workflow for detailed contribution guidelines.


πŸ“‹ Makefile Commands

This project includes a comprehensive Makefile for common development tasks. Run make help to see all available commands.

πŸš€ Quick Start Commands

# All-in-one: Initialize DB, format, lint, and test (RECOMMENDED for first-time setup)
make all ENV=dev

# This single command does everything:
# 1. Waits for database to be ready
# 2. Runs database migrations
# 3. Creates initial data (superuser)
# 4. Formats code with ruff
# 5. Lints code
# 6. Runs all tests

πŸ“¦ Installation & Setup

make install                  # Install dependencies using uv
make set-env ENV=dev          # Set environment (dev|staging|production|test)

πŸ—„οΈ Database Commands

# Database initialization (complete setup)
make init-db ENV=dev          # Wait for DB, run migrations, create initial data

# Migration management
make migrate ENV=dev          # Run all pending migrations (upgrade head)
make migrate-current ENV=dev  # Show current migration revision
make migrate-history ENV=dev  # Show migration history
make migrate-revision MESSAGE='add user table' ENV=dev  # Create new migration
make migrate-upgrade REVISION=<rev> ENV=dev  # Upgrade to specific revision
make migrate-downgrade REVISION=-1 ENV=dev  # Downgrade by one revision

Important: The Makefile automatically uses -c app/alembic.ini for all Alembic commands. If running Alembic directly, always specify the config:

python -m alembic -c app/alembic.ini upgrade head
python -m alembic -c app/alembic.ini current

✨ Code Quality Commands

make format                   # Format code with ruff (auto-fix)
make lint                     # Run ruff linter (check only)
make type-check               # Run mypy type checker
make check                    # Run all checks (lint + type-check)

Tip: Use make format before committing to ensure consistent code style.

πŸ§ͺ Testing Commands

make test                     # Run all tests
make test-unit                # Run unit tests only (fast, isolated)
make test-integration         # Run integration tests only
make test-e2e                 # Run end-to-end tests only
make test-acceptance          # Run acceptance tests only
make test-coverage            # Run tests with coverage report

Test Workflow:

  1. Write tests first (TDD approach)
  2. Run make test-unit for fast feedback during development
  3. Run make test before committing
  4. Run make test-coverage to check coverage

πŸš€ Run Server Commands

make dev                      # Run in development mode (auto-reload)
make staging                  # Run in staging environment
make prod                     # Run in production environment

🐳 Docker Commands

# Build
make docker-build             # Build default Docker image
make docker-build-env ENV=dev # Build for specific environment

# Run
make docker-run              # Run with default (dev) environment
make docker-run-env ENV=dev  # Run for specific environment
make docker-logs ENV=dev     # View logs
make docker-stop ENV=dev     # Stop containers

# Docker Compose (full stack)
make docker-compose-up ENV=dev      # Start entire stack
make docker-compose-down ENV=dev   # Stop entire stack
make docker-compose-logs ENV=dev   # View all service logs

🧹 Cleanup Commands

make clean                    # Remove generated files (venv, cache, coverage)

πŸ“– Getting Help

make help                     # Show all available commands with descriptions

πŸ’‘ Common Workflows

First-Time Setup

make install
cp configs/dev.env.example configs/dev.env
# Edit configs/dev.env
docker-compose up -d
make all ENV=dev
make dev

Daily Development

# Start working
make dev

# Before committing
make format                   # Format code
make lint                     # Check for issues
make test                     # Run tests

Creating a Migration

make migrate-revision MESSAGE='add new feature' ENV=dev
# Review the generated migration file
make migrate ENV=dev          # Apply migration

Before Pull Request

make format                   # Format code
make lint                     # Check linting
make type-check               # Check types
make test                     # Run all tests
make test-coverage            # Check coverage

πŸ“ License

This project is licensed under the MIT License.


πŸ’‘ What's Next?

  1. Explore the Documentation
  2. Understand the Architecture
  3. Set up your Development Environment
  4. Test the POC features:
    • Register a new user
    • Confirm email
    • Create posts
    • Add comments
    • Like posts
  5. Build following Best Practices
  6. Deploy using the Deployment Guide

πŸ“ POC Status

This is a Proof of Concept demonstrating:

  • βœ… User authentication and registration workflow
  • βœ… Email confirmation system
  • βœ… Post creation and management
  • βœ… Comment system
  • βœ… Like/unlike functionality
  • βœ… Clean architecture patterns
  • βœ… Type-safe API with Pydantic v2
  • βœ… Multi-database provider support

Note: This POC is built on an enterprise-grade FastAPI template and can be extended for production use.


Built with ❀️ for production-ready FastAPI applications

About

A production-ready FastAPI template for building AI agent applications. This template provides a robust foundation for building scalable, secure, and maintainable services.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages