diff --git a/.gitignore b/.gitignore index 2592865..218365d 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,4 @@ crashlytics-build.properties ~$*.xlsx Assets/GameMain/Configs/ResourceBuilder.xml /.dotnet +/openspec/changes/archive \ No newline at end of file diff --git a/docs/UI-5层架构设计规范.md b/docs/UI-5层架构设计规范.md index bc88819..eb0a2fa 100644 --- a/docs/UI-5层架构设计规范.md +++ b/docs/UI-5层架构设计规范.md @@ -1,86 +1,123 @@ -# UI 五层架构设计规范(RawData / Controller / View / Context / UseCase) +# UI 五层架构设计规范(UseCase / RawData / Controller / Context / View) -## 1. 适用范围 +## 1. 文档目标 -- 适用目录:`Assets/GameMain/Scripts/UI/*` -- 重点对象:采用五层拆分的 UI 模块(`MenuScene`、`GameScene`、`General` 下的分层 UI) -- 本文不展开 Unity GameFramework 底层实现细节,仅约束项目内 UI 代码组织与协作方式 +本文定义一套可长期复用的 UI 分层设计方案,用于约束 UI 模块的职责边界、依赖方向、通信方式和测试策略。 -## 2. 架构总览 +- 本文描述的是规范,不是对某个项目现状的总结 +- 项目内目录或基类只作为落地示例,不改变本文的抽象约束 +- 本文重点约束 UIForm 级模块;子组件(`Item`、`Area` 等)可只实现 `Context + View` +- Unity GameFramework 的底层细节不在本文展开,本文只约束项目内 UI 代码组织 -UI 模块采用“输入数据 -> 业务编排 -> 展示数据 -> 渲染表现”的分层方式,核心链路如下: +## 2. 核心原则 -1. 外部流程(Procedure/GameState)创建并绑定 UseCase -2. 通过 `GameEntry.UIRouter` 打开指定 UI -3. Controller 从 UseCase 取 RawData,并转换为 Context -4. View 使用 Context 渲染 -5. View 通过事件回传交互,Controller 处理后驱动 UseCase 更新,再刷新 View +### 2.1 单向数据职责 -简化关系图: +UI 的职责链路固定为: ```text -Procedure/GameState - -> UIRouter - -> Controller <-> UseCase - -> Context -> View -View --(CustomEvent)--> Controller +外部流程 + -> Controller + -> UseCase + -> RawData / Result + -> BuildContext + -> View + +View + --(UI 专用事件)--> Controller ``` +说明: + +- `UseCase` 只负责业务规则、状态推进和纯业务数据生成 +- `Controller` 是 UI 编排中心,也是唯一允许构建 `Context` 的层 +- `View` 只负责渲染和抛出交互,不直接处理业务状态 + +### 2.2 严格分离业务数据与展示数据 + +- `RawData` 是纯业务数据,不承载展示模型 +- `Context` 是纯展示数据,不进入 `UseCase` +- `UseCase` 不能返回 `Context` +- `View` 只能消费 `Context` + +### 2.3 Controller 是 UI 唯一外部入口 + +对于 UIForm 级模块,外部流程只能通过 `Controller` 驱动 UI: + +- 打开 UI +- 关闭 UI +- 绑定 `UseCase` +- 刷新 UI +- 响应 UI 专用事件 + +`View` 不作为外部流程的直接依赖对象。 + ## 3. 五层职责定义 -### 3.1 RawData 层 +### 3.1 UseCase 层 -职责:承载“业务原始数据”,作为 UseCase 到 Controller 的传输模型。 - -约束: - -- 命名:`XXXFormRawData` -- 只描述数据,不包含 UI 渲染行为 -- 可保留领域对象或数据表对象(例如 `DRLevelUpReward`、`WeaponBase`) -- 不依赖具体 View 组件 - -参考: - -- `Assets/GameMain/Scripts/UI/GameScene/RawData/ShopFormRawData.cs` -- `Assets/GameMain/Scripts/UI/GameScene/RawData/LevelUpFormRawData.cs` -- `Assets/GameMain/Scripts/UI/MenuScene/RawData/SelectRoleFormRawData.cs` - -### 3.2 UseCase 层 - -职责:封装 UI 对应业务用例,负责业务规则、状态推进、数据生成。 +职责:封装 UI 对应的业务用例,负责业务规则、状态推进、校验和纯业务结果输出。 约束: - 实现 `IUIUseCase` - 命名:`XXXFormUseCase` -- 对外提供 `CreateInitialModel / TryRefresh / Select / Confirm` 等语义化方法 -- 返回 RawData(或结果对象),不直接操作具体 View +- 对外提供语义化方法,例如 `CreateInitialModel`、`TryRefresh`、`Select`、`Confirm` +- 返回值只能是 `RawData` 或纯业务结果对象,例如 `XXXResult`、`XXXActionResult` +- 不依赖 `Context`、`View`、`UGuiForm`、`MonoBehaviour` 等 UI 类型 +- 不负责 UI 资源加载、文本拼装、颜色选择、图标转换等展示处理 +- 不发布 UI 专用事件 -参考: +适用场景: -- `Assets/GameMain/Scripts/UI/GameScene/UseCase/ShopFormUseCase.cs` -- `Assets/GameMain/Scripts/UI/GameScene/UseCase/LevelUpFormUseCase.cs` -- `Assets/GameMain/Scripts/UI/MenuScene/UseCase/SelectRoleFormUseCase.cs` +- UI 会读写领域状态 +- UI 存在明确业务规则、条件分支、校验或状态推进 +- UI 的交互结果需要被测试和复用 -### 3.3 Controller 层 +### 3.2 RawData 层 -职责:UI 编排层,连接 UseCase 与 View,管理 UI 生命周期、事件订阅、数据转换。 +职责:承载 `UseCase -> Controller` 的纯业务传输模型。 约束: -- 继承 `UIFormControllerCommonBase` +- 命名:`XXXFormRawData` +- 只描述业务数据,不包含 UI 展示行为 +- 可以包含领域对象、配置对象、标识符、枚举、数值和纯数据集合 +- 不允许依赖 `Context`、`View`、`Sprite`、`TMP_Text` 等展示相关类型 +- 不允许直接使用 `XXXItemContext`、`XXXFormContext` 作为字段类型 + +说明: + +- `RawData` 的目标是表达“业务上发生了什么” +- `Context` 的目标是表达“界面应该怎么显示” +- 两者不能混用 + +### 3.3 Controller 层 + +职责:UI 编排层,负责连接外部流程、`UseCase`、`View`,并统一管理 UI 生命周期与展示状态。 + +约束: + +- UIForm 级模块默认必须有 `Controller` - 命名:`XXXFormController` +- 可基于 `UIFormControllerCommonBase` 实现 - 通过 `BindUseCase(IUIUseCase)` 注入用例并做类型校验 -- `OpenUI(object userData = null)` 支持:`Context`、`RawData`、`null` -- 负责 RawData -> Context 的转换(常见 `BuildContext`) -- 在 `SubscribeCustomEvents / UnsubscribeCustomEvents` 成对管理事件 -- 可做局部刷新(避免整窗重建) +- `OpenUI(object userData = null)` 负责接受外部参数、准备数据并打开 UI +- 负责 `RawData / Result -> Context` 的转换,常见形式为 `BuildContext` +- 负责事件订阅与解除订阅,且必须成对出现 +- 负责全量刷新与局部刷新策略 +- 负责过滤 UI 专用事件的 `sender`,确保事件只作用于当前 UI 实例 -参考: +允许职责: -- `Assets/GameMain/Scripts/UI/GameScene/Controller/ShopFormController.cs` -- `Assets/GameMain/Scripts/UI/GameScene/Controller/LevelUpFormController.cs` -- `Assets/GameMain/Scripts/UI/MenuScene/Controller/SelectRoleFormController.cs` +- 将业务数据转换为展示友好的文本、图标、颜色、列表状态 +- 在必要时查询本地化、资源映射或展示适配逻辑 + +禁止职责: + +- 在 `Controller` 中堆叠大段领域业务规则 +- 绕过 `Context` 直接把业务对象塞给 `View` +- 直接修改其他 UI 的内部 `View` ### 3.4 Context 层 @@ -89,104 +126,224 @@ View --(CustomEvent)--> Controller 约束: - 继承 `UIContext` -- 命名:`XXXFormContext` 或 `XXXItemContext` -- 字段以展示友好为目标(标题、描述、图标、稀有度、列表等) -- 允许组合子 Context(例如列表区 + 条目) +- 命名:`XXXFormContext`、`XXXItemContext`、`XXXAreaContext` +- 只能由 `Controller` 构建和更新 +- 字段以展示友好为目标,例如标题、描述、图标、颜色、状态、列表、按钮文案 +- 允许组合子 `Context` +- 不进入 `UseCase` -参考: +说明: -- `Assets/GameMain/Scripts/UI/GameScene/Context/ShopFormContext.cs` -- `Assets/GameMain/Scripts/UI/GameScene/Context/DisplayListAreaContext.cs` -- `Assets/GameMain/Scripts/UI/MenuScene/Context/SelectRoleFormContext.cs` +- `Context` 可以包含展示层需要的最终数据 +- `Context` 可以是“已格式化”的显示数据 +- 但这些数据必须由 `Controller` 负责准备,而不是 `UseCase` ### 3.5 View 层 -职责:纯表现层,负责控件绑定、显示刷新、交互事件抛出。 +职责:纯表现层,负责控件绑定、渲染刷新、动画触发和交互事件抛出。 约束: - Form 类继承 `UGuiForm`,子组件通常继承 `MonoBehaviour` -- 命名:`XXXForm` / `XXXItem` / `XXXArea` +- 命名:`XXXForm`、`XXXItem`、`XXXArea` - 提供 `RefreshUI(Context)`、`OnInit(Context)`、`OnReset()` 等渲染入口 -- 用户交互通过 `GameEntry.Event.Fire(...)` 通知 Controller -- 不承载业务规则(计算、流程推进、数据筛选应在 UseCase) +- 只消费 `Context` +- 用户交互通过 UI 专用事件通知 `Controller` +- 不承载业务规则、流程推进、数据筛选和领域状态修改 +- 不订阅全局业务事件 -参考: +允许职责: -- `Assets/GameMain/Scripts/UI/GameScene/View/ShopForm.cs` -- `Assets/GameMain/Scripts/UI/GameScene/View/DisplayListArea.cs` -- `Assets/GameMain/Scripts/UI/MenuScene/View/SelectRoleForm.cs` +- 本地控件显隐 +- 动画播放 +- 一次性的纯视觉状态缓存 -## 4. 标准交互流程 +禁止职责: -### 4.1 初始化与绑定 +- 直接调用 `UseCase` +- 直接修改领域状态 +- 订阅或处理全局业务事件 +- 将自己作为业务逻辑的入口 -1. Procedure/GameState 创建 UseCase -2. 调用 `GameEntry.UIRouter.BindUIUseCase(UIFormType.X, useCase)` +## 4. UI 类型分级 -示例: +### 4.1 标准五层 UI -- `Assets/GameMain/Scripts/Procedure/Game/GameStateShop.cs` -- `Assets/GameMain/Scripts/Procedure/Game/GameStateLevelUp.cs` -- `Assets/GameMain/Scripts/Procedure/ProcedureStartMenu.cs` +组成:`UseCase + RawData + Controller + Context + View` -### 4.2 打开 UI +适用条件: -1. 调用 `GameEntry.UIRouter.OpenUI(UIFormType.X)` -2. Controller 从 UseCase 取 RawData(或接收外部 RawData/Context) -3. Controller 构建 Context 后打开/刷新 Form -4. View 在 `OnOpen` 中校验 Context 类型并执行 `RefreshUI` +- UI 需要读写领域状态 +- UI 存在明确业务规则或分支 +- UI 交互会改变游戏流程、角色状态、背包、战斗结果等业务对象 +- UI 行为需要被自动化测试覆盖 -### 4.3 用户交互到刷新 +默认规则: -1. View 触发事件(如购买、刷新、选择) -2. Controller 监听事件并调用 UseCase -3. UseCase 返回新数据或操作结果 -4. Controller 更新 Context 并刷新全部或局部 UI +- 新增业务型 UI,优先使用完整五层 -### 4.4 关闭 UI +### 4.2 轻量 UI -1. 调用 `GameEntry.UIRouter.CloseUI(UIFormType.X)` -2. Controller 解除事件订阅并关闭窗体 -3. View `OnClose` 清理本地状态 +组成:`Controller + Context + View` -## 5. 目录与命名规范 +说明: -- 目录:`UI//RawData|UseCase|Controller|Context|View` -- 五层同名前缀保持一致:`ShopForm*`、`LevelUpForm*`、`SelectRoleForm*` -- 子组件上下文命名:`RoleItemContext`、`DisplayItemContext`、`LevelUpRewardItemContext` -- 新增 UI Form 时优先建立完整五层;仅纯静态展示可降级为 View-only +- `UseCase` 对轻量 UI 不强制 +- `RawData` 也不是强制层,可按需要补充 +- 轻量 UI 仍然必须通过 `Controller` 驱动,不能让 `View` 直接承担外部入口 -## 6. 依赖方向约束 +适用条件: + +- 只承担展示、导航、确认、提示等轻量职责 +- 没有独立的业务规则或状态推进 +- 只需要把已有参数转换成界面展示 + +升级规则: + +- 一旦轻量 UI 开始承载业务规则、校验或状态推进,应升级为标准五层 UI + +## 5. 依赖方向约束 允许依赖: -- `UseCase -> RawData / 领域对象` -- `Controller -> UseCase + RawData + Context + View + Event` -- `View -> Context + Event` +- `UseCase -> 领域对象 / 纯业务服务 / RawData / Result` +- `Controller -> UseCase + RawData + Result + Context + View + UI 专用事件` +- `Context -> 子 Context / 纯展示值对象` +- `View -> Context + UI 专用事件` 禁止依赖: +- `UseCase -> Context / View / Unity 具体展示组件` +- `RawData / Result -> Context / View` +- `Context -> View / UseCase` - `View -> UseCase` +- `View -> 全局业务事件` - `View -> 领域状态修改` -- `Context/RawData -> View` -## 7. 新增一个五层 UI 的落地步骤 +## 6. 事件通信规范 -1. 在目标场景目录创建 `RawData / UseCase / Context / Controller / View` 对应类型 -2. 在 UseCase 中实现模型创建与交互方法 -3. 在 Controller 中实现 `BindUseCase`、`OpenUI`、`BuildContext`、事件订阅 -4. 在 View 中实现 `RefreshUI` 和交互事件抛出 -5. 在对应 Procedure/GameState 里完成 UseCase 绑定与 Open/Close 调用 -6. 自测三条主链路:首次打开、交互刷新、关闭重开 +### 6.1 UI 与 Controller 的通信方式 -## 8. 项目当前实践说明 +`View` 与 `Controller` 的通信通过当前 UI 模块专用事件完成。 -- `ShopForm`、`LevelUpForm`、`SelectRoleForm` 是当前五层模式的主要样板 -- `DialogForm` 也有 Controller/Context/RawData,但 UseCase 为可选 -- `HudForm`、`StartMenuForm` 当前为轻用例场景,可不强制 UseCase -- `SettingForm`、`AboutForm` 属于历史直连型 UI,不属于五层完整样板 +约束: ---- +- UI 专用事件只服务于当前 UI 模块 +- 这些事件不是业务公共事件 +- 业务模块、流程模块、领域模块不应复用这些事件 +- 如果底层使用全局事件总线实现,也只能把它当作“传输通道”,不能把事件语义扩散成全局契约 -如后续需要统一重构,建议优先把历史直连型 UI(如 `SettingForm`)迁移到五层模板,以降低 UI 逻辑耦合度。 +### 6.2 事件边界 + +- `View -> Controller`:使用 UI 专用事件 +- `Controller -> View`:通过刷新 `Context` 或调用 `View` 的渲染接口 +- `Controller -> UseCase`:直接方法调用 +- `UseCase -> Controller`:通过返回 `RawData / Result`,不通过 UI 事件反推界面 + +### 6.3 事件安全要求 + +- `Controller` 必须校验事件 `sender` +- 同类 UI 可同时存在时,事件必须只作用于当前窗体实例 +- UI 专用事件命名应体现模块归属,避免语义过宽 + +## 7. 标准交互流程 + +### 7.1 有 UseCase 的标准流程 + +```text +Procedure / GameState + -> 创建 UseCase + -> BindUseCase + -> OpenUI + +Controller + -> UseCase.CreateInitialModel() + -> BuildContext(rawData) + -> View.RefreshUI(context) + +View + --(UI 专用事件)--> Controller + +Controller + -> UseCase.Action(...) + -> Result / RawData + -> BuildContext / PartialRefresh + -> View.RefreshUI(...) +``` + +### 7.2 无 UseCase 的轻量流程 + +```text +外部流程 + -> OpenUI(userData) + +Controller + -> BuildContext(userData) + -> View.RefreshUI(context) + +View + --(UI 专用事件)--> Controller + +Controller + -> 处理轻量逻辑或路由动作 + -> 更新 Context / 打开其他 UI / 关闭当前 UI +``` + +### 7.3 关闭流程 + +1. 外部流程或 `Controller` 调用关闭逻辑 +2. `Controller` 解除事件订阅 +3. `View.OnClose` 清理本地视觉状态 +4. 下次打开时重新按 `Context` 初始化 + +## 8. 目录与命名规范 + +目录示例以 `Assets/GameMain/Scripts/UI` 为例。 + +- 目录:`UI//UseCase|RawData|Controller|Context|View` +- 五层同名前缀保持一致,例如 `ShopForm*`、`LevelUpForm*` +- 子组件上下文命名:`RoleItemContext`、`RewardItemContext`、`DisplayAreaContext` +- 结果对象命名:`XXXResult`、`XXXActionResult` +- 轻量 UI 可以省略 `UseCase` 和 `RawData` 目录,但不省略 `Controller`、`Context`、`View` + +## 9. 测试规范 + +### 9.1 自动化测试范围 + +如果一个 UI 具备 `UseCase`,并且需要补自动化测试,则统一使用 EditMode 测试。 + +优先覆盖: + +- 初始化模型生成 +- 业务分支与校验 +- 用户动作对应的结果对象 +- 边界条件和非法输入 + +### 9.2 Controller / View 的验证策略 + +`Controller` 和 `View` 以人工验收为主,重点验证: + +- 首次打开 +- 交互刷新 +- 局部刷新 +- 关闭重开 +- 非法参数或空数据输入时的表现 + +## 10. 落地检查清单 + +新增 UI 时,至少检查以下事项: + +1. 先判断该 UI 属于标准五层还是轻量 UI +2. 如果存在业务规则或状态推进,必须引入 `UseCase` +3. `RawData` 中不得出现 `Context` 类型 +4. `Context` 只能在 `Controller` 中构建 +5. `View` 不得订阅全局业务事件 +6. `View` 的交互只能通过 UI 专用事件上报 +7. `Controller` 必须成对管理事件订阅与解除订阅 +8. 有 `UseCase` 且需要补自动化测试时,测试写入 EditMode + +## 11. 非目标说明 + +- 本文不讨论历史实现,也不为历史写法背书 +- 本文不要求所有 UI 必须强制引入 `UseCase` +- 本文不展开底层 UI 框架或事件系统实现细节 diff --git a/skills/ui-five-layer-architecture/SKILL.md b/skills/ui-five-layer-architecture/SKILL.md new file mode 100644 index 0000000..4b898d0 --- /dev/null +++ b/skills/ui-five-layer-architecture/SKILL.md @@ -0,0 +1,81 @@ +--- +name: ui-five-layer-architecture +description: Define, review, and refactor UI modules using a strict five-layer architecture (UseCase, RawData, Controller, Context, View). Use when creating cross-project UI architecture standards, designing new UI modules, reviewing layer boundaries and event flow, converting ad-hoc UI code into layered structure, or validating UI test strategy for business-driven interfaces. +--- + +# UI Five-Layer Architecture + +## Quick Start + +1. Read `./references/ui-five-layer-standard.md`. +2. Classify the UI as `standard-five-layer` or `lightweight`. +3. Apply boundary rules before editing code or writing design output. +4. Use the checklists in this file to drive design, review, or refactor tasks. + +## Workflow + +### 1. Scope the task + +Decide which mode the user needs: + +- architecture-spec mode: create or revise a UI architecture standard +- design mode: design one or more UI modules before coding +- implementation mode: implement or refactor code to match the standard +- review mode: audit existing code for boundary or dependency violations + +### 2. Choose module level + +Use `standard-five-layer` when UI owns business state transitions, validations, or branching behavior. + +Use `lightweight` when UI only handles display/navigation and has no independent business rules. + +### 3. Enforce non-negotiable boundaries + +Apply these constraints in every mode: + +- keep `UseCase` business-only and return only `RawData/Result` +- build `Context` only inside `Controller` +- keep `View` presentation-only and event-emitting only +- keep `View` out of global business event subscriptions +- route external UI open/close/refresh through `Controller` + +### 4. Apply communication and dependency checks + +Validate: + +- dependency direction is valid for all touched files +- UI-specific events stay UI-local in meaning +- `Controller` filters sender and instance scope when needed +- no `RawData` field uses `*Context` types + +### 5. Produce mode-specific output + +- architecture-spec mode: + - output the final standard text + - include strict rules, permitted exceptions, and checklists +- design mode: + - output layer map and flow diagram for each UI module + - include type list and event list +- implementation mode: + - implement code changes matching the standard + - update tests if `UseCase` behavior changes +- review mode: + - report findings first, ordered by severity + - include concrete file and line references + +## Architecture Checklist + +Use this list before closing any task: + +1. Classify each UI module correctly: `standard-five-layer` or `lightweight`. +2. Ensure `UseCase` does not construct `Context` or touch view concerns. +3. Ensure `RawData` does not include `*Context` or presentation types. +4. Ensure `Controller` owns all `RawData/Result -> Context` transformation. +5. Ensure `View` only consumes `Context` and emits UI-local events. +6. Ensure external open/close/update operations enter through `Controller`. +7. Ensure event ownership and sender filtering are explicit. +8. Ensure test approach matches policy in the reference file. + +## References + +Read `./references/ui-five-layer-standard.md` for the full specification. diff --git a/skills/ui-five-layer-architecture/agents/openai.yaml b/skills/ui-five-layer-architecture/agents/openai.yaml new file mode 100644 index 0000000..d92a807 --- /dev/null +++ b/skills/ui-five-layer-architecture/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "UI Five-Layer Architecture" + short_description: "Cross-project UI five-layer architecture standards" + default_prompt: "Use $ui-five-layer-architecture to define, review, or refactor a UI module with clear five-layer boundaries." diff --git a/skills/ui-five-layer-architecture/references/ui-five-layer-standard.md b/skills/ui-five-layer-architecture/references/ui-five-layer-standard.md new file mode 100644 index 0000000..6a60f41 --- /dev/null +++ b/skills/ui-five-layer-architecture/references/ui-five-layer-standard.md @@ -0,0 +1,274 @@ +# 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