Chapter 22: The Full Picture
We have built a complete online bookstore from scratch. Let's step back and see the full architecture, review what we built, and look at where to go from here.
Architecture Overview
┌──────────────┐
│ FastAPI │
│ Endpoints │
└──────┬───────┘
│
┌──────────────────┼──────────────────┐
│ │ │
domain.process() domain.query_for() domain.query_for()
(Commands) (BookCatalog) (StorefrontView)
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Command │ │Projection│ │Projection│
│ Handlers │ │(Read DB) │ │(Read DB) │
└────┬─────┘ └──────────┘ └──────────┘
│
┌────▼─────┐
│Aggregates│
│ (Book, │
│ Order, │
│Inventory,│
│Shipping) │
└────┬─────┘
│ raise_() events
┌────▼─────┐
│ Outbox │──────► Redis Streams
└──────────┘ │
┌──────┼──────┐
│ │ │
┌────▼─┐ ┌──▼───┐ ┌▼────────┐
│Event │ │Proj- │ │Process │
│Handl.│ │ectors│ │Manager │
└──────┘ └──────┘ └─────────┘
Everything We Built
Domain Elements
| Element | Count | Examples |
|---|---|---|
| Aggregates | 4 | Book, Order, Inventory, Shipping |
| Entities | 1 | OrderItem |
| Value Objects | 2 | Money, Address |
| Commands | 8+ | AddBook, PlaceOrder, ConfirmOrder, ShipOrder, RestockInventory, ... |
| Events | 6+ | BookAdded, OrderConfirmed, OrderShipped, BookPriceUpdated, ... |
| Command Handlers | 3+ | BookCommandHandler, OrderCommandHandler, InventoryCommandHandler |
| Event Handlers | 2 | BookEventHandler, OrderEventHandler |
| Projections | 3 | BookCatalog, BookReport, StorefrontView |
| Projectors | 3 | BookCatalogProjector, BookReportProjector, StorefrontProjector |
| Domain Services | 1 | OrderFulfillmentService |
| Process Managers | 1 | OrderFulfillmentPM |
| Subscribers | 1 | BookSupplyWebhookSubscriber |
CLI Commands Used
| Command | Purpose | Chapter |
|---|---|---|
protean shell |
Interactive exploration | 1 |
protean database setup |
Create database tables | 8 |
protean database drop |
Drop database tables | 8 |
protean database truncate |
Clear all data | 8 |
protean server |
Start async processing engine | 12 |
protean events trace |
Trace message causation chains | 16 |
protean dlq list |
List dead-letter queue entries | 17 |
protean dlq inspect |
Inspect a failed message | 17 |
protean dlq replay |
Replay a failed message | 17 |
protean dlq purge |
Remove unrecoverable messages | 17 |
protean subscriptions status |
Check handler health | 18 |
protean observatory |
Real-time monitoring dashboard | 18 |
CQRS Patterns Applied
| Pattern | How We Used It |
|---|---|
| Command/Query Separation | Commands change state; query_for() reads projections |
| Event-Driven Side Effects | Events trigger inventory, notifications, projections |
| Read Model Projections | BookCatalog, BookReport, StorefrontView |
| Outbox Pattern | Reliable event delivery via Redis |
| Anti-Corruption Layer | Subscriber translates external data |
| Domain Services | Cross-aggregate validation (inventory check) |
| Process Manager / Saga | Multi-step fulfillment with compensation |
| Priority Lanes | Bulk imports without starving production |
| Dead Letter Queues | Failure recovery with fix-and-replay |
Production Configuration Reference
A complete domain.toml for production:
[databases.default]
provider = "postgresql"
database_uri = "${DATABASE_URL}"
[brokers.default]
provider = "redis"
url = "${REDIS_URL}"
event_processing = "async"
command_processing = "async"
enable_outbox = true
[event_store]
provider = "memory"
[server]
default_subscription_type = "stream"
messages_per_tick = 100
priority_lanes = true
[server.stream_subscription]
blocking_timeout_ms = 100
max_retries = 3
retry_delay_seconds = 1
enable_dlq = true
Running the Complete System
# 1. Start infrastructure
docker run -d --name bookshelf-db -e POSTGRES_DB=bookshelf -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:15
docker run -d --name bookshelf-redis -p 6379:6379 redis:7-alpine
# 2. Set up the database
export PROTEAN_DOMAIN=bookshelf
protean database setup
# 3. Start the async processing server
protean server &
# 4. Start the API
uvicorn bookshelf.api:app --host 0.0.0.0 --port 8000 &
# 5. Start the observatory (optional)
protean observatory --port 9000 &
Where to Go from Here
Event Sourcing
Store events as the source of truth instead of snapshots. The Event Sourcing Tutorial is a comprehensive 22-chapter guide that builds a banking platform, covering temporal queries, snapshots, event upcasting, and more.
Deep Dives
- Guides — detailed coverage of each domain element
- Architecture — DDD, CQRS, and Event Sourcing theory
- Adapters — database, broker, cache, and event store adapters
- Patterns — aggregate sizing, idempotent handlers, validation layering
- CLI Reference — all command-line tools
Application Services (The DDD Alternative)
This tutorial used Commands and Command Handlers (the CQRS approach). In the pure DDD approach, Application Services fill the same role — they receive requests directly and coordinate the domain logic, without the explicit command objects. See Application Services and the DDD Pathway for that reading order.
Congratulations! You have built and operated a complete production CQRS system with Protean. The bookstore handles real traffic asynchronously, validates business rules across aggregates, integrates with external systems, and has full operational tooling for monitoring, debugging, and recovery.