A complete Domain-Driven Design implementation in Python, converted from Laravel.
This project follows DDD patterns with a clear separation of concerns:
ddd_python_sample/
├── src/ # Domain and Application layers
│ ├── shared/ # Shared kernel
│ │ ├── domain/ # Base classes (Entity, Event)
│ │ ├── application/ # Bus interfaces
│ │ └── infrastructure/ # Event bus, database session
│ ├── client_bc/ # Client Bounded Context
│ │ └── client/
│ │ ├── domain/ # Entity, ValueObjects, Events
│ │ ├── application/ # Commands, Queries, DTOs
│ │ └── infrastructure/ # Repository, Model
│ └── reservation_bc/ # Reservation Bounded Context
│ └── booking/
│ ├── domain/ # Aggregate, ValueObjects, Events
│ ├── application/ # Commands, Queries, DTOs
│ └── infrastructure/ # Repository, Models
├── adapters/ # Infrastructure adapters
│ └── http/ # HTTP adapter (FastAPI)
│ └── api/
│ ├── clients/ # Client endpoints
│ └── bookings/ # Booking endpoints
├── tests/ # Test suite
├── main.py # Application entry point
└── pyproject.toml # Python dependencies
- Immutable (
@dataclass(frozen=True)) - Self-validating in
__post_init__ - ULID-based identifiers (26 characters)
- Examples:
BookingId,PartySize,Money,TimeSlot
- Mutable (
@dataclass) - Factory methods:
create()andreconstitute() - Business logic encapsulated in methods
- Domain events recorded on state changes
Bookingis the aggregate root- Controls access to
BookingProduct(child entity) - Enforces consistency boundaries
- Immutable (
@dataclass(frozen=True)) - Past tense naming (
BookingConfirmed, notConfirmBooking) - Created via
from_entity()factory methods - Published after successful persistence
- Interface in domain layer (ABC)
- Implementation in infrastructure layer (SQLAlchemy)
- Mapper methods:
_to_entity(),_to_model()
- Commands modify state
- Queries return DTOs
- Separate handlers for each
Cliententity withClientId- Events:
ClientCreatedEvent - Commands:
CreateClientCommand - Queries:
GetClientByIdQuery
Bookingaggregate withBookingProduct- Value Objects:
BookingId,PartySize,Money,TimeSlot - Enums:
BookingStatus,ProductType - Events:
BookingCreated,BookingConfirmed,BookingCancelled, etc. - Commands:
CreateBooking,ConfirmBooking,CancelBooking - Queries:
GetBookingById,IndexBookings
# Install dependencies
pip install poetry
poetry install
# Run the application
poetry run python main.py
# Or with uvicorn directly
poetry run uvicorn main:app --reloadAPI documentation available at: http://localhost:8000/docs
POST /api/clients- Create clientGET /api/clients/{id}- Get client
POST /api/bookings- Create bookingGET /api/bookings- List bookings (with filters)GET /api/bookings/{id}- Get bookingPOST /api/bookings/{id}/confirm- Confirm bookingPOST /api/bookings/{id}/cancel- Cancel bookingGET /api/bookings/restaurant/{id}- Get bookings by restaurant
poetry run pytest- Value Objects as dataclass(frozen=True) - Ensures immutability
- ULID for IDs - Time-ordered, globally unique, URL-safe
- Factory methods on entities -
create()for new,reconstitute()for hydration - Events recorded in entity - Released after persistence
- DTOs for layer boundaries - Separate from domain objects
- Pydantic for HTTP schemas - Validation and serialization