Designing CQRS Architecture

1. Understanding CQRS Pattern

AspectDetail
CommandState-changing op (write)
QueryRead; returns data without side effects
Separate modelsOptimize each independently
When to useAsymmetric R/W, complex domain, audit needs
When NOTSimple CRUD; adds complexity

2. Designing Command Side

ElementDetail
Command handlerLoads aggregate, validates, applies events
ValidationDomain invariants enforced
PersistenceEvent store or normalized OLTP
OutputDomain events emitted to bus

3. Designing Query Side

ElementDetail
Read model storeDenormalized: ES, Redis, MV
ProjectorSubscribes to events, updates read store
Read APIDirect query; no domain logic
Multiple read modelsOne per use case

4. Designing Read Model Projections

Example: Projection updater (Java)

@EventHandler
public void on(OrderPlaced e) {
    readDb.upsert("order_summary", Map.of(
        "id", e.orderId(),
        "customer", e.customerName(),
        "total", e.total(),
        "status", "PLACED",
        "placed_at", e.occurredAt()
    ));
}
ConcernDetail
IdempotentTrack processed event_id
OrderPer aggregate, in event order
Failure handlingRetry, DLQ, alert

5. Designing Event Sourcing with CQRS

SynergyDetail
Source of truthEvent store
ProjectionsMany read models from same events
Time travelReplay to any point
RebuildTrash + replay to fix bugs

6. Designing Eventual Consistency Handling

UX StrategyDetail
Optimistic UIShow change immediately, reconcile
Read after write to write sideBypass read model briefly
Polling with versionWait until projection catches up
Display lag SLA"Updated ~5s ago"

7. Designing Read Model Synchronization

MechanismDetail
Push (events)Projector subscribes to event stream
Pull (CDC)Debezium streams DB changes
Lag monitoringAlert if > SLA
BackpressurePause writes if projector falls behind

8. Designing Command Validation

LayerValidation
SchemaRequired fields, types
AuthorizationCaller can perform op
Domain invariantsInside aggregate
Cross-aggregateSaga or process manager

9. Designing Query Optimization

TechniqueDetail
DenormalizePre-join in projection
Specialized storesES for search, Redis for KV
CachingRead model + cache
Index per queryTailored to access pattern

10. Designing Read Model Rebuilding

Rebuild Process

  1. Create new read model store/version
  2. Replay events from offset 0 into new store
  3. Catch up to live tail
  4. Switch reads to new store atomically
  5. Decommission old store

11. Designing CQRS with Event Store

ElementDetail
WriteAppend events to stream-per-aggregate
ConcurrencyOptimistic via expected version
ReadSubscribe + project
ToolsEventStoreDB, Marten + Postgres, Axon

12. Designing CQRS Scaling Strategy

SideScaling
Command sideShard by aggregate id
Query sideRead replicas, denormalized stores
ProjectorPartitioned consumer group
Hot aggregatePartition by sub-key