251 lines
4.3 KiB
Markdown
251 lines
4.3 KiB
Markdown
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
|
|
|
|
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. |