Merge branch 'GPU-Instancing' of http://106.12.111.150:4000/basil/vampire-like into GPU-Instancing
This commit is contained in:
commit
56f74eee9a
|
|
@ -91,3 +91,4 @@ Assets/GameMain/Configs/ResourceBuilder.xml
|
|||
/.dotnet
|
||||
/.omx
|
||||
/.vscode
|
||||
/openspec/changes/archive
|
||||
|
|
@ -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<TContext, TForm>`
|
||||
- 命名:`XXXFormRawData`
|
||||
- 只描述业务数据,不包含 UI 展示行为
|
||||
- 可以包含领域对象、配置对象、标识符、枚举、数值和纯数据集合
|
||||
- 不允许依赖 `Context`、`View`、`Sprite`、`TMP_Text` 等展示相关类型
|
||||
- 不允许直接使用 `XXXItemContext`、`XXXFormContext` 作为字段类型
|
||||
|
||||
说明:
|
||||
|
||||
- `RawData` 的目标是表达“业务上发生了什么”
|
||||
- `Context` 的目标是表达“界面应该怎么显示”
|
||||
- 两者不能混用
|
||||
|
||||
### 3.3 Controller 层
|
||||
|
||||
职责:UI 编排层,负责连接外部流程、`UseCase`、`View`,并统一管理 UI 生命周期与展示状态。
|
||||
|
||||
约束:
|
||||
|
||||
- UIForm 级模块默认必须有 `Controller`
|
||||
- 命名:`XXXFormController`
|
||||
- 可基于 `UIFormControllerCommonBase<TContext, TForm>` 实现
|
||||
- 通过 `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/<SceneDomain>/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/<SceneDomain>/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 框架或事件系统实现细节
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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."
|
||||
|
|
@ -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/<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
|
||||
Loading…
Reference in New Issue