7.9 KiB
7.9 KiB
阶段 ④ UI Spec — UI 规则定义与约束规范
定义:定义每个交付面的 UI 行为与视觉约束,让 UI 实现者(人或 agent)不发明任何决策:页面骨架、组件粒度、状态机、动作权限由表面规格(Surface Specification) 规定;颜色/字号/间距/组件形态由设计系统契约(DESIGN.md) 规定。 输入:① 规格 §3(Surface Specification)+ ②/③ 的接口契约(UI 消费的字段)。 输出:表面规格 + DESIGN.md(含 token)+ i18n 约束。 进入下一阶段(⑤ 实现):状态机、动作权限、设计 token、i18n 全部定案。
适用判定:本阶段仅当改动拥有用户可见 UI(web 界面、Electron 窗口、设置面板、硬件设备界面)时强制;纯后端/网关/CLI 改动标记
not applicable。
1. 要求(Requirements)
1.1 进入条件
- 规格 §3 已定义交付面清单与每个面的消费字段(字段有类型、可空性、枚举值)。
- 项目已有或需要建立视觉事实源(
DESIGN.md/ 主题变量 / 组件库)。
1.2 完成条件(DoD)
- 每个交付面有:页面骨架 + 组件粒度边界 + 完整状态机 + 动作×权限表
- 每个 UI 提交/展示的字段能在规格 §2 找到(契约门)
- 视觉 token(颜色/字号/间距/圆角/组件)有语义化来源,不出现临时发明的
blue500类裸色 - 全部 UI 文案走 i18n(本仓:
packages/web-ui/src/i18n/messages.ts,zh-CN/en-US 双语),无硬编码用户可见字符串 - 可访问性约束写明:对比度(WCAG AA)、focus-visible、颜色不单独承载状态、reduced-motion
- 异常态(加载/空/错误/禁用/提交中)有明确视觉与文案定义(对应规格
E-*)
2. 规则(Rules)
2.1 表面规格规则(Surface Specification)
| 编号 | 规则 |
|---|---|
| R-4.1 | 骨架先行:每个交付面先定页面骨架(区域划分),再定组件,禁止直接进入像素级布局。 |
| R-4.2 | 组件粒度即所有权边界:明确"哪个组件拥有哪个状态"(如筛选条是查询条件的唯一事实源、表格不持有选择集)。组件不得越界:表格不能清空选择,只能向拥有者发请求。 |
| R-4.3 | 状态机完整:Idle/Loading/Ready/Empty/Error/Submitting 等状态全列;Loading(骨架屏)与 Submitting(保留现有内容+禁用交互)是不同状态,不得合并。 |
| R-4.4 | 动作×权限表:每个动作列角色与禁用条件(如"Auditor 看到页面但没有动作控件,而非禁用按钮")。 |
| R-4.5 | 交互约束显式:URL 持有可分享状态、筛选变更清空选择、选择集不跨页、破坏性操作需确认且写明数量——写成条目,不留给实现。 |
| R-4.6 | 截图不是 spec:图片可表达布局,但必须同时有规则、状态转换、权限(R-1.7 在 UI 层同样生效)。 |
2.2 设计系统规则(DESIGN.md / 视觉 token)
| 编号 | 规则 |
|---|---|
| R-4.7 | 视觉事实源唯一:有 UI 的项目维护唯一的视觉 token 事实源(本仓现状:packages/web-ui/src/theme/tokens.css,语义 token + CSS 变量,经 styles.css @import 消费;若将来建根级 DESIGN.md 则与之对齐);禁止在组件里临时发明颜色/间距/字号。 |
| R-4.8 | 语义 token 优先:token 用语义角色(primary/surface/danger),不用调色板名(teal-500);组件 token 带状态(如 button-primary-hover、text-input-focused)。 |
| R-4.9 | token 可导出可防漂移:token 能导出为 CSS 变量/主题,并用 lint/diff/单测检查漂移(本仓:tokens.css 变量 + styles.test.ts 等单测守卫;useAppearance.ts 归一化主题 id);"文件存在"不等于"被使用"(G-3)。 |
| R-4.10 | 可访问性硬约束:正文与 focus 态满足 WCAG AA 对比度;错误/成功/选中状态不得只靠颜色表达;支持 reduced-motion;表单与错误态有明确指引。 |
| R-4.11 | 不强推框架外规范:后端/CLI/纯数据项目标记 not applicable,不套用视觉契约。 |
2.3 i18n 规则
| 编号 | 规则 |
|---|---|
| R-4.12 | 所有用户可见文案走 key 化翻译(本仓:packages/web-ui/src/i18n/messages.ts,扁平 key + t(key, params?),key 按命名空间组织:common.*/task.*/settings.*/shell.*/inspector.*/mode.*);禁止硬编码中文/英文串。 |
| R-4.13 | 多语言文案与 UI 状态同步维护;新增文案必须同时补齐既有语言包。 |
| R-4.14 | 设备端/子窗口界面不做 i18n 决策,文案由宿主统一注入(避免每窗口维护语言状态)。 |
3. 输出规范
3.1 表面规格结构(每个交付面一份)
Skeleton 页面骨架:区域划分与信息层级
Component 组件粒度:组件清单 + 各自拥有的状态 + 不允许越界的边界
Granularity
State Machine 状态全集 + 合法转换 + 每个状态的禁用手势(表格或图)
Actions & Guards 动作 × 角色 × 禁用条件(含"只读角色无控件而非禁用")
Interaction 交互约束:URL 状态、选择集规则、确认对话框、虚拟化/固定行高、截断策略
Constraints
模板参考:
vendor/better-harness/references/bootstrap/examples/frontend-web-spec.md的 §3(复用结构,内容必须基于本仓事实)。
3.2 DESIGN.md 结构
frontmatter(机器可读) colors / typography / rounded / spacing / components
(顶层组,语义角色 + 组件状态 token,支持 {colors.primary} 引用)
Markdown(人读) Overview / Colors / Typography / Layout / Elevation & Depth /
Shapes / Components / Do's and Don'ts
+ 可访问性(对比度、focus-visible、color-not-alone、reduced-motion)
+ 每个 token 的"何时用 / 何时不用 / 防止什么 agent 错误"
完整示例:
vendor/better-harness/case-studies/project-harness/design-md-complete-example.md(结构性回退模板,数值必须替换为本仓已核实的来源)。若项目尚无 DESIGN.md:从现有代码/主题推断并标注"推断",未决品牌决策标记needs-design-decision,禁止编造。
3.3 交付物清单
- 每个交付面的表面规格
DESIGN.md(若建)或其缺失项清单;本仓现状:视觉 token 事实源为packages/web-ui/src/theme/tokens.css(含证据分级:Present / Structured / Token-ready / Agent-ready / Aligned / Backstopped)- i18n key 清单(新增/变更)
- UI 验收映射:表面规格的每条交互约束 ↔ 规格
AC-xx↔ 06-validation.md 的测试点(组件/E2E)
4. UI 验证约束(预置,详见阶段 ⑥)
- UI 验证分驱动平面(D0 进程内渲染树 → D1 浏览器自动化协议 → D2 附加运行中浏览器 → D3 OS 输入/无障碍 → D4 物理设备),选满足声明的最便宜平面,失败再升级。
- 驱动与观察分离:同一模型既驱动 UI 又目测自己的截图 = 无独立裁判,不能算 pass(
Self-reported success反模式)。截图基线只追加不覆盖。 - 定位器禁止跨动作缓存(元素索引/坐标每次交互前重新读取);降级顺序:语义选择器 → 文本/aria → 原始坐标,并记录最终落到哪一级。
5. 轻量路径(小改动)
- 单组件样式调整:更新 DESIGN.md 对应 token + 表面规格的组件小节,不重写整份规格。
- 触碰多交付面、状态机重构、主题切换:必须完整走本阶段。
6. 相关文档
- 输入:阶段 ① 01-requirement.md §3、阶段 ③ 03-detailed-design.md
- 验证:阶段 ⑥ 06-validation.md(UI 驱动平面与裁判分离约束)