refactor use cases

This commit is contained in:
2025-12-21 01:20:27 +01:00
parent c12656d671
commit 8ecd638396
39 changed files with 2523 additions and 686 deletions

View File

@@ -0,0 +1,264 @@
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/<context>/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/<context>/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/<context>/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/<context>/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.

View File

@@ -0,0 +1,252 @@
Services Design Guide (Clean Architecture)
This document defines all service types used across the system and assigns clear, non-overlapping responsibilities.
It exists to remove ambiguity around the word “service”, which is heavily overloaded.
The rules below are strict.
Overview
The system contains four distinct service categories, each in a different layer:
1. Frontend Services
2. API Services
3. Core Application Services
4. Core Domain Services
They must never be mixed.
1. Frontend Services
Purpose
Frontend services orchestrate UI-driven workflows.
They answer the question:
“How does the UI obtain and submit data?”
Responsibilities
Frontend services MAY:
• call API clients
• apply client-side guards (blockers, throttles)
• create View Models
• orchestrate multiple API calls
• handle recoverable UI errors
Frontend services MUST NOT:
• contain business rules
• validate domain invariants
• modify domain state
• know about core domain objects
Placement
apps/website/lib/services/
Example
• LeagueService
• RaceService
• AuthService
Each service is UI-facing, not business-facing.
2. API Services (Application Services)
Purpose
API services adapt HTTP-level concerns to core use cases.
They answer the question:
“How does an external client interact with the core?”
Responsibilities
API services MAY:
• orchestrate multiple use cases
• perform authorization checks
• map transport input to use-case input
• coordinate transactions
API services MUST NOT:
• contain domain logic
• enforce business invariants
• build domain entities
• return domain objects
Placement
apps/api/**/ApplicationService.ts
Example
• LeagueApplicationService
• SeasonApplicationService
API services are delivery-layer coordinators.
3. Core Application Services (Use Cases)
Purpose
Core application services implement business use cases.
They answer the question:
“What does the system do?”
Responsibilities
Use Cases MUST:
• accept primitive input only
• create Value Objects
• create or modify Entities
• enforce business rules
• call repositories via ports
• communicate results via output ports
Use Cases MUST NOT:
• know about HTTP, UI, or frameworks
• return DTOs
• perform persistence directly
Placement
core/<context>/application/commands/
core/<context>/application/queries/
Example
• CreateLeagueUseCase
• ApplyPenaltyUseCase
• GetLeagueStandingsQuery
Use Cases define system behavior.
4. Core Domain Services
Purpose
Domain services encapsulate domain logic that does not belong to a single entity.
They answer the question:
“What rules exist that span multiple domain objects?”
Responsibilities
Domain services MAY:
• coordinate multiple entities
• compute derived domain values
• enforce cross-aggregate rules
Domain services MUST:
• use only domain concepts
• return domain objects or primitives
Domain services MUST NOT:
• access repositories
• depend on application services
• perform IO
Placement
core/<context>/domain/services/
Example
• SeasonConfigurationFactory
• ChampionshipAggregator
• StrengthOfFieldCalculator
Domain services protect business integrity.
Dependency Rules (Non-Negotiable)
Frontend Service
→ API Client
→ API Service
→ Core Use Case
→ Domain Service / Entity
Reverse dependencies are forbidden.
Anti-Patterns (Forbidden)
❌ Frontend calling core directly
❌ API service constructing domain entities
❌ Use case returning DTOs
❌ Domain service accessing repositories
❌ Single class acting as multiple service types
Naming Conventions
Layer Naming
Frontend *Service
API *ApplicationService
Core Application *UseCase, *Query
Core Domain *Service, *Factory, *Calculator
Mental Model (Final)
Services coordinate.
Use Cases decide.
Domain enforces truth.
Adapters translate.
If a class violates this mental model, it is in the wrong layer.
Final Summary
• “Service” means different things in different layers
• Mixing service types causes architectural decay
• Clean Architecture remains simple when roles stay pure
This document defines the only allowed service roles in the system.