Files
gridpilot.gg/docs/architecture/DATA_FLOW.md
2025-12-19 11:32:16 +01:00

4.3 KiB
Raw Blame History

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.

  1. 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

  1. 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

  1. 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

  1. 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

  1. 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

  1. 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

  1. 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.

  1. 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

  1. 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.