@yss123/cage-cli 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +1 -1
  2. package/dist/analyze.js +3 -0
  3. package/dist/analyze.js.map +1 -1
  4. package/dist/capabilities.js +10 -0
  5. package/dist/capabilities.js.map +1 -1
  6. package/dist/config.d.ts +4 -0
  7. package/dist/config.js.map +1 -1
  8. package/dist/context.js +2 -2
  9. package/dist/context.js.map +1 -1
  10. package/dist/doctor.js +1 -1
  11. package/dist/doctor.js.map +1 -1
  12. package/dist/findings.d.ts +1 -1
  13. package/dist/findings.js +2 -2
  14. package/dist/findings.js.map +1 -1
  15. package/dist/graph-business.d.ts +11 -8
  16. package/dist/graph-business.js +16 -16
  17. package/dist/graph-business.js.map +1 -1
  18. package/dist/graph-relations.js +3 -5
  19. package/dist/graph-relations.js.map +1 -1
  20. package/dist/impact.js +1 -4
  21. package/dist/impact.js.map +1 -1
  22. package/dist/ontology-names.d.ts +17 -0
  23. package/dist/ontology-names.js +42 -0
  24. package/dist/ontology-names.js.map +1 -0
  25. package/dist/sync.d.ts +5 -1
  26. package/dist/sync.js +16 -9
  27. package/dist/sync.js.map +1 -1
  28. package/graph-ui/app.js +3 -2
  29. package/graph-ui/business.js +11 -3
  30. package/graph-ui/graph-business.js +16 -16
  31. package/graph-ui/graph-relations.js +3 -5
  32. package/package.json +6 -6
  33. package/templates/app/.agents/skills/cage-development/SKILL.md +1 -1
  34. package/templates/app/AGENTS.md +12 -9
  35. package/templates/app/README.md +2 -2
  36. package/templates/app/apps/api/package.json +2 -2
  37. package/templates/app/apps/web/package.json +3 -1
  38. package/templates/app/apps/web/src/app/styles/global.css +12 -11
  39. package/templates/app/apps/web/src/main.tsx +18 -7
  40. package/templates/app/apps/web/src/shared/lib/error-message.ts +1 -1
  41. package/templates/app/apps/web/src/shared/ui/approval-member-picker.tsx +1 -1
  42. package/templates/app/cage.config.json +2 -1
  43. package/templates/app/docs/README.md +6 -4
  44. package/templates/app/docs/development/README.md +21 -5
  45. package/templates/app/docs/development/examples/note/note.ts +8 -4
  46. package/templates/app/docs/development/examples/purchase-example.md +5 -5
  47. package/templates/app/docs/development/getting-started/architecture.md +5 -5
  48. package/templates/app/docs/development/getting-started/workflow.md +17 -23
  49. package/templates/app/docs/development/guides/approvals.md +4 -4
  50. package/templates/app/docs/development/guides/business-collaboration.md +3 -1
  51. package/templates/app/docs/development/guides/frontend-ui.md +30 -0
  52. package/templates/app/docs/development/guides/intelligence.md +14 -12
  53. package/templates/app/docs/development/guides/ontology-modeling.md +83 -0
  54. package/templates/app/docs/development/guides/recipes.md +28 -14
  55. package/templates/app/docs/development/guides/relations.md +31 -8
  56. package/templates/app/docs/development/reference/commenting.md +7 -4
  57. package/templates/app/docs/development/reference/primitives.md +5 -3
  58. package/templates/app/docs/development/skills/cage-development/SKILL.md +30 -20
  59. package/templates/app/docs/development/tools/diagnostics.md +4 -1
  60. package/templates/app/docs/development/tools/ontology-context.md +1 -1
  61. package/templates/app/docs/development/tools/troubleshooting.md +3 -3
  62. package/templates/app/docs/errors/CAGE-APPR-007.md +1 -1
  63. package/templates/app/docs/errors/CAGE-GRANT-001.md +18 -12
  64. package/templates/app/docs/errors/CAGE-GRANT-002.md +2 -2
  65. package/templates/app/docs/errors/CAGE-GRANT-003.md +3 -3
  66. package/templates/app/docs/errors/CAGE-ONTOLOGY-001.md +52 -0
  67. package/templates/app/docs/errors/CAGE-STATE-003.md +1 -1
  68. package/templates/app/docs/errors/CAGE-SYNC-001.md +2 -2
  69. package/templates/app/docs/errors/README.md +7 -1
  70. package/templates/app/docs/errors/runtime.md +1 -1
  71. package/templates/app/package.json +3 -3
  72. package/templates/app/packages/contracts/package.json +1 -1
  73. package/templates/app/packages/contracts/src/aggregates/role/index.ts +2 -2
  74. package/templates/app/packages/contracts/src/aggregates/user/index.ts +3 -3
  75. package/templates/app/packages/domain/package.json +5 -5
  76. package/templates/app/packages/domain/src/modules/purchase/approval-members.ts +1 -1
  77. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +2 -2
  78. package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +4 -4
  79. package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +10 -17
  80. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +4 -5
  81. package/templates/app/packages/domain/src/workflows/purchase-process.ts +1 -1
  82. package/templates/blank/.agents/skills/cage-development/SKILL.md +1 -1
  83. package/templates/blank/AGENTS.md +12 -9
  84. package/templates/blank/apps/api/package.json +1 -1
  85. package/templates/blank/apps/web/package.json +3 -1
  86. package/templates/blank/apps/web/src/app/styles/global.css +6 -5
  87. package/templates/blank/apps/web/src/main.tsx +18 -7
  88. package/templates/blank/cage.config.json +1 -0
  89. package/templates/blank/docs/README.md +6 -4
  90. package/templates/blank/docs/development/README.md +21 -5
  91. package/templates/blank/docs/development/examples/note/note.ts +8 -4
  92. package/templates/blank/docs/development/examples/purchase-example.md +5 -5
  93. package/templates/blank/docs/development/getting-started/architecture.md +5 -5
  94. package/templates/blank/docs/development/getting-started/workflow.md +17 -23
  95. package/templates/blank/docs/development/guides/approvals.md +4 -4
  96. package/templates/blank/docs/development/guides/business-collaboration.md +3 -1
  97. package/templates/blank/docs/development/guides/frontend-ui.md +30 -0
  98. package/templates/blank/docs/development/guides/intelligence.md +14 -12
  99. package/templates/blank/docs/development/guides/ontology-modeling.md +83 -0
  100. package/templates/blank/docs/development/guides/recipes.md +28 -14
  101. package/templates/blank/docs/development/guides/relations.md +31 -8
  102. package/templates/blank/docs/development/reference/commenting.md +7 -4
  103. package/templates/blank/docs/development/reference/primitives.md +5 -3
  104. package/templates/blank/docs/development/skills/cage-development/SKILL.md +30 -20
  105. package/templates/blank/docs/development/tools/diagnostics.md +4 -1
  106. package/templates/blank/docs/development/tools/ontology-context.md +1 -1
  107. package/templates/blank/docs/development/tools/troubleshooting.md +3 -3
  108. package/templates/blank/docs/errors/CAGE-APPR-007.md +1 -1
  109. package/templates/blank/docs/errors/CAGE-GRANT-001.md +18 -12
  110. package/templates/blank/docs/errors/CAGE-GRANT-002.md +2 -2
  111. package/templates/blank/docs/errors/CAGE-GRANT-003.md +3 -3
  112. package/templates/blank/docs/errors/CAGE-ONTOLOGY-001.md +52 -0
  113. package/templates/blank/docs/errors/CAGE-STATE-003.md +1 -1
  114. package/templates/blank/docs/errors/CAGE-SYNC-001.md +2 -2
  115. package/templates/blank/docs/errors/README.md +7 -1
  116. package/templates/blank/docs/errors/runtime.md +1 -1
  117. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +12 -11
  118. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +18 -7
  119. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +1 -1
  120. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/approval-member-picker.tsx +1 -1
  121. package/templates/blank/docs/examples/purchase-admin/cage.config.json +2 -1
  122. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +2 -2
  123. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +3 -3
  124. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approval-members.ts +1 -1
  125. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +2 -2
  126. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +4 -4
  127. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +10 -17
  128. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +4 -5
  129. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +1 -1
  130. package/templates/blank/package.json +3 -3
  131. package/templates/blank/packages/contracts/package.json +1 -1
  132. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +2 -2
  133. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +3 -3
  134. package/templates/blank/packages/domain/package.json +5 -5
@@ -0,0 +1,83 @@
1
+ # 把业务含义写进本体声明
2
+
3
+ [返回学习入口](../README.md) · [业务澄清](business-collaboration.md) · [能力选择](recipes.md) · [本体查询](../tools/ontology-context.md)
4
+
5
+ Cage 的本体来自实际注册的领域声明。对象是什么、状态表示什么、对象之间如何关联、操作后影响谁,都应落实到这些声明及其实现中。图谱用来检查和解释它们;不另建一份与运行代码分离的本体配置来代替领域设计。
6
+
7
+ 用户可以通过自然语言、业务文档、已有系统、表格或原型表达需求。原型只能提供其中一部分线索:页面上的“所属部门”可能是对象引用,也可能只是历史名称快照,必须结合业务含义判断。模板和参考例子提供框架用法,不能替用户决定对象、关系或流程。
8
+
9
+ ## 编码前,把相关业务说清楚
10
+
11
+ 新建或修改领域时,沿[Skill 的实现映射](../skills/cage-development/SKILL.md#4-写代码前说明实现映射),说明本次涉及的对象、关系、动作与结果。小改动用几句话即可;已有清楚的业务文档直接引用,不要求每次另建文档或让用户逐项填表。
12
+
13
+ | 要说清楚什么 | 应落实到哪里 | 如何核对 |
14
+ | --- | --- | --- |
15
+ | 对象代表什么,是否有独立身份和生命周期 | aggregate、fields、states、不变量 | 不按页面数建表,不把独立业务对象藏进任意 JSON |
16
+ | 谁属于谁,双方各能关联几个,关系可否为空 | ref、unique、optional、hasMany、manyToMany 或关系聚合 | 外键方向、基数、目标声明、mappedBy 和实际查询一致 |
17
+ | 状态表示什么,哪些操作允许进入或离开 | states 的 labels、terminal、command 的 from/to | 状态名称和允许操作符合用户规则,保留状态的操作用 to: null |
18
+ | 谁能执行,能作用于哪些记录 | 能力、scope、invokedBy、constraints | 页面隐藏按钮和审批选人不能代替服务端授权 |
19
+ | 操作完成后,其他对象或系统怎样变化 | emits、reaction、approval、job、connector 及执行代码 | 明确触发、输入映射、事务、失败和重试;读取依赖不等于自动联动 |
20
+ | 怎样才算业务完成 | 已确认规则及成功、失败例子 | 独立读取结果,验证关键反例,区分静态声明和实际执行 |
21
+
22
+ 涉及取舍时按[业务澄清](business-collaboration.md)提出疑点及选项。例如“一个员工是否允许同时有两个有效任职”“删除父对象后子记录如何处理”不能由字段名推断。已明确的规则直接采用,普通技术用法由 agent 查证。
23
+
24
+ ## 名称写在真实 API 中
25
+
26
+ 机器标识负责存储、能力点、路由和代码引用,业务名称负责让用户与 agent 理解它们。中文业务用中文名称,其他语言的应用用对应业务用语;不要为翻译而改已有状态值、表名或能力点。
27
+
28
+ | 内容 | 结构化填写位置 | 边界 |
29
+ | --- | --- | --- |
30
+ | 业务对象 | `aggregate('Note', { description: '部门便笺', ... })` | 说明对象含义;长篇规则仍由代码、JSDoc 和业务文档解释 |
31
+ | 字段及引用 | `text(120).describe('便笺标题')`、`ref('Dept').describe('所属部门')` | 描述不能代替 ref 关系、输入校验或 scope |
32
+ | 集合关系 | `.describe(...)` 或工厂选项 `description` | `hasMany` 仍需真实的 `mappedBy`,`manyToMany` 不会自动生成有业务状态的关系对象 |
33
+ | 每个状态 | `states(..., { labels: { active: '使用中', archived: '已归档' } })` | 每个状态都应有业务名;初态、终态和可达性单独声明/检查 |
34
+ | 业务操作 | `command(对象, { description: '归档便笺', ... })` | 用业务意图命名,实际条件由 from、constraints、handler 等落实 |
35
+ | 事件 | `event('NoteArchived', { ... }, { description: '便笺已归档' })` | 描述已发生的事实;没有下游需求时不必添加事件 |
36
+ | 查询、定时任务 | 各自选项中的 `description` | reads/calls、SQL 或 run 才表达实际依赖和处理 |
37
+ | 完整业务阅读流程 | `businessProcess` 的 `title/description`,阶段的 `title/description/actor` | action 和连接引用真实实现;阅读规格本身不会执行命令或补出缺失联动 |
38
+ | 板块、角色、无通用描述选项的协作节点、短标题覆盖 | `cage.config.json` 的 `graph.labels`,键为完整节点 key | 属于显示覆盖;不会修正错误关系,也不会自动成为其他界面的文案 |
39
+
40
+ 优先把名称与领域声明一起维护。已有项目可用 `graph.labels` 适配:`state:Note.archived`、`field:Note.deptId`、`command:Note.archive`。配置覆盖优先于声明文案;字段也能使用本体属性里的 description。不要为每个节点发明不存在的 `label` 或 `description` 选项,先用 `cage capabilities` 核对公开签名。
41
+
42
+ 普通源码注释和前端的 `statusLabel` 映射不会自动被抽取。仅在注释写“archived 表示已归档”,或者仅在页面翻译 archived,图谱仍缺少该状态的业务名。`graph.labels` 只作用于 CLI 图谱及上下文;页面文案与领域状态含义仍需核对一致,前端不得为读取文案导入 domain。
43
+
44
+ 完整可编译示例见[便笺领域声明](../examples/note/note.ts)。其中 active/archived 保持机器标识,labels 写“使用中/已归档”,字段和命令分别填写自己的业务名称。便笺不需要审批和事件,不为凑齐图谱节点而添加它们。
45
+
46
+ ## 对象关系要落到声明与执行
47
+
48
+ 参考[关系指南](relations.md)选择方向与保存方式。例如“每条评论属于一条便笺”:
49
+
50
+ - 评论上的 `noteId: ref('Note').describe('所属便笺')` 表达真正引用;普通 `id()`、`text()` 或命名为 noteId 的字段不会自动建立引用。
51
+ - 便笺上的 `hasMany('NoteComment', { mappedBy: 'noteId', description: '便笺评论' })` 只是反查。修改归属仍执行评论命令,不能写父对象的只读集合。
52
+ - 评论是否沿用便笺部门、便笺归档后能否评论,分别由评论命令的 reads、handler 和允许规则落实;ref 不会自动继承权限、状态或删除行为。
53
+
54
+ 跨对象动作也要有真实执行链。“批准后占用资源”应能找到命令发事件、反应接收、调用目标命令的完整声明,以及数据映射与事务选择。`reads` 箭头只证明读取,`from/to` 只证明允许的迁移,`invokedBy: 'process'` 只证明调用身份;它们都不能独自证明审批或自动执行。
55
+
56
+ 业务阅读确实跨多个对象时,可以声明 `businessProcess` 解释完整主线并引用真实实现;简单对象生命周期不必额外包一层流程。图谱看起来有连线不能代替实际业务用例。
57
+
58
+ ## 检查名称,再按业务验收
59
+
60
+ 在应用根目录执行:
61
+
62
+ ```sh
63
+ pnpm exec cage check
64
+ pnpm gen
65
+ pnpm exec cage graph
66
+ pnpm exec cage context "本次业务用语" --format json
67
+ ```
68
+
69
+ `CAGE-ONTOLOGY-001` 报告当前项目有源码位置的聚合、字段、状态、命令、事件、查询和任务缺少非空结构化名称。字段和状态的位置指向所属聚合,不是假装精确的成员行号。来自依赖包且没有本地声明位置的节点不在本检查范围;协作节点没有统一的 description API,也不纳入该完整性规则。
70
+
71
+ 旧配置默认产生警告;新脚手架启用以下门禁,也可在已有应用补齐名称后启用:
72
+
73
+ ```json
74
+ {
75
+ "graph": {
76
+ "naming": "required"
77
+ }
78
+ }
79
+ ```
80
+
81
+ 将 naming 合并进原有 graph 配置,保留 title 和 labels。required 让缺名阻止 check/gen/verify;图谱仍会展示可抽取的图及诊断,便于修复。默认警告并不表示业务文案已经完成,应在交付中说明仍缺什么。
82
+
83
+ 静态检查只能验证名称存在和框架可识别的结构,不能判断中文是否准确,也不能判断一条外键是否符合任意用户需求。检查后逐项返回编码前的规则:对象含义、关系方向与基数、状态迁移、触发链及权限是否一致?成功和关键失败例子是否得到预期结果?按这些证据报告完成程度,不把“命名门禁通过”当作“理解了业务”。
@@ -2,7 +2,7 @@
2
2
 
3
3
  [返回学习入口](../README.md) · [原语示例](../reference/primitives.md) · [开发步骤](../getting-started/workflow.md)
4
4
 
5
- 本页用于把用户的业务描述转成 Cage 项目的可执行修改。先通过[框架开发 Skill](../skills/cage-development/SKILL.md)理解执行模型,首次使用可沿[完整入门课](../getting-started/first-feature.md)学习。按需要读对应配方,不要求为每个任务加载所有能力。
5
+ 本页负责业务规则到 Cage 能力的设计映射;工作顺序由[框架开发 Skill](../skills/cage-development/SKILL.md)统一规定,具体命令见[开发步骤](../getting-started/workflow.md)。按需要读对应配方,不要求为每个任务加载所有能力。
6
6
 
7
7
  需要 AI 审批、业务助理、随页聊天、模型管理或性格配置时,先用 `cage capabilities` 查框架能力,再按[原生智能化指南](intelligence.md)接入。普通业务建模仍按下文声明聚合和命令;接入已有框架服务无需另建一套通用后端。
8
8
 
@@ -15,8 +15,8 @@
15
15
  | 管理什么对象?有哪些字段? | aggregate、字段与 Zod 输入 | 报销单:金额、事由、部门、提单人、明细 |
16
16
  | 有哪些阶段?谁能做什么? | states、command、invokedBy | 草稿可编辑、提交后审批、完成后不可撤回 |
17
17
  | 数据属于谁/哪个部门? | 范围字段 + 角色数据范围 | 申请人看本人,经理看部门及下级 |
18
- | 每次操作有什么硬规则? | constraints、invariants、fail | 提单人不可审批、额度上限、金额必须为正 |
19
- | 成功后还要发生什么? | event、reaction、approval、outbound | 启动审批、登记额度占用、推送财务系统 |
18
+ | 每次操作有什么硬规则? | constraints、invariants、fail | 提单人不可审批、金额必须为正 |
19
+ | 成功后还要发生什么? | event、reaction、approval、outbound | 启动审批、登记资源占用、推送财务系统 |
20
20
  | 取消/失败要撤销什么? | cancelOn、释放命令、补偿流程 | 取消待办、释放占用、远端撤销或人工补偿 |
21
21
  | 页面需要看什么? | 生成的 list/get、query、业务页面 | 分页、详情、按状态汇总、导出与导入 |
22
22
 
@@ -39,13 +39,29 @@
39
39
 
40
40
  角色是后台分配的数据,能力是被授权的动作,门户是界面组织方式。当前会话公开类型不应通过类型断言凭空添加 roles;若需求要展示实际角色列表,应查找当前允许的读取接口或明确所需接口缺口。多角色能力/范围按框架规则合并,前端切换菜单不会自动切换服务端执行身份。用不同真实主体验证权限,不能用固定姓名或公司名称模拟范围。
41
41
 
42
+ ## 写代码前的实现映射
43
+
44
+ 理解规则并核对能力后,把“规则 → 框架机制与证据 → 修改位置 → 验收”连接起来。按当前任务写一段说明或小表即可;这里是设计示例,不是要求复制的业务或固定计划文件。
45
+
46
+ 例如,用户已经明确:“已有部门通知增加归档;原有编辑者能归档;归档后保留记录、禁止修改;可见范围不变。”先查现有通知声明、编辑权限、页面及生成契约,再查[命令原语](../reference/primitives.md)。在这些证据一致的前提下,可以形成以下映射:
47
+
48
+ | 已确认规则 | 已查证的框架做法 | 受影响的位置 | 可观察的验收 |
49
+ | --- | --- | --- | --- |
50
+ | 通知可以归档并保留历史 | 在原聚合增加归档状态与命令,使用 `from/to` 表达转换;复用现有记录 | 原通知领域模块、导出、重新生成的契约与迁移草稿 | 授权主体归档后独立读取仍是同一记录,状态已改变 |
51
+ | 归档后禁止修改 | 核对所有相关修改命令的允许状态,让服务端拒绝归档状态的修改 | 原修改命令及必要的规则用例,页面按状态更新操作入口 | 直接请求修改归档记录被拒绝,刷新后内容仍未改变 |
52
+ | 原有编辑者能归档,可见范围不变 | 沿用原归属字段和读范围,明确新增归档能力由哪些现有角色获得;选人或隐藏按钮不代替授权 | 角色配置、命令能力、页面实际契约调用 | 原编辑者获得对应授权后成功;缺能力主体拒绝;范围外主体仍不能读取 |
53
+
54
+ 实际任务中把“原通知领域模块”等替换为查到的具体文件、声明和签名位置;生成前说明预期契约,生成后核对实际方法。迁移是否新增、需要哪些数据处理,以真实生成差异和已有数据为准。不要从这个例子推断所有项目都需要归档,也不要顺手加入恢复、删除或通知订阅。
55
+
56
+ 如果需求只说“加一个归档”,是否可恢复、谁能归档、归档后能否修改等应按对本次设计的影响提出;用户未要求恢复功能时可作为可选建议,不能擅自纳入实现。业务决定尚未取得时,映射中的相关行为保持待定,继续查证和推进独立部分。
57
+
42
58
  ## 新增一个普通管理对象
43
59
 
44
- 按[最小便笺业务](../reference/primitives.md)新增 `packages/domain/src/modules/<业务>/<对象>.ts`:字段、范围、不变量、create/update/archive 命令。采用唯一的导出名和必要的 `name` 覆盖,避免 index 的 `export *` 丢失重名符号。
60
+ 参考[最小便笺业务](../reference/primitives.md)在 `packages/domain/src/modules/<业务>/<对象>.ts` 声明字段、范围、不变量和本次确需的命令。便笺演示 create/update/archive;当前业务是否需要这些动作由已确认规则决定。采用唯一的导出名和必要的 `name` 覆盖,避免 index 的 `export *` 丢失重名符号。
45
61
 
46
- 从模块 index 到 domain 入口导出后运行 check/gen,审查迁移,再在 `apps/web/src/modules/<业务>` 使用生成 contracts 做列表、详情、表单和操作按钮,经模块公开入口注册到 app 路由。列表和详情都有独立 URL,筛选/分页进入 query,按[浏览器配方](routing.md)检查导航。最后给角色授权并补图谱中文名。完整归属规则见[目录规范](../reference/project-structure.md)。不要手写后端增删改查路由、ORM 实体与 repository,也不要复制框架鉴权代码。
62
+ 声明时同步填写对象、字段、操作的业务名称及每个状态的 labels,按[本体建模指南](ontology-modeling.md)核对对象含义、关系和操作结果。从模块 index 到 domain 入口导出后运行 check/gen,处理缺名诊断并审查迁移,再在 `apps/web/src/modules/<业务>` 使用生成 contracts 做列表、详情、表单和操作按钮,经模块公开入口注册到 app 路由。列表和详情都有独立 URL,筛选/分页进入 query,按[浏览器配方](routing.md)检查导航,并为需要的角色授权。完整归属规则见[目录规范](../reference/project-structure.md)。不要手写后端增删改查路由、ORM 实体与 repository,也不要复制框架鉴权代码。
47
63
 
48
- 完成标准:授权用户能创建和修改,范围外数据不可见,归档后的允许行为符合业务要求,生成契约和迁移一致。没有审批需求时不必添加审批;没有外部系统时不必添加连接器。
64
+ 完成标准:已要求的动作由授权主体执行,范围外数据不可见,状态和失败行为符合已确认规则,生成契约和迁移一致。没有审批需求时不必添加审批;没有外部系统时不必添加连接器。
49
65
 
50
66
  ## 增加一对多或多对多
51
67
 
@@ -56,9 +72,9 @@
56
72
  ## 给业务单据加审批
57
73
 
58
74
  1. 为单据补草稿、待审批、通过、驳回等真实状态及命令;提交时发事件。
59
- 2. 通过/驳回使用 process 命令,根据业务添加职责分离、额度等约束。
75
+ 2. 通过/驳回使用 process 命令,根据业务添加职责分离等约束;分支条件写在审批路由中。
60
76
  3. 添加 approval 绑定和 route;只将需要的字段放进 routable,取消命令发事件并配置 cancelOn。
61
- 4. 配置实际部门负责人、角色或指定用户;给审批人配置能力、范围和额度。
77
+ 4. 配置实际部门负责人、角色或指定用户;给审批人配置能力和范围。
62
78
  5. 页面通过待办接口操作。通过后需占用资源时用反应调用资源命令,按业务一致性选择同事务。
63
79
 
64
80
  完成标准:提交生成待办、正确的人审批、越权和自审批拒绝、取消能结束待办、资源配对完整。转办、委派归还及当前节点前签、后签和并行必签见[审批任务流转](approvals.md),须显式启用政策并传任务版本,旧实例是否开放签序以其快照为准。任意流程设计器、动态 JS 选人和指定节点退回仍需明确扩展范围。
@@ -98,12 +114,10 @@
98
114
  ## 给编程工具的任务模板
99
115
 
100
116
  ```text
101
- 阅读当前项目 AGENTS.md,按 docs/development/README.md 找到本次需求对应的原语和标准范例。
102
- 遵守 docs/development/reference/project-structure.md:领域和前端按业务建 modules,app 组合页面,shared 只放通用代码,不平铺 src 或堆进 main.tsx。
117
+ 阅读当前项目 AGENTS.md,按 docs/development/skills/cage-development/SKILL.md 完成理解、澄清、能力查证、实现映射、编码和验收。
103
118
  业务:……;角色与数据范围:……;状态与允许动作:……;审批/外部系统/资源占用:……。
104
- 阅读后主动指出描述或文档中的疑点,按 docs/development/guides/business-collaboration.md 给出可行选项、影响与推荐,让我选择;已明确条件不重复询问,普通技术细节自行查证处理。
105
- 将已选择的规则映射到 domain、页面、契约、迁移、授权和验收,再完成实现;等待业务决定时继续不依赖该决定的工作,可选建议不阻塞已明确任务。
106
- 使用当前公开 API;对无法表达的需求说明具体缺口,不编造方法。
107
- 生成文件通过 cage gen 更新,数据库使用已有 .env 配置,按改动完成必要验证。
119
+ 先用业务语言说明对本次目标的理解,主动指出疑点,给出可行选项、影响与推荐,让我选择;已明确条件不重复询问,普通技术细节自行查证处理。
120
+ 查现有实现和当前版本 API,写代码前简述已确定规则如何落到 Cage、改哪些模块、如何验收;能明确实现的部分直接推进,等待业务决定时继续独立工作。
121
+ 遵守项目目录与中文注释规范,生成文件通过 cage gen 更新,按改动完成必要验证。
108
122
  交付时说明用户如何体验、管理员需配置什么,以及通过/跳过/未执行的检查。
109
123
  ```
@@ -23,40 +23,57 @@
23
23
  下面可作为 `packages/domain/src/modules/note/note.ts`。它是[最小便笺](../reference/primitives.md)的关系版本,按需要替换原文件,避免重复声明 Note。
24
24
 
25
25
  ```ts
26
+ /**
27
+ * 便笺关系示例,由 domain 入口导出后参与注册、契约和图谱生成。
28
+ * Note 维护协作人集合,NoteComment 通过 noteId 归属便笺;命令只返回变化,持久化由内核完成。
29
+ * 名称使用 description/describe/labels 写入本体,中文注释不代替这些结构化信息。
30
+ */
26
31
  import {
27
32
  aggregate, command, fail, hasMany, manyToMany, ref, scope, states, text,
28
33
  } from '@yss123/cage-kernel';
29
34
  import { z } from 'zod';
30
35
 
36
+ /** 部门便笺独立维护状态和协作人;评论有自己的聚合,本例没有提供便笺归档命令。 */
31
37
  export const Note = aggregate('Note', {
32
38
  description: '部门便笺',
33
39
  fields: {
34
- title: text(120),
35
- deptId: ref('Dept'),
36
- createdBy: ref('User'),
40
+ title: text(120).describe('便笺标题'),
41
+ deptId: ref('Dept').describe('所属部门'),
42
+ createdBy: ref('User').describe('创建人'),
37
43
  // 这是 ID 集合。框架负责物理中间表、约束、关联写入和事务。
38
44
  members: manyToMany('User', { description: '协作成员' }),
39
45
  // 从评论上的 noteId 反查;这不是一份可写的评论 ID 数组。
40
46
  comments: hasMany('NoteComment', { mappedBy: 'noteId', description: '便笺评论' }),
41
47
  },
42
- states: states('active', 'archived', { terminal: ['archived'] }),
48
+ states: states('active', 'archived', {
49
+ terminal: ['archived'],
50
+ labels: { active: '使用中', archived: '已归档' },
51
+ }),
43
52
  scope: scope.deptSubtree('deptId'),
44
53
  invariants: { titleNotBlank: (note) => note.title.trim().length > 0 },
45
54
  });
46
55
 
56
+ /** 评论以 noteId 归属便笺;创建命令读取便笺并复制部门,不依赖 ref 自动继承范围。 */
47
57
  export const NoteComment = aggregate('NoteComment', {
48
58
  description: '便笺评论',
49
59
  fields: {
50
- noteId: ref('Note'),
51
- body: text(2000),
52
- deptId: ref('Dept'),
53
- createdBy: ref('User'),
60
+ noteId: ref('Note').describe('所属便笺'),
61
+ body: text(2000).describe('评论内容'),
62
+ deptId: ref('Dept').describe('所属部门'),
63
+ createdBy: ref('User').describe('评论人'),
54
64
  },
65
+ // 与框架默认的 active/deleted 生命周期相同,仅显式补齐图谱名称,不新增删除操作。
66
+ states: states('active', 'deleted', {
67
+ terminal: ['deleted'],
68
+ labels: { active: '有效评论', deleted: '已删除' },
69
+ }),
55
70
  scope: scope.deptSubtree('deptId'),
56
71
  });
57
72
 
73
+ /** 创建使用中的便笺,可选初始协作人;部门与创建人由内核按当前主体填入。 */
58
74
  export const createNote = command(Note, {
59
75
  name: 'create', from: 'new', to: 'active',
76
+ description: '创建部门便笺',
60
77
  input: z.object({
61
78
  title: z.string().trim().min(1).max(120),
62
79
  members: z.array(z.string().uuid()).optional(),
@@ -65,23 +82,29 @@ export const createNote = command(Note, {
65
82
  handler: (draft) => draft,
66
83
  });
67
84
 
85
+ /** 完整替换使用中便笺的协作人,空数组表示全部解绑;调用方负责提供完整目标集合。 */
68
86
  export const setNoteMembers = command(Note, {
69
87
  name: 'setMembers', from: 'active', to: null,
88
+ description: '替换便笺协作人',
70
89
  input: z.object({ id: z.string().uuid(), members: z.array(z.string().uuid()) }),
71
90
  // 完整替换集合;[] 表示全部解绑。只改关系也会递增便笺版本并写审计。
72
91
  handler: (_draft, input) => ({ members: input.members }),
73
92
  });
74
93
 
94
+ /** 向完整草稿追加协作人,保留既有关联;内核在事务中校验新增目标并规范化集合。 */
75
95
  export const addNoteMembers = command(Note, {
76
96
  name: 'addMembers', from: 'active', to: null,
97
+ description: '追加便笺协作人',
77
98
  input: z.object({ id: z.string().uuid(), memberIds: z.array(z.string().uuid()) }),
78
99
  // 草稿包含完整的既有关联。增量追加可以保留当前操作者看不到的旧成员。
79
100
  // 数组去重与排序由框架统一处理,业务不再维护第二套集合规范化。
80
101
  handler: (draft, input) => ({ members: [...draft.members, ...input.memberIds] }),
81
102
  });
82
103
 
104
+ /** 读取当前可见便笺后创建评论;便笺不可见或已归档时拒绝,成功时沿用其部门。 */
83
105
  export const createNoteComment = command(NoteComment, {
84
106
  name: 'create', from: 'new', to: 'active', reads: { notes: Note },
107
+ description: '评论便笺',
85
108
  input: z.object({ noteId: z.string().uuid(), body: z.string().trim().min(1).max(2000) }),
86
109
  handler: async (_draft, input, { notes }) => {
87
110
  const note = await notes.get(input.noteId);
@@ -79,14 +79,17 @@ export const Note = aggregate('Note', {
79
79
  description: '部门便笺',
80
80
  fields: {
81
81
  /** 便笺标题,最多 120 个字符;命令去除首尾空白后要求非空,不接受 null。 */
82
- title: text(120),
82
+ title: text(120).describe('便笺标题'),
83
83
  /** 所属部门 UUID;创建输入不允许指定,内核从当前主体部门补入,用于范围判断。 */
84
- deptId: ref('Dept'),
84
+ deptId: ref('Dept').describe('所属部门'),
85
85
  /** 创建人 UUID;内核在新建结果中填入操作者,已有记录更新时保留原值。 */
86
- createdBy: ref('User'),
86
+ createdBy: ref('User').describe('创建人'),
87
87
  },
88
88
  /** active 可改标题;archived 为终态,update 的 from 会拒绝对归档记录的修改。 */
89
- states: states('active', 'archived', { terminal: ['archived'] }),
89
+ states: states('active', 'archived', {
90
+ terminal: ['archived'],
91
+ labels: { active: '使用中', archived: '已归档' },
92
+ }),
90
93
  /** 声明部门范围字段和建议范围,实际授权由角色决定,并非自动授予部门可见权。 */
91
94
  scope: scope.deptSubtree('deptId'),
92
95
  invariants: {
@@ -31,6 +31,8 @@
31
31
 
32
32
  字段可链式使用 `.optional()`、`.unique()`、`.sensitive('phone')`、`.hidden()` 等。可用敏感种类以包导出的 `SENSITIVE_KINDS` 为准;hidden 字段不会作为普通公开读字段,sensitive 字段按权限掩码。不要通过前端隐藏来替代它们。
33
33
 
34
+ 业务含义同步写在框架能抽取的位置:字段 `.describe('所属部门')`、对象和操作的 `description`、每个状态的 `labels`。普通注释与前端文案不替代这些名称;完整填写位置、对象关系与检查方式见[本体建模指南](../guides/ontology-modeling.md)。
35
+
34
36
  集合关系也放在 `fields` 中,但不是普通 SQL 列,不支持上述四种修饰。完整声明、成员命令、分页接口、权限与迁移见[对象关系指南](../guides/relations.md)。纯关联不手写 NoteMember 聚合,具有职位、状态等业务属性的关联仍应建业务聚合。
35
37
 
36
38
  不要定义 `id/version/status/createdAt/updatedAt/tenantId` 同名业务字段。聚合名和事件名用大驼峰,字段、命令、查询和任务名用小驼峰,状态名用小写下划线。
@@ -70,10 +72,10 @@ handler: async (order, _input, { stock }) => {
70
72
  ```ts
71
73
  // 片段:放在采购 approve 的配置中。
72
74
  invokedBy: 'process',
73
- constraints: [sod.notSameAs('createdBy'), ceiling('amount')],
75
+ constraints: [sod.notSameAs('createdBy')],
74
76
  ```
75
77
 
76
- `sod` 防止提单人审批自己;`ceiling` 读取审批人该能力上的额度参数,没有额度也拒绝。管理员在 `/admin` 给角色配置 `PurchaseOrder.approve` 的 `ceiling`,不是把额度写死进页面。
78
+ `sod` 防止提单人审批自己。审批流程的业务条件按需声明:采购示例按金额决定是否进入财务节点;其他流程也可以按类型、部门等字段分流,或不使用金额。
77
79
 
78
80
  不变量写在 `aggregate(..., { invariants: { 名称: 对象 => boolean } })`,在最终结果合并和目标状态确定后检查。例如 `Number(o.amount) > 0`。约束回答“这次操作允许吗”,不变量回答“结果对象合法吗”。可用 `Constraint` 类型定义自定义约束对象;先核对公开导出,不假设所有内部 helper 都是公共 API。
79
81
 
@@ -209,7 +211,7 @@ export const poRoute = route('po-approval', [
209
211
 
210
212
  内置选人器是 `approver.deptLeader(字段名)`、`approver.role(角色code)`、`approver.user(用户id)`。条件使用 `gt/gte/lt/lte/eq/ne/isIn` 等封闭表达式。`mode: 'any'/'all'` 描述一步内的人如何完成,不表示任意并行分支。人工节点可通过 `actions: { transfer: true, delegate: true, addSign: true }` 显式开放转办、委派归还和当前节点并行必签,默认关闭;任务版本、权限、SDK 与边界见[审批任务流转](../guides/approvals.md)。任意函数选人、前后加签和并行流程分支仍需扩展。
211
213
 
212
- 被选中的审批人还要具备结论命令所需能力、范围和额度。部门负责人为空会产生 `CAGE-APPR-007`,详见[排错](../tools/troubleshooting.md)。
214
+ 被选中的审批人还要具备结论命令所需能力和范围。部门负责人为空会产生 `CAGE-APPR-007`,详见[排错](../tools/troubleshooting.md)。
213
215
 
214
216
  ## 连接器、定时任务和逃生口
215
217
 
@@ -5,7 +5,9 @@ description: 使用 Cage 框架开发、修改和排查业务应用。适用于
5
5
 
6
6
  # 使用 Cage 开发业务
7
7
 
8
- 阅读用户描述、业务文档和现有实现,主动提出疑问与建议,与用户共同确定业务规则,再转换成 Cage 声明,把声明、生成契约、页面和实际执行连接起来。按当前任务使用本指南,保留项目自己的业务规则和用户授权边界。本文由框架维护,适用于不同业务和 agent;案例中的对象、角色和流程不代表当前应用的需求。
8
+ 本 Skill 是编程 agent 的工作流程:**读项目 → 理解需求并澄清 → 查证框架与现有实现 → 说明实现映射 → 编码 → 按业务验收**。先知道用户要什么、Cage 如何实现,再改代码;不要从一句需求直接套用熟悉的技术方案。
9
+
10
+ 按当前任务使用本流程,保留项目自己的业务规则和用户授权边界。案例中的对象、角色和流程不代表当前应用的需求。这里指导开发阶段的 agent;应用内原生 AI 的接入另见[智能化指南](../../guides/intelligence.md)。
9
11
 
10
12
  ## 先建立正确的运行模型
11
13
 
@@ -42,6 +44,8 @@ Cage 是由业务声明驱动的框架。应用定义业务含义,框架执行
42
44
 
43
45
  ## 2. 提出疑问和建议,与用户共同确定业务
44
46
 
47
+ 先用业务语言整理本次目标:谁要完成什么事,操作前后发生什么变化,哪些条件必须成立,怎样才算完成。区分用户明确提出的规则、文档和代码提供的事实、尚待决定的问题及可选建议;只整理本次相关内容,不能用一份功能名列表代替业务理解。
48
+
45
49
  按[业务澄清与共同设计](../../guides/business-collaboration.md)处理不完整的描述和不清楚的文档。主动指出可能影响业务含义、使用体验、实现范围或验收的疑点,不等到实现失败才询问,也不默默补成自定规则。
46
50
 
47
51
  - 先读相关上下文;API、版本与当前行为由 agent 查文档、公开签名和实现证据。查证后仍涉及业务取舍的,交给用户选择。
@@ -50,26 +54,14 @@ Cage 是由业务声明驱动的框架。应用定义业务含义,框架执行
50
54
  - 沿用用户已给出的选择和授权,不重复确认。普通技术细节自行解决;用户明确委托 agent 决定时,在委托范围内选择并说明依据。推荐、预选和未回复均不等于用户已选择。
51
55
  - 将回答更新为业务规则和验收例子,再映射到框架;实现中发现新疑问仍按此方式处理,用户改主意时同步调整受影响的部分。
52
56
 
53
- 业务条件明确后,按[业务设计与能力选择](../../guides/recipes.md)形成简短的实现映射:
54
-
55
- | 需要确定的事实 | 对应设计 |
56
- | --- | --- |
57
- | 管理什么、哪些数据必须共同成立 | 聚合边界、字段、不变量和对象关系 |
58
- | 谁在什么阶段做什么 | 命令、输入、允许状态、调用身份、硬约束 |
59
- | 数据归谁、各主体可以看到什么 | 归属字段、角色能力及范围,敏感字段掩码 |
60
- | 成功后发生什么、失败要恢复什么 | 事件、反应、审批、连接器、资源释放及补偿 |
61
- | 页面如何展示和操作 | 生成的读取/写入契约、查询、URL、加载与失败状态 |
62
- | 如何知道实现正确 | 持久结果、另一主体的观察结果和关键拒绝路径 |
63
-
64
- 仅记录与本次改动有关的设计,不要求每个任务生成额外计划文件。对每个新增业务按钮,能指出它调用的真实契约;对每个范围要求,能指出服务端使用的归属字段与授权。缺少对应关系时,先补设计。
65
-
66
57
  ## 3. 选择已有能力并核对用法
67
58
 
68
- 按下表阅读相关章节;先看最小接入,再查高级选项。不要一次加载所有专题。
59
+ 带着已理解的业务动作,按[业务设计与能力选择](../../guides/recipes.md)判断聚合、一致性和能力边界,再按下表查用法。先看当前应用有没有对应实现,再决定复用、修改还是新增;不要先设计一套通用后端,再尝试套进 Cage。先看最小接入,再查高级选项,不要一次加载所有专题。
69
60
 
70
61
  | 需求 | 选择方法与学习入口 |
71
62
  | --- | --- |
72
63
  | 新对象、状态、业务操作 | [原语](../../reference/primitives.md):先确定命令意图;已有记录只改字段使用 `to: null`,仍检查允许状态 |
64
+ | 对象/状态看不懂、关系和联动不清楚 | [本体建模](../../guides/ontology-modeling.md):业务含义落实到真实声明,名称完整性与业务正确性分别核对 |
73
65
  | 一对多、多对多 | [关系](../../guides/relations.md):只读反查选 hasMany;纯链接选 manyToMany;关系有独立状态/属性时再建聚合 |
74
66
  | 列表、详情、统计 | 普通 list/get 优先;汇总或联表使用[query](../../reference/primitives.md#两种查询写法),显式 reads 与安全视图 |
75
67
  | 角色、本人/部门范围、敏感字段 | [授权模型](../../getting-started/architecture.md#权限是几层判断):先定归属字段,再配置能力和范围,核对当前会话公开字段 |
@@ -79,7 +71,7 @@ Cage 是由业务声明驱动的框架。应用定义业务含义,框架执行
79
71
  | 导入、导出 | [数据传输](../../guides/transfers.md):导入逐条或原子执行命令,导出异步读取;跟踪任务到终态 |
80
72
  | 第三方系统 | [连接器配方](../../guides/recipes.md#接入外部系统):外呼、验签、幂等、回写命令与失败恢复 |
81
73
  | 原生 AI、AI 审批、随页助理 | [智能化](../../guides/intelligence.md):先检查已有框架能力和 domain 启用状态,再配置策略、授权、模型与界面 |
82
- | 页面、导航、会话 | [目录](../../reference/project-structure.md)与[路由](../../guides/routing.md):模块公开入口、独立 URL、会话恢复与用户缓存清理 |
74
+ | 页面、导航、会话与组件 | [目录](../../reference/project-structure.md)、[路由](../../guides/routing.md)与[前端组件](../../guides/frontend-ui.md):AI 生成真实 React 页面、Ant Design 组合、模块公开入口、独立 URL、会话恢复与用户缓存清理 |
83
75
 
84
76
  知道任务类别时直接阅读上表的章节;需要定位具体术语时先用本地文本搜索。在应用根目录使用:
85
77
 
@@ -93,7 +85,24 @@ pnpm exec cage context "当前业务关键词" --format json
93
85
 
94
86
  调用前确认真实签名、参数、返回结果和前提。类型断言不能增加服务端实际未返回的字段。若当前版本确有缺口,说明具体缺口,给出有依据的可行方案及其业务影响,让用户选择涉及目标或范围变化的方案,同时继续处理独立部分;不要编造 API、复制框架运行时或用本地模拟补足正式业务。
95
87
 
96
- ## 4. 沿一条真实链路实施,再扩展
88
+ ## 4. 写代码前说明实现映射
89
+
90
+ 对准备实现的部分,向用户简述以下对应关系;示例见[规则到实现的映射](../../guides/recipes.md#写代码前的实现映射)。这一步应发生在修改业务代码之前,不能写完后再补一份解释。
91
+
92
+ | 要说明什么 | 必须有的依据 |
93
+ | --- | --- |
94
+ | 本次要实现的业务行为 | 已明确的目标、规则和来源;尚待决定的事项单列 |
95
+ | Cage 如何实现 | 已查证的聚合、命令、状态、范围及必要的后续流程;具体指南、公开签名或现有声明位置 |
96
+ | 具体改哪里 | 复用或修改的模块与导出、需要生成的契约/迁移、页面入口及运行前提;区分框架已提供和应用需完成的部分 |
97
+ | 怎样证明完成 | 用户能观察到的成功结果,以及相关的权限、状态、边界值或失败情形 |
98
+
99
+ 每个业务提交按钮应对应真实契约,每项可见范围应有服务端归属和授权依据,每个自动后续动作应有执行与失败处理路径。对应不上时先查证或补设计;涉及业务取舍则回到第 2 步,不用猜测、类型断言或模拟数据填空。
100
+
101
+ 新建或修改领域时,按[本体建模](../../guides/ontology-modeling.md)说明相关对象的业务含义、关系方向/基数、状态与动作前后结果,再映射到 ref/集合关系、states、命令及必要的触发链。自然语言、文档、表格和原型都是需求证据;不能按页面建表、按字段名猜外键,或把读取箭头当自动联动。聚合/字段/命令等填写结构化描述,每个状态填写 labels;普通注释和页面文案不会自动进入图谱。
102
+
103
+ 清楚的小改动用一两句话即可,不要求新建计划文件,也不要求用户批准普通技术方案。已有明确需求与授权就继续实施;只有尚未确定的业务选择阻塞依赖它的部分。需求或能力证据变化时更新这份映射,避免实现与已选规则脱节。
104
+
105
+ ## 5. 沿一条真实链路实施,再扩展
97
106
 
98
107
  新业务先完成一个动作的保存与读取;已有业务只贯通受影响的动作。按[开发步骤](../../getting-started/workflow.md)操作:
99
108
 
@@ -105,13 +114,14 @@ pnpm exec cage context "当前业务关键词" --format json
105
114
 
106
115
  编写时同步遵守[中文注释规范](../../reference/commenting.md):说明职责、输入输出、调用关系和实际边界。注释中的保证必须能在代码中找到实现。
107
116
 
108
- ## 5. 用观察结果决定完成程度
117
+ ## 6. 用观察结果决定完成程度
109
118
 
110
- 验证与改动匹配,不因小改动运行全部数据库测试。以双方确定的业务规则和验收例子为依据,检查选择是否落实;待决定事项不能报告为已完成。对新的业务读写链,至少核对所涉及的以下证据:
119
+ 验证与改动匹配,不因小改动运行全部数据库测试。逐项回到编码前的规则与验收例子,检查实现和生成结果是否落实了选择、是否混入未要求的业务行为;待决定事项不能报告为已完成。对新的业务读写链,至少核对所涉及的以下证据:
111
120
 
112
121
  | 要证明什么 | 应取得的证据 |
113
122
  | --- | --- |
114
123
  | 声明与接口相符 | check、生成一致性、类型检查以及实际契约调用 |
124
+ | 本体可理解且符合需求 | 处理本次声明的 CAGE-ONTOLOGY-001,按业务用语检查图谱/context;逐项核对关系、状态和触发依据,再用业务例子验证,名称齐全不等于业务正确 |
115
125
  | 数据持久保存 | 命令成功后通过安全接口独立读取;页面重新加载使用同一服务端记录 |
116
126
  | 权限与范围生效 | 允许主体成功,范围外或缺能力主体的直接请求被拒绝 |
117
127
  | 流程真正执行 | 提交、待办、决定、结论命令及最终业务状态对应起来 |
@@ -121,7 +131,7 @@ pnpm exec cage context "当前业务关键词" --format json
121
131
 
122
132
  检查通过不能扩大解释为未检查的业务结果。交付分别报告通过、跳过、未执行,附具体行为与证据;缺少运行条件时明确剩余验证,不伪造成功记录。
123
133
 
124
- ## 6. 遇到失败,沿边界定位
134
+ ## 7. 遇到失败,沿边界定位
125
135
 
126
136
  先保留 `code / at / reason / fix` 和相关操作事实,查[排错方法](../../tools/troubleshooting.md)与[错误码册](../../../errors/README.md)。从页面真实调用开始,定位第一个不符合预期的边界,再做最小修正:
127
137
 
@@ -8,12 +8,15 @@ pnpm exec cage capabilities reactionEach --format json
8
8
  pnpm exec cage capabilities "AI审批" --format json
9
9
  pnpm exec cage capabilities "页面上下文" --format json
10
10
  pnpm exec cage capabilities "性格" --format json
11
+ pnpm exec cage capabilities "状态名称" --format json
11
12
  pnpm exec cage context "设备归还" --format json
12
13
  pnpm exec cage doctor --format json
13
14
  ```
14
15
 
15
16
  公开能力报告包含包版本、真实签名、公开导出名、声明位置与本地学习指南。未安装的包标为未检查;未命中关键词不能证明能力不存在。完整例子见 [原语](../reference/primitives.md) 和 [任务配方](../guides/recipes.md)。
16
17
 
18
+ “本体建模”“状态名称”“对象关系”分别召回真实的领域声明、状态 labels 和关系 API。按[本体建模指南](../guides/ontology-modeling.md)填写结构化名称;`CAGE-ONTOLOGY-001` 对本地可定位且支持命名的节点检查非空名称,默认警告,`graph.naming: 'required'` 时阻止 check/gen/verify。它不从注释或页面推断含义,也不把名称存在判为业务关系正确。
19
+
17
20
  原生智能化可用“AI审批”“业务助理”“随页助理”“模型管理”“性格”“Responses”“上下文预算”等关键词检索,结果指向[智能化指南](../guides/intelligence.md)。例如 AI 审批返回现有 `step` 的重载及 `AiStepOptions`,不是另造 `aiStep` 原语。公开能力可被检索,不代表本应用已经导出 `ai()`、执行迁移、配置模型或授予角色权限;接着核对项目启用状态,最后进行实际功能验证。
18
21
 
19
22
  `doctor` 复用 `check`、`gen --check`,输出统一的 `schemaVersion / observedAt / checks / findings / registration / routes`。每个检查包含 `status / source / reason / next`。`pass` 表示相应证据通过,`fail` 表示已发现问题,`unknown` 表示未检查;`complete: false` 不能作为完整验收通过。注册报告列出声明位置、domain 入口、注册节点和对应路由,集合反应还包含上限、排序键、顺序和事务。
@@ -26,7 +29,7 @@ pnpm exec cage doctor --format json
26
29
  pnpm exec cage doctor --runtime-url http://127.0.0.1:3000 --cookie-file .cage/diagnostic-cookie.txt
27
30
  ```
28
31
 
29
- 此模式只调用受 `Sys.ops.read` 保护的诊断接口。证据缺失、服务未运行、没有权限或没有 worker 心跳时标记 `unknown`;接口显示已加载版本和注册指纹,不能仅凭磁盘源码推断进程已经更新。能力已配置给某个角色也不代表任意用户具备范围、额度或调用身份。完成修改后仍需运行 `verify` 和实际业务验收。
32
+ 此模式只调用受 `Sys.ops.read` 保护的诊断接口。证据缺失、服务未运行、没有权限或没有 worker 心跳时标记 `unknown`;接口显示已加载版本和注册指纹,不能仅凭磁盘源码推断进程已经更新。能力已配置给某个角色也不代表任意用户具备范围或调用身份。完成修改后仍需运行 `verify` 和实际业务验收。
30
33
 
31
34
  运行指纹优先使用项目标准 `src→dist` 的实际编译入口,并逐文件检查源码与对应产物的修改时间。缺少构建或使用非标准输出布局时标记未知;编译后还需要重启 API 和 worker。源码经不同转换器执行时的函数文本可能不同,因此不把源码指纹直接当作生产产物指纹。
32
35
 
@@ -58,7 +58,7 @@ export const purchaseOverview = businessProcess('purchase-overview', {
58
58
 
59
59
  `cage check` 用 [CAGE-BIZ-001](../../errors/CAGE-BIZ-001.md) 和 [CAGE-BIZ-002](../../errors/CAGE-BIZ-002.md) 检查声明与实现关系。它不执行 handler、map 或审批,所以仍需业务回归证明运行行为。
60
60
 
61
- 阶段直接使用 `title`、`description`、`actor` 的中文文案;操作和字段等继续用 `graph.labels`,审批角色可用 `"role:finance": "财务"`。状态也可在 `states(..., { labels: { draft: '草稿' } })` 中维护中文名;这些名称不更改原有状态标识。
61
+ 阶段直接使用 `title`、`description`、`actor` 的业务文案;对象和操作使用声明的 `description`,字段使用 `.describe(...)`,每个状态都在 `states(..., { labels: { draft: '草稿' } })` 中填写名称。`graph.labels` 用于显示覆盖及无通用描述选项的节点,例如 `"role:finance": "财务"`。普通注释与前端状态映射不会被抽取,`CAGE-ONTOLOGY-001` 会报告缺失的结构化名称;填写位置与业务验收边界见[本体建模指南](../guides/ontology-modeling.md)。这些名称不更改机器标识。
62
62
 
63
63
  ## 开发一项需求的入口
64
64
 
@@ -10,7 +10,7 @@
10
10
 
11
11
  先保留完整诊断的 code、源码位置、reason/fix、requestId 或 outboxId。检查所在阶段,再修复原因;不要通过改业务状态、给全局权限、注释约束或禁用 lint 消除现象。
12
12
 
13
- 先执行 `pnpm exec cage doctor` 查看各阶段证据;异步动作按 requestId/outboxId/业务对象用 `cage timeline` 关联实际执行记录。能力、范围、调用身份或额度不清楚时,有权诊断的管理员可使用 `cage explain`,不会执行目标命令。完整参数与权限见[诊断指南](diagnostics.md)。
13
+ 先执行 `pnpm exec cage doctor` 查看各阶段证据;异步动作按 requestId/outboxId/业务对象用 `cage timeline` 关联实际执行记录。能力、范围或调用身份不清楚时,有权诊断的管理员可使用 `cage explain`,不会执行目标命令。完整参数与权限见[诊断指南](diagnostics.md)。
14
14
 
15
15
  ## 按现象定位
16
16
 
@@ -19,7 +19,7 @@
19
19
  | dev 启不动 | `.env` 是否在项目根目录,数据库服务是否可连接 | 缺连接、密码/端口错误、没执行迁移、端口占用 |
20
20
  | init 提示账号已存在 | CAGE-INIT-002;找已有 APP/READ/MIGRATE 连接 | 角色在 PG 集群内共享;不应覆盖原密码 |
21
21
  | 新业务不出现在接口/图谱 | 顶层 export const 和 domain/index.ts | 漏导出、重名导出、放进函数/条件声明 |
22
- | API 403 | code/detail、角色能力、调用身份、硬约束 | 能力不足、CSRF、职责分离、额度缺失/超限 |
22
+ | API 403 | code/detail、角色能力、调用身份、硬约束 | 能力不足、CSRF、职责分离或其他业务约束不满足 |
23
23
  | 详情 404 | 记录 id、租户和数据范围 | 不存在或在范围外;不能仅凭 404 断言被删除 |
24
24
  | 列表为空 | read 能力、范围与相应字段 | 默认本人范围、无 owner 字段或部门不匹配 |
25
25
  | 电话看不到明文 | sensitive 标注、unmask 能力 | 默认掩码是正常安全行为 |
@@ -42,7 +42,7 @@
42
42
  | `approver.role('finance')` | 创建 code 为 finance 的角色,并给实际用户分配 | 选人看角色 code,不是中文显示名称 |
43
43
  | `approver.user(id)` | 使用存在的用户 UUID,核对业务可用性 | 把用户名或角色名当成 UUID |
44
44
 
45
- 选人成功后,再检查此人所需能力、数据范围、额度。示例中提单人不能审批自己,经理的 `PurchaseOrder.approve` 必须有 ceiling 参数。
45
+ 选人成功后,再检查此人所需能力、数据范围及结论命令的业务约束。示例中提单人不能审批自己;采购金额决定是否进入财务节点,不需要配置角色额度。
46
46
 
47
47
  若事件已进入死信,在 `/admin` 查看对应 outboxId 的错误并修正配置,再点击重放。原 submit 通常已提交,单据处于 pending_approval;不要重复提交,更不要直接 SQL 改回 draft。重放后确认待办及后续事件,不把“点击重放成功”当成整条链路已经完成。
48
48
 
@@ -15,7 +15,7 @@ worker 启动或推进审批步骤时选人器没有找到人,或字段选人/
15
15
  1. 先看本项目 approvals.ts:deptLeader 读取单据部门的负责人;role 使用角色 code;user 使用实际用户 UUID。
16
16
  2. 在 /admin 设置单据所属部门的负责人,或创建对应 code 的角色并分配实际用户。给用户经理角色,并不等于设置了部门负责人。
17
17
  3. field 使用提交时保存的 routable 人员字段;检查 UUID 对应账号是否全部在当前租户且 active。不能删掉不合格人员后默认为审批通过;字段快照错误需按业务撤回/重提修正。
18
- 4. 再核对审批人的结论能力、数据范围、ceiling 额度和职责分离。选中审批人不等于允许完成审批。
18
+ 4. 再核对审批人的结论能力、数据范围和职责分离。选中审批人不等于允许完成审批。
19
19
  5. 若 OrderSubmitted 已入死信,修复后在 /admin 按 outboxId 重放,确认待办生成;原提交已成功时不重复提交或 SQL 改回草稿。
20
20
 
21
21
  ## 正例
@@ -1,4 +1,4 @@
1
- # CAGE-GRANT-001:授予超出自己的能力或额度
1
+ # CAGE-GRANT-001:授予超出自己的能力或参数
2
2
 
3
3
  [返回错误码册](README.md) · [业务排错](../development/tools/troubleshooting.md)
4
4
 
@@ -8,16 +8,16 @@
8
8
 
9
9
  阶段:组织命令。
10
10
 
11
- 管理员授予自己没有的能力/更高参数,或分配含越权能力的角色。
11
+ 管理员授予自己没有的能力/更高数值参数、分配含越权能力的角色,或尝试维护受保护的超级管理员角色与账号。
12
12
 
13
13
  ## 修复步骤
14
14
 
15
- 1. 由具备足够能力和参数的管理员操作;降低授予范围到自身权限内,不禁用防提权约束。
15
+ 1. 由具备足够能力和参数的管理员操作;超级管理员角色和账号由超级管理员维护。目标用户的角色不可见时需先取得角色读取能力和全部范围,不禁用防提权约束。
16
16
 
17
17
  ## 正例
18
18
 
19
19
  ```text
20
- 有 approve=100000 额度的管理员授予不超过自身的额度
20
+ 自己有采购审批能力时,给普通角色授予该能力
21
21
  ```
22
22
 
23
23
  ## 反例
@@ -34,16 +34,22 @@
34
34
 
35
35
  以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
36
36
 
37
- - `packages/admin/src/domain/constraints.ts:39`
38
- - `packages/admin/src/domain/constraints.ts:42`
39
- - `packages/admin/src/domain/constraints.ts:78`
37
+ - `packages/admin/src/domain/constraints.ts:38`
38
+ - `packages/admin/src/domain/constraints.ts:40`
39
+ - `packages/admin/src/domain/constraints.ts:55`
40
+ - `packages/admin/src/domain/constraints.ts:61`
41
+ - `packages/admin/src/domain/constraints.ts:67`
42
+ - `packages/admin/src/domain/constraints.ts:69`
43
+ - `packages/admin/src/domain/constraints.ts:85`
44
+ - `packages/admin/src/domain/constraints.ts:88`
45
+ - `packages/admin/src/domain/constraints.ts:124`
40
46
 
41
47
  实现片段(位置随框架版本更新):
42
48
 
43
49
  ```ts
44
- const mine = ctx.capabilities.get(input.capability);
45
- if (!mine) return violation('[CAGE-GRANT-001] 不能授出自己没有的能力点');
46
- for (const [k, v] of Object.entries(input.params ?? {})) {
47
- if (typeof v === 'number' && typeof mine[k] === 'number' && v > (mine[k] as number)) {
48
- return violation(`[CAGE-GRANT-001] 参数 ${k}=${v} 超过了你自己的 ${mine[k]}`);
50
+ if (!role.capabilities?.some((entry: { capability: string }) => entry.capability === '*') || ctx.actor?.kind === 'system') return ok();
51
+ if (!ctx.capabilities.has('*')) return violation('[CAGE-GRANT-001] 只有超级管理员可以维护超级管理员角色');
52
+ if (meta.capability === 'Role.archive' || (meta.capability === 'Role.revokeCapability' && input.capability === '*'))
53
+ return violation('[CAGE-GRANT-001] 不能停用超级管理员角色或移除全部能力标记');
54
+ return ok();
49
55
  ```
@@ -34,8 +34,8 @@
34
34
 
35
35
  以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
36
36
 
37
- - `packages/admin/src/domain/constraints.ts:59`
38
- - `packages/admin/src/domain/constraints.ts:82`
37
+ - `packages/admin/src/domain/constraints.ts:105`
38
+ - `packages/admin/src/domain/constraints.ts:128`
39
39
 
40
40
  实现片段(位置随框架版本更新):
41
41
 
@@ -8,11 +8,11 @@
8
8
 
9
9
  阶段:组织命令。
10
10
 
11
- 授权请求引用了注册表没有声明的能力点。
11
+ 授权请求引用了注册表没有声明的能力点,或普通授权操作使用了初始化专用的全部能力标记。
12
12
 
13
13
  ## 修复步骤
14
14
 
15
- 1. 先在 domain 声明并导出相应命令/聚合,再查看能力目录;不要在管理页面凭空发明能力名称。
15
+ 1. 先在 domain 声明并导出相应命令/聚合,再查看能力目录;不要在管理页面凭空发明能力名称。全部能力标记仅由首次初始化写入。
16
16
 
17
17
  ## 正例
18
18
 
@@ -35,7 +35,7 @@ PurchaseOrder.anything // 没有对应声明
35
35
  以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
36
36
 
37
37
  - `packages/admin/src/domain/constraints.ts:21`
38
- - `packages/admin/src/domain/constraints.ts:26`
38
+ - `packages/admin/src/domain/constraints.ts:27`
39
39
 
40
40
  实现片段(位置随框架版本更新):
41
41