CQRS Light with Clean Architecture This document defines CQRS Light as a pragmatic, production-ready approach that integrates cleanly with Clean Architecture. It is intentionally non-dogmatic, avoids event-sourcing overhead, and focuses on clarity, performance, and maintainability. ⸻ 1. What CQRS Light Is CQRS Light separates how the system writes data from how it reads data — without changing the core architecture. Key properties: • Commands and Queries are separated logically, not infrastructurally • Same database is allowed • No event bus required • No eventual consistency by default CQRS Light is an optimization, not a foundation. ⸻ 2. What CQRS Light Is NOT CQRS Light explicitly does not include: • Event Sourcing • Message brokers • Projections as a hard requirement • Separate databases • Microservices Those can be added later if needed. ⸻ 3. Why CQRS Light Exists Without CQRS: • Reads are forced through domain aggregates • Aggregates grow unnaturally large • Reporting logic pollutes the domain • Performance degrades due to object loading CQRS Light solves this by allowing: • Strict domain logic on writes • Flexible, optimized reads ⸻ 4. Core Architectural Principle Writes protect invariants. Reads optimize information access. Therefore: • Commands enforce business rules • Queries are allowed to be pragmatic and denormalized ⸻ 5. Placement in Clean Architecture CQRS Light does not introduce new layers. It reorganizes existing ones. core/ └── / └── application/ ├── commands/ # Write side (Use Cases) └── queries/ # Read side (Query Use Cases) Domain remains unchanged. ⸻ 6. Command Side (Write Model) Purpose • Modify state • Enforce invariants • Emit outcomes Characteristics • Uses Domain Entities and Value Objects • Uses Repositories • Uses Output Ports • Transactional Example Structure core/racing/application/commands/ ├── CreateLeagueUseCase.ts ├── ApplyPenaltyUseCase.ts └── RegisterForRaceUseCase.ts ⸻ 7. Query Side (Read Model) Purpose • Read state • Aggregate data • Serve UI efficiently Characteristics • No domain entities • No invariants • No side effects • May use SQL/ORM directly Example Structure core/racing/application/queries/ ├── GetLeagueStandingsQuery.ts ├── GetDashboardOverviewQuery.ts └── GetDriverStatsQuery.ts Queries are still Use Cases, just read-only ones. ⸻ 8. Repositories in CQRS Light Write Repositories • Used by command use cases • Work with domain entities • Enforce consistency core/racing/domain/repositories/ └── LeagueRepositoryPort.ts ⸻ Read Repositories • Used by query use cases • Return flat, optimized data • Not domain repositories core/racing/application/ports/ └── LeagueStandingsReadPort.ts Implementation lives in adapters. ⸻ 9. Performance Benefits (Why It Matters) Without CQRS Light • Aggregate loading • N+1 queries • Heavy object graphs • CPU and memory overhead With CQRS Light • Single optimized queries • Minimal data transfer • Database does aggregation • Lower memory footprint This results in: • Faster endpoints • Simpler code • Easier scaling ⸻ 10. Testing Strategy Commands • Unit tests • Mock repositories and ports • Verify output port calls Queries • Simple unit tests • Input → Output verification • No mocks beyond data source CQRS Light reduces the need for complex integration tests. ⸻ 11. When CQRS Light Is a Good Fit Use CQRS Light when: • Read complexity is high • Write logic must stay strict • Dashboards or analytics exist • Multiple clients consume the system Avoid CQRS Light when: • Application is CRUD-only • Data volume is small • Read/write patterns are identical ⸻ 12. Migration Path CQRS Light allows incremental adoption: 1. Start with classic Clean Architecture 2. Separate commands and queries logically 3. Optimize read paths as needed 4. Introduce events or projections later (optional) No rewrites required. ⸻ 13. Key Rules (Non-Negotiable) • Commands MUST use the domain • Queries MUST NOT modify state • Queries MUST NOT enforce invariants • Domain MUST NOT depend on queries • Core remains framework-agnostic ⸻ 14. Mental Model Think of CQRS Light as: One core truth, two access patterns. The domain defines truth. Queries define convenience. ⸻ 15. Final Summary CQRS Light provides: • Cleaner domain models • Faster reads • Reduced complexity • Future scalability Without: • Infrastructure overhead • Event sourcing complexity • Premature optimization It is the safest way to gain CQRS benefits while staying true to Clean Architecture.