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 • **contain presentation or formatting logic** (e.g., `formatForDisplay()`) ⸻ ### Domain vs. Presentation Value Objects It is critical to distinguish between **Domain Value Objects** and **Presentation Value Objects** (Displays): - **Domain Value Objects (Core):** Protect business meaning and invariants. They are pure and know nothing about how data is shown to users. - **Display Objects (Website):** Protect presentation logic and formatting. They are used by the Website (both server and client) to ensure consistent display. If the API needs to return formatted strings, this logic belongs in **API Presenters**, not in Domain Value Objects. 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.