Merge branch 'GPU-Instancing' of http://106.12.111.150:4000/basil/vampire-like into GPU-Instancing

This commit is contained in:
SepComet 2026-05-10 16:33:15 +08:00
commit 56f74eee9a
5 changed files with 632 additions and 115 deletions

1
.gitignore vendored
View File

@ -91,3 +91,4 @@ Assets/GameMain/Configs/ResourceBuilder.xml
/.dotnet
/.omx
/.vscode
/openspec/changes/archive

View File

@ -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 框架或事件系统实现细节

View File

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

View File

@ -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."

View File

@ -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