Domain Objects Design Guide (Clean Architecture) This document defines all domain object types used in the Core and assigns strict responsibilities and boundaries. Its goal is to remove ambiguity between: • Entities • Value Objects • Aggregate Roots • Domain Services • Domain Events The rules in this document are non-negotiable. ⸻ Core Principle Domain objects represent business truth. They: • outlive APIs and UIs • must remain stable over time • must not depend on technical details If a class answers a business question, it belongs here. ⸻ 1. Entities Definition An Entity is a domain object that: • has a stable identity • changes over time • represents a business concept Identity matters more than attributes. ⸻ Responsibilities Entities MUST: • own their identity • enforce invariants on state changes • expose behavior, not setters Entities MUST NOT: • depend on DTOs or transport models • access repositories or services • perform IO • know about frameworks ⸻ Creation Rules • New entities are created via create() • Existing entities are reconstructed via rehydrate() core//domain/entities/ ⸻ Example • League • Season • Race • Driver ⸻ 2. Value Objects Definition A Value Object is a domain object that: • has no identity • is immutable • is defined by its value ⸻ Responsibilities Value Objects MUST: • validate their own invariants • be immutable • be comparable by value Value Objects MUST NOT: • contain business workflows • reference entities • perform IO ⸻ Creation Rules • create() for new domain meaning • fromX() for interpreting external formats core//domain/value-objects/ ⸻ Example • Money • LeagueName • RaceTimeOfDay • SeasonSchedule ⸻ 3. Aggregate Roots Definition An Aggregate Root is an entity that: • acts as the consistency boundary • protects invariants across related entities All access to the aggregate happens through the root. ⸻ Responsibilities Aggregate Roots MUST: • enforce consistency rules • control modifications of child entities Aggregate Roots MUST NOT: • expose internal collections directly • allow partial updates bypassing rules ⸻ Example • League (root) • Season (root) ⸻ 4. Domain Services Definition A Domain Service encapsulates domain logic that: • does not naturally belong to a single entity • involves multiple domain objects ⸻ Responsibilities Domain Services MAY: • coordinate entities • calculate derived domain values Domain Services MUST: • operate only on domain types • remain stateless Domain Services MUST NOT: • access repositories • orchestrate use cases • perform IO core//domain/services/ ⸻ Example • SeasonConfigurationFactory • ChampionshipAggregator • StrengthOfFieldCalculator ⸻ 5. Domain Events Definition A Domain Event represents something that: • has already happened • is important to the business ⸻ Responsibilities Domain Events MUST: • be immutable • carry minimal information Domain Events MUST NOT: • contain behavior • perform side effects core//domain/events/ ⸻ Example • RaceCompleted • SeasonActivated ⸻ 6. What Does NOT Belong in Domain Objects ❌ DTOs ❌ API Models ❌ View Models ❌ Repositories ❌ Framework Types ❌ Logging ❌ Configuration If it depends on infrastructure, it does not belong here. ⸻ 7. Dependency Rules Entities → Value Objects Entities → Domain Services Domain Services → Entities Reverse dependencies are forbidden. ⸻ 8. Testing Requirements Domain Objects MUST: • have unit tests for invariants • be tested without mocks Domain Services MUST: • have deterministic tests ⸻ Mental Model (Final) Entities protect state. Value Objects protect meaning. Aggregate Roots protect consistency. Domain Services protect cross-entity rules. Domain Events describe facts. ⸻ Final Summary • Domain objects represent business truth • They are pure and framework-free • They form the most stable part of the system If domain objects are clean, everything else becomes easier.