# UI Five-Layer Architecture Standard ## Table of Contents 1. [Scope and Intent](#scope-and-intent) 2. [Core Model](#core-model) 3. [Layer Definitions](#layer-definitions) 4. [UI Module Levels](#ui-module-levels) 5. [Dependency Rules](#dependency-rules) 6. [Event Communication Rules](#event-communication-rules) 7. [Interaction Flow](#interaction-flow) 8. [Naming and Folder Conventions](#naming-and-folder-conventions) 9. [Testing Policy](#testing-policy) 10. [Anti-Patterns](#anti-patterns) 11. [Delivery Checklist](#delivery-checklist) ## Scope and Intent Use this standard to define and enforce a stable UI architecture that can be reused across projects. Primary goals: - keep business logic independent from UI rendering - keep UI rendering deterministic and testable - make reviews and refactors consistent - reduce coupling and regression risk ## Core Model Base chain: ```text External Flow -> Controller -> UseCase -> RawData / Result -> BuildContext -> View View --(UI-local event)--> Controller ``` Rules: - `UseCase` produces business outputs only. - `Controller` is the only layer that creates `Context`. - `View` only renders and emits interaction events. ## Layer Definitions ### UseCase Responsibilities: - own business rules and state transitions - validate business actions - return `RawData` or result objects Constraints: - do not depend on `Context`, `View`, or rendering types - do not format display strings or map visual assets - do not publish UI-local events ### RawData Responsibilities: - carry business data from `UseCase` to `Controller` Constraints: - keep data business-oriented - do not reference any `*Context` type - do not contain rendering objects (for example UI components) ### Controller Responsibilities: - be the external entry point for open/close/refresh - bind and call `UseCase` - transform `RawData/Result` into `Context` - subscribe/unsubscribe UI-local events - coordinate full or partial refresh Constraints: - do not let `View` bypass controller orchestration - do not hide heavy business logic that belongs in `UseCase` ### Context Responsibilities: - carry display-ready data for rendering Constraints: - construct/update only in `Controller` - do not enter `UseCase` - allow composition (`FormContext`, `ItemContext`, `AreaContext`) ### View Responsibilities: - bind controls and render `Context` - emit UI-local interaction events Constraints: - do not call `UseCase` - do not mutate domain state - do not subscribe to global business events - do not become external entry points ## UI Module Levels ### Standard Five-Layer Module Structure: - `UseCase + RawData + Controller + Context + View` Use when: - module owns business rules, validations, or branching state transitions - user actions mutate domain state - behavior requires automated verification ### Lightweight Module Structure: - `Controller + Context + View` Use when: - module is display/navigation/confirmation only - no independent business rules are present Rule: - upgrade to standard five-layer as soon as business rules appear ## Dependency Rules Allowed: - `UseCase -> domain/services/RawData/Result` - `Controller -> UseCase/RawData/Result/Context/View/UI-local events` - `Context -> child context/value objects` - `View -> Context/UI-local events` Forbidden: - `UseCase -> Context/View/rendering types` - `RawData/Result -> Context/View` - `Context -> UseCase/View` - `View -> UseCase` - `View -> global business events` - `View -> domain state mutation` ## Event Communication Rules ### Event Ownership - `View -> Controller` uses UI-local events only - UI-local events are not global business contracts - business/domain modules must not consume UI-local event semantics ### Safety Requirements - validate sender ownership in `Controller` - scope handling to the active UI instance - keep subscribe/unsubscribe symmetric ## Interaction Flow ### Standard Module ```text External Flow -> create/bind UseCase -> open UI via Controller Controller -> UseCase action -> RawData/Result -> BuildContext -> View refresh View --(UI-local event)--> Controller ``` ### Lightweight Module ```text External Flow -> open UI via Controller(userData) Controller -> BuildContext(userData) -> View refresh View --(UI-local event)--> Controller ``` ## Naming and Folder Conventions Recommended folders: - `UI//UseCase` - `UI//RawData` - `UI//Controller` - `UI//Context` - `UI//View` Recommended naming: - `XXXFormUseCase` - `XXXFormRawData` - `XXXFormController` - `XXXFormContext`, `XXXItemContext`, `XXXAreaContext` - `XXXResult`, `XXXActionResult` ## Testing Policy Policy: - if a UI has a `UseCase` and automated tests are added, use EditMode tests for the `UseCase` Priority coverage: - initial model generation - business branch and validation behavior - action result correctness - boundary and invalid input handling Manual verification focus: - first open - interaction refresh - partial refresh - close and reopen - null/invalid userData behavior ## Anti-Patterns Do not allow: - `UseCase` returning `Context` - `RawData` carrying `*Context` - `View` subscribing global business events - direct domain mutation inside `View` - skipping `Controller` as module entry - module marked lightweight while carrying business state transitions ## Delivery Checklist Use this checklist before marking work complete: 1. classify each module as standard or lightweight 2. verify business rules sit in `UseCase` only 3. verify `Context` is built only in `Controller` 4. verify `RawData` has no presentation model leakage 5. verify `View` is render-and-emit only 6. verify UI-local events are scoped and sender-checked 7. verify dependency direction constraints pass 8. verify tests/manual checks match the testing policy