207 lines
4.3 KiB
Markdown
207 lines
4.3 KiB
Markdown
Frontend & Backend Output Shapes – Clean Architecture (Strict, Final)
|
||
|
||
This document defines the exact responsibilities, naming, and placement of all data shapes involved in delivering data from Core → API → Frontend UI.
|
||
|
||
It resolves all ambiguity around Presenters, View Models, DTOs, and Output Ports.
|
||
There is no overlap of terminology across layers.
|
||
|
||
⸻
|
||
|
||
1. Core Layer (Application / Use Cases)
|
||
|
||
Core Output Ports (formerly “Presenters”)
|
||
|
||
In the Core, a Presenter is not a UI concept.
|
||
|
||
It is an Output Port that defines how a Use Case emits its result.
|
||
|
||
Rules
|
||
• Core Output Ports:
|
||
• define what data is emitted
|
||
• do not store state
|
||
• do not expose getters
|
||
• do not reference DTOs or View Models
|
||
• Core never pulls data back from an output port
|
||
• Core calls present() and stops
|
||
|
||
Naming
|
||
• *OutputPort
|
||
• *Result (pure application result)
|
||
|
||
Example
|
||
|
||
export interface CompleteDriverOnboardingResult {
|
||
readonly success: boolean;
|
||
readonly driverId?: string;
|
||
readonly error?: string;
|
||
}
|
||
|
||
export interface CompleteDriverOnboardingOutputPort {
|
||
present(result: CompleteDriverOnboardingResult): void;
|
||
}
|
||
|
||
The Core does not know or care what happens after present() is called.
|
||
|
||
⸻
|
||
|
||
2. API Layer (Delivery / Adapter)
|
||
|
||
API Presenters (Response Mappers)
|
||
|
||
API Presenters are Adapters.
|
||
|
||
They:
|
||
• implement Core Output Ports
|
||
• translate Core Results into API Response DTOs
|
||
• store response state temporarily for the controller
|
||
|
||
They are not View Models.
|
||
|
||
Rules
|
||
• API Presenters:
|
||
• implement a Core Output Port
|
||
• map Core Results → API Responses
|
||
• may store state internally
|
||
• API Presenters must not:
|
||
• contain business logic
|
||
• reference frontend View Models
|
||
|
||
Naming
|
||
• *Presenter or *ResponseMapper
|
||
• Output types end with Response or ApiResponse
|
||
|
||
⸻
|
||
|
||
3. Frontend Layer (apps/website)
|
||
|
||
View Models (UI-Owned, Final Form)
|
||
|
||
A View Model represents fully prepared UI state.
|
||
|
||
Only the frontend has Views — therefore only the frontend has View Models.
|
||
|
||
Rules
|
||
• View Models:
|
||
• live only in apps/website
|
||
• accept API Response DTOs as input
|
||
• expose UI-ready data and helpers
|
||
• View Models must not:
|
||
• contain domain logic
|
||
• validate business rules
|
||
• perform side effects
|
||
• be sent back to the server
|
||
|
||
Naming
|
||
• *ViewModel
|
||
|
||
⸻
|
||
|
||
4. Website Presenters (DTO → ViewModel)
|
||
|
||
Website Presenters are pure mappers.
|
||
|
||
They:
|
||
• convert API Response DTOs into View Models
|
||
• perform formatting and reshaping
|
||
• are deterministic and side-effect free
|
||
|
||
They are not Core Presenters.
|
||
|
||
Rules
|
||
• Input: API DTOs
|
||
• Output: View Models
|
||
• Must not:
|
||
• call APIs
|
||
• read storage
|
||
• perform decisions
|
||
|
||
⸻
|
||
|
||
5. API Client (Frontend)
|
||
|
||
The API Client is a thin HTTP layer.
|
||
|
||
Rules
|
||
• Sends HTTP requests
|
||
• Returns API DTOs only
|
||
• Must not:
|
||
• return View Models
|
||
• contain business logic
|
||
• format data for UI
|
||
|
||
⸻
|
||
|
||
6. Website Services (Orchestration)
|
||
|
||
Website Services orchestrate:
|
||
• API Client calls
|
||
• Website Presenter mappings
|
||
|
||
They are the only layer allowed to touch both.
|
||
|
||
Rules
|
||
• Services:
|
||
• call API Client
|
||
• call Website Presenters
|
||
• return View Models only
|
||
• Components never touch API Client or DTOs
|
||
|
||
⸻
|
||
|
||
7. Final Data Flow (Unambiguous)
|
||
|
||
Core Use Case
|
||
→ OutputPort.present(Result)
|
||
|
||
API Presenter (Adapter)
|
||
→ maps Result → ApiResponse
|
||
|
||
API Controller
|
||
→ returns ApiResponse (JSON)
|
||
|
||
Frontend API Client
|
||
→ returns ApiResponse DTO
|
||
|
||
Website Presenter
|
||
→ maps DTO → ViewModel
|
||
|
||
UI Component
|
||
→ consumes ViewModel
|
||
|
||
|
||
⸻
|
||
|
||
8. Terminology Rules (Strict)
|
||
|
||
Term Layer Meaning
|
||
OutputPort Core Use case output contract
|
||
Result Core Pure application result
|
||
Presenter (API) apps/api Maps Result → API Response
|
||
Response / ApiResponse apps/api HTTP transport shape
|
||
Presenter (Website) apps/website Maps DTO → ViewModel
|
||
ViewModel apps/website UI-ready state
|
||
|
||
No term is reused with a different meaning.
|
||
|
||
⸻
|
||
|
||
9. Non-Negotiable Rules
|
||
• Core has no DTOs
|
||
• Core has no View Models
|
||
• API has no View Models
|
||
• Frontend has no Core Results
|
||
• View Models exist only in the frontend
|
||
• Presenters mean different things per layer, but:
|
||
• Core = Output Port
|
||
• API = Adapter
|
||
• Website = Mapper
|
||
|
||
⸻
|
||
|
||
10. Final Merksatz
|
||
|
||
The Core emits results.
|
||
The API transports them.
|
||
The Frontend interprets them.
|
||
|
||
If a type tries to do more than one of these — it is incorrectly placed. |