275 lines
5.8 KiB
Markdown
275 lines
5.8 KiB
Markdown
# 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/<Domain>/UseCase`
|
|
- `UI/<Domain>/RawData`
|
|
- `UI/<Domain>/Controller`
|
|
- `UI/<Domain>/Context`
|
|
- `UI/<Domain>/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
|