Instructions: FastAPI Backend with Hexagonal Architecture
You are a Python/FastAPI expert. Create a backend following hexagonal architecture, SOLID principles, and KISS.
🏗️ Project Structure
├── .github/workflows/ # CI/CD (tests, linting, deploy)
├── src/
│ ├── main.py # FastAPI app
│ ├── config.py # Pydantic Settings
│ ├── dependencies.py # Dependency injection
│ ├── domain/ # Business core
│ │ ├── entities/ # Business entities (Pydantic)
│ │ ├── ports/ # Interfaces (ABC)
| │ | ├── inbound/ # Interfaces for application use cases entry points(ABC)
| │ | ├── outbound/ # Interfaces for infrastructure implementation (ABC)
│ │ └── services/ # Business services (optional, required if use case logic start to be heavy)
│ │ └── errors/ # Redefined and centralised all errors types and messages
│ │ └── logging/ # Centralised all log messages
│ ├── application/
│ │ ├── requests/ # Input DTOs (Pydantic)
│ │ └── responses/ # FastAPI responses output DTOs (Pydantic)z
│ │ ├── use_cases/ # Application logic
│ │ └── routes/ # FastAPI routes
│ └── infrastructure/ # One folder = one implementation
│ ├── postgres/ # adapter.py + models.py
│ ├── mongodb/ # adapter.py + models.py
│ └── email/ # adapter.py
For per-layer file templates, load the relevant reference file below.
Core principles
- Domain stays pure: entities hold invariants, no framework/infra imports inside
domain/.
- Application orchestrates: use cases coordinate domain + ports; no direct infrastructure calls.
- Infrastructure adapts: one folder per concrete adapter (
postgres/, mongodb/, email/).
- Ports = ABCs: interfaces in
domain/ports/ (inbound/ for app entry points, outbound/ for infra contracts).
- Inbound/outbound split: inbound ports invoked by routers/schedulers/consumers; outbound ports implemented by adapters.
- Direct transformations: convert at the adapter boundary inline; no
from_entity / to_entity mapper helpers.
- No Response DTOs for domain: response/request DTOs live in
application/; domain entities stay domain-shaped.
- Centralized errors: all error codes, messages, and custom exceptions in
domain/errors/.
- Centralized logging: all log message enums in
domain/logging/.
- KISS: no
__init__.py unless re-export is genuinely needed; prefer flat, explicit imports.
🛡️ Edge cases (mandatory handling)
Every use case, adapter, and route MUST handle edge cases defensively, not just the happy path. During implementation, cover:
- Null / None / undefined inputs — validate at the port boundary; raise the correct domain error, never let
None propagate silently into business logic
- Empty / boundary values — empty list, empty string,
0, negative numbers, datetime.min / datetime.max, single-element collections; handle explicitly
- Off-by-one boundaries — pagination first/last page, offset equals total count, zero results
- Invalid / malformed input — Pydantic validation covers schema, but add domain-level validation for business rules (invalid state transition, value out of business range)
- Concurrency / race conditions — duplicate creation, optimistic locking conflict, idempotency key replay; handle with proper error or upsert
- External adapter failure — outbound adapter raises or times out; catch at the use case level, map to the correct domain error, never silently swallow
- State transitions — already-exists, not-found, already-deleted, illegal transition; raise the correct centralized error from
domain/errors/
If the feature has domain invariants, enforce them in the entity constructor / validators and raise the matching domain/errors/ exception when violated.
Workflow
- Pre-flight: read the repo
AGENTS.md for existing conventions and tooling.
- Scaffold structure →
references/project-structure.md — create the directory tree.
- Bootstrap app →
references/main-config-dependencies.md — main.py, config.py, dependencies.py.
- Wire routes/DTOs →
references/routes-requests-responses.md — routes/, requests/, responses/.
- Implement use cases →
references/use-cases.md — application logic + inbound ports.
- Define entities →
references/entities.md — domain/entities/ Pydantic models.
- Centralize errors →
references/errors.md — error codes, messages, custom exceptions.
- Centralize logging →
references/logging.md — log message enums.
- Define ports →
references/ports.md — domain/ports/inbound/ + domain/ports/outbound/ ABCs.
References
references/project-structure.md — Directory tree and folder responsibilities.
references/main-config-dependencies.md — main.py, config.py, dependencies.py templates (lifespan, settings, DI).
references/routes-requests-responses.md — routes/, requests/, responses/ templates (routers + DTOs).
references/use-cases.md — use_cases/ template (application logic + inbound port usage).
references/entities.md — domain/entities/ Pydantic entity templates.
references/errors.md — Error codes, ErrorMessage enum, custom exceptions.
references/logging.md — Log message StrEnum templates.
references/ports.md — domain/ports/ ABC interfaces (inbound/outbound).
1---2name: hexagonal-python-patterns3description: FastAPI / Python backend patterns: hexagonal architecture, SOLID, KISS, ports (ABC inbound/outbound), Pydantic entities, use cases, centralized errors/logging. Trigger on: FastAPI, Python backend, pyproject.toml, uv.lock, or any request to implement/refactor/fix/scaffold a Python endpoint, use case, or adapter. Use when working on ANY FastAPI or Python backend, not only explicitly hexagonal ones; defaults the structure to hexagonal.4---56# Instructions: FastAPI Backend with Hexagonal Architecture78You are a Python/FastAPI expert. Create a backend following hexagonal architecture, SOLID principles, and KISS.910## 🏗️ Project Structure1112```13├── .github/workflows/ # CI/CD (tests, linting, deploy)14├── src/15│ ├── main.py # FastAPI app16│ ├── config.py # Pydantic Settings17│ ├── dependencies.py # Dependency injection18│ ├── domain/ # Business core19│ │ ├── entities/ # Business entities (Pydantic)20│ │ ├── ports/ # Interfaces (ABC)21| │ | ├── inbound/ # Interfaces for application use cases entry points(ABC)22| │ | ├── outbound/ # Interfaces for infrastructure implementation (ABC)23│ │ └── services/ # Business services (optional, required if use case logic start to be heavy)24│ │ └── errors/ # Redefined and centralised all errors types and messages25│ │ └── logging/ # Centralised all log messages26│ ├── application/27│ │ ├── requests/ # Input DTOs (Pydantic)28│ │ └── responses/ # FastAPI responses output DTOs (Pydantic)z29│ │ ├── use_cases/ # Application logic30│ │ └── routes/ # FastAPI routes31│ └── infrastructure/ # One folder = one implementation32│ ├── postgres/ # adapter.py + models.py33│ ├── mongodb/ # adapter.py + models.py34│ └── email/ # adapter.py35```3637For per-layer file templates, load the relevant reference file below.3839## Core principles4041- **Domain stays pure**: entities hold invariants, no framework/infra imports inside `domain/`.42- **Application orchestrates**: use cases coordinate domain + ports; no direct infrastructure calls.43- **Infrastructure adapts**: one folder per concrete adapter (`postgres/`, `mongodb/`, `email/`).44- **Ports = ABCs**: interfaces in `domain/ports/` (`inbound/` for app entry points, `outbound/` for infra contracts).45- **Inbound/outbound split**: inbound ports invoked by routers/schedulers/consumers; outbound ports implemented by adapters.46- **Direct transformations**: convert at the adapter boundary inline; no `from_entity` / `to_entity` mapper helpers.47- **No Response DTOs for domain**: response/request DTOs live in `application/`; domain entities stay domain-shaped.48- **Centralized errors**: all error codes, messages, and custom exceptions in `domain/errors/`.49- **Centralized logging**: all log message enums in `domain/logging/`.50- **KISS**: no `__init__.py` unless re-export is genuinely needed; prefer flat, explicit imports.5152## 🛡️ Edge cases (mandatory handling)53Every use case, adapter, and route MUST handle edge cases defensively, not just the happy path. During implementation, cover:54- **Null / None / undefined inputs** — validate at the port boundary; raise the correct domain error, never let `None` propagate silently into business logic55- **Empty / boundary values** — empty list, empty string, `0`, negative numbers, `datetime.min` / `datetime.max`, single-element collections; handle explicitly56- **Off-by-one boundaries** — pagination first/last page, offset equals total count, zero results57- **Invalid / malformed input** — Pydantic validation covers schema, but add domain-level validation for business rules (invalid state transition, value out of business range)58- **Concurrency / race conditions** — duplicate creation, optimistic locking conflict, idempotency key replay; handle with proper error or upsert59- **External adapter failure** — outbound adapter raises or times out; catch at the use case level, map to the correct domain error, never silently swallow60- **State transitions** — already-exists, not-found, already-deleted, illegal transition; raise the correct centralized error from `domain/errors/`6162If the feature has domain invariants, enforce them in the entity constructor / validators and raise the matching `domain/errors/` exception when violated.6364## Workflow65661. **Pre-flight**: read the repo `AGENTS.md` for existing conventions and tooling.672. **Scaffold structure** → `references/project-structure.md` — create the directory tree.683. **Bootstrap app** → `references/main-config-dependencies.md` — `main.py`, `config.py`, `dependencies.py`.694. **Wire routes/DTOs** → `references/routes-requests-responses.md` — `routes/`, `requests/`, `responses/`.705. **Implement use cases** → `references/use-cases.md` — application logic + inbound ports.716. **Define entities** → `references/entities.md` — `domain/entities/` Pydantic models.727. **Centralize errors** → `references/errors.md` — error codes, messages, custom exceptions.738. **Centralize logging** → `references/logging.md` — log message enums.749. **Define ports** → `references/ports.md` — `domain/ports/inbound/` + `domain/ports/outbound/` ABCs.7576## References7778- `references/project-structure.md` — Directory tree and folder responsibilities.79- `references/main-config-dependencies.md` — `main.py`, `config.py`, `dependencies.py` templates (lifespan, settings, DI).80- `references/routes-requests-responses.md` — `routes/`, `requests/`, `responses/` templates (routers + DTOs).81- `references/use-cases.md` — `use_cases/` template (application logic + inbound port usage).82- `references/entities.md` — `domain/entities/` Pydantic entity templates.83- `references/errors.md` — Error codes, `ErrorMessage` enum, custom exceptions.84- `references/logging.md` — Log message `StrEnum` templates.85- `references/ports.md` — `domain/ports/` ABC interfaces (inbound/outbound).