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//application/commands/ core//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//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.