@yss123/cage-cli 0.1.0 → 0.3.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 (734) hide show
  1. package/README.md +69 -3
  2. package/bin/cage.js +5 -0
  3. package/bin/create-cage-app.js +5 -0
  4. package/dist/analyze.d.ts +16 -0
  5. package/dist/analyze.js +20 -2
  6. package/dist/analyze.js.map +1 -1
  7. package/dist/baseline.d.ts +8 -0
  8. package/dist/baseline.js +13 -0
  9. package/dist/baseline.js.map +1 -1
  10. package/dist/bootstrap.d.ts +20 -0
  11. package/dist/bootstrap.js +75 -0
  12. package/dist/bootstrap.js.map +1 -0
  13. package/dist/budget.d.ts +7 -0
  14. package/dist/budget.js +49 -5
  15. package/dist/budget.js.map +1 -1
  16. package/dist/capabilities.d.ts +38 -0
  17. package/dist/capabilities.js +133 -0
  18. package/dist/capabilities.js.map +1 -0
  19. package/dist/config.d.ts +33 -4
  20. package/dist/config.js +22 -1
  21. package/dist/config.js.map +1 -1
  22. package/dist/context.d.ts +86 -0
  23. package/dist/context.js +235 -0
  24. package/dist/context.js.map +1 -0
  25. package/dist/create-prompt.d.ts +12 -0
  26. package/dist/create-prompt.js +62 -0
  27. package/dist/create-prompt.js.map +1 -0
  28. package/dist/create.d.ts +38 -1
  29. package/dist/create.js +52 -13
  30. package/dist/create.js.map +1 -1
  31. package/dist/derive.d.ts +23 -0
  32. package/dist/derive.js +40 -0
  33. package/dist/derive.js.map +1 -1
  34. package/dist/dev.d.ts +6 -0
  35. package/dist/dev.js +23 -51
  36. package/dist/dev.js.map +1 -1
  37. package/dist/doctor.d.ts +98 -0
  38. package/dist/doctor.js +93 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/env.d.ts +6 -0
  41. package/dist/env.js +11 -0
  42. package/dist/env.js.map +1 -1
  43. package/dist/findings.d.ts +27 -0
  44. package/dist/findings.js +20 -0
  45. package/dist/findings.js.map +1 -1
  46. package/dist/gen/contracts.d.ts +28 -0
  47. package/dist/gen/contracts.js +81 -20
  48. package/dist/gen/contracts.js.map +1 -1
  49. package/dist/gen/index.d.ts +26 -0
  50. package/dist/gen/index.js +112 -4
  51. package/dist/gen/index.js.map +1 -1
  52. package/dist/gen/zod-code.d.ts +43 -1
  53. package/dist/gen/zod-code.js +180 -16
  54. package/dist/gen/zod-code.js.map +1 -1
  55. package/dist/graph-approvals.d.ts +60 -0
  56. package/dist/graph-approvals.js +80 -0
  57. package/dist/graph-approvals.js.map +1 -0
  58. package/dist/graph-business.d.ts +135 -0
  59. package/dist/graph-business.js +404 -0
  60. package/dist/graph-business.js.map +1 -0
  61. package/dist/graph-command.d.ts +28 -0
  62. package/dist/graph-command.js +88 -0
  63. package/dist/graph-command.js.map +1 -0
  64. package/dist/graph-model.d.ts +65 -0
  65. package/dist/graph-model.js +134 -0
  66. package/dist/graph-model.js.map +1 -0
  67. package/dist/graph-presentation.d.ts +27 -0
  68. package/dist/graph-presentation.js +34 -0
  69. package/dist/graph-presentation.js.map +1 -0
  70. package/dist/graph-query.d.ts +266 -0
  71. package/dist/graph-query.js +304 -0
  72. package/dist/graph-query.js.map +1 -0
  73. package/dist/graph-relations.d.ts +34 -0
  74. package/dist/graph-relations.js +172 -0
  75. package/dist/graph-relations.js.map +1 -0
  76. package/dist/graph-search.d.ts +56 -0
  77. package/dist/graph-search.js +99 -0
  78. package/dist/graph-search.js.map +1 -0
  79. package/dist/graph-snapshot.d.ts +28 -4
  80. package/dist/graph-snapshot.js +32 -20
  81. package/dist/graph-snapshot.js.map +1 -1
  82. package/dist/graph.d.ts +13 -2
  83. package/dist/graph.js +78 -5
  84. package/dist/graph.js.map +1 -1
  85. package/dist/impact.d.ts +56 -0
  86. package/dist/impact.js +90 -18
  87. package/dist/impact.js.map +1 -1
  88. package/dist/index.d.ts +15 -1
  89. package/dist/index.js +15 -1
  90. package/dist/index.js.map +1 -1
  91. package/dist/init.d.ts +18 -0
  92. package/dist/init.js +146 -0
  93. package/dist/init.js.map +1 -0
  94. package/dist/load.d.ts +10 -0
  95. package/dist/load.js +15 -0
  96. package/dist/load.js.map +1 -1
  97. package/dist/main.d.ts +6 -0
  98. package/dist/main.js +170 -37
  99. package/dist/main.js.map +1 -1
  100. package/dist/migrate.d.ts +15 -6
  101. package/dist/migrate.js +31 -53
  102. package/dist/migrate.js.map +1 -1
  103. package/dist/ontology.d.ts +69 -2
  104. package/dist/ontology.js +101 -4
  105. package/dist/ontology.js.map +1 -1
  106. package/dist/process-rules.d.ts +21 -0
  107. package/dist/process-rules.js +100 -0
  108. package/dist/process-rules.js.map +1 -0
  109. package/dist/process.d.ts +32 -0
  110. package/dist/process.js +32 -0
  111. package/dist/process.js.map +1 -1
  112. package/dist/project-structure.d.ts +13 -0
  113. package/dist/project-structure.js +104 -0
  114. package/dist/project-structure.js.map +1 -0
  115. package/dist/registration.d.ts +16 -0
  116. package/dist/registration.js +56 -0
  117. package/dist/registration.js.map +1 -0
  118. package/dist/rules.d.ts +52 -0
  119. package/dist/rules.js +58 -0
  120. package/dist/rules.js.map +1 -1
  121. package/dist/runtime-diagnostics.d.ts +27 -0
  122. package/dist/runtime-diagnostics.js +60 -0
  123. package/dist/runtime-diagnostics.js.map +1 -0
  124. package/dist/snapshots.d.ts +40 -0
  125. package/dist/snapshots.js +62 -0
  126. package/dist/snapshots.js.map +1 -0
  127. package/dist/static-check.d.ts +33 -0
  128. package/dist/static-check.js +38 -5
  129. package/dist/static-check.js.map +1 -1
  130. package/dist/sync.d.ts +11 -0
  131. package/dist/sync.js +139 -10
  132. package/dist/sync.js.map +1 -1
  133. package/dist/upgrade.d.ts +16 -0
  134. package/dist/upgrade.js +21 -0
  135. package/dist/upgrade.js.map +1 -1
  136. package/dist/verify.d.ts +14 -0
  137. package/dist/verify.js +19 -0
  138. package/dist/verify.js.map +1 -1
  139. package/dist/version.js +5 -0
  140. package/dist/version.js.map +1 -1
  141. package/graph-ui/app.js +367 -35
  142. package/graph-ui/approval-flow.js +165 -0
  143. package/graph-ui/business.css +985 -0
  144. package/graph-ui/business.js +549 -0
  145. package/graph-ui/flowchart-interaction.js +177 -0
  146. package/graph-ui/flowchart.js +1059 -0
  147. package/graph-ui/graph-approvals.js +79 -0
  148. package/graph-ui/graph-business.js +403 -0
  149. package/graph-ui/graph-model.js +133 -0
  150. package/graph-ui/graph-relations.js +171 -0
  151. package/graph-ui/graph-search.js +98 -0
  152. package/graph-ui/index.html +26 -12
  153. package/graph-ui/model.js +47 -77
  154. package/graph-ui/relations.js +6 -125
  155. package/graph-ui/structure.js +48 -1
  156. package/graph-ui/style.css +33 -0
  157. package/package.json +10 -8
  158. package/templates/app/.dockerignore +2 -0
  159. package/templates/app/.env.example +68 -14
  160. package/templates/app/AGENTS.md +135 -12
  161. package/templates/app/Dockerfile +2 -0
  162. package/templates/app/README.md +49 -16
  163. package/templates/app/_gitignore +9 -0
  164. package/templates/app/apps/api/package.json +2 -2
  165. package/templates/app/apps/api/src/main.ts +5 -1
  166. package/templates/app/apps/api/src/worker.ts +3 -0
  167. package/templates/app/apps/web/index.html +1 -0
  168. package/templates/app/apps/web/package.json +7 -3
  169. package/templates/app/apps/web/src/app/app.tsx +128 -0
  170. package/templates/app/apps/web/src/{style.css → app/styles/global.css} +88 -8
  171. package/templates/app/apps/web/src/app/use-session.ts +43 -0
  172. package/templates/app/apps/web/src/app/workspace-layout.tsx +109 -0
  173. package/templates/app/apps/web/src/main.tsx +9 -543
  174. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +31 -0
  175. package/templates/app/apps/web/src/modules/approval/index.ts +6 -0
  176. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +73 -0
  177. package/templates/app/apps/web/src/modules/auth/index.ts +5 -0
  178. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +71 -0
  179. package/templates/app/apps/web/src/modules/inventory/index.ts +5 -0
  180. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +102 -0
  181. package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
  182. package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  183. package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  184. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  185. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +82 -0
  186. package/templates/app/apps/web/src/modules/purchase/index.ts +7 -0
  187. package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  188. package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
  189. package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
  190. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +240 -0
  191. package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
  192. package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  193. package/templates/app/apps/web/src/shared/hooks/use-command.ts +42 -0
  194. package/templates/app/apps/web/src/shared/lib/error-message.ts +24 -0
  195. package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
  196. package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  197. package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
  198. package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  199. package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  200. package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
  201. package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  202. package/templates/app/apps/web/src/shared/ui/notice.tsx +20 -0
  203. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +35 -0
  204. package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
  205. package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
  206. package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
  207. package/templates/app/apps/web/vite.config.ts +8 -0
  208. package/templates/app/cage.config.json +10 -1
  209. package/templates/app/db/migrations/0002_draft.sql +12 -0
  210. package/templates/app/db/migrations/0003_draft.sql +8 -0
  211. package/templates/app/deploy/nginx.conf +52 -0
  212. package/templates/app/docs/ai/README.md +98 -0
  213. package/templates/app/docs/ai/architecture.md +148 -0
  214. package/templates/app/docs/ai/commenting.md +203 -0
  215. package/templates/app/docs/ai/diagnostics.md +80 -0
  216. package/templates/app/docs/ai/files.md +93 -0
  217. package/templates/app/docs/ai/intelligence.md +348 -0
  218. package/templates/app/docs/ai/ontology-context.md +172 -0
  219. package/templates/app/docs/ai/primitives.md +282 -0
  220. package/templates/app/docs/ai/project-structure.md +128 -0
  221. package/templates/app/docs/ai/purchase-example.md +111 -0
  222. package/templates/app/docs/ai/recipes.md +89 -0
  223. package/templates/app/docs/ai/relations.md +160 -0
  224. package/templates/app/docs/ai/routing.md +86 -0
  225. package/templates/app/docs/ai/transfers.md +92 -0
  226. package/templates/app/docs/ai/troubleshooting.md +65 -0
  227. package/templates/app/docs/ai/workflow.md +152 -0
  228. package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
  229. package/templates/app/docs/errors/CAGE-APPR-001.md +48 -0
  230. package/templates/app/docs/errors/CAGE-APPR-002.md +47 -0
  231. package/templates/app/docs/errors/CAGE-APPR-003.md +47 -0
  232. package/templates/app/docs/errors/CAGE-APPR-004.md +47 -0
  233. package/templates/app/docs/errors/CAGE-APPR-005.md +47 -0
  234. package/templates/app/docs/errors/CAGE-APPR-006.md +53 -0
  235. package/templates/app/docs/errors/CAGE-APPR-007.md +50 -0
  236. package/templates/app/docs/errors/CAGE-APPR-010.md +48 -0
  237. package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
  238. package/templates/app/docs/errors/CAGE-AUTH-001.md +47 -0
  239. package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
  240. package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
  241. package/templates/app/docs/errors/CAGE-BUDGET-001.md +47 -0
  242. package/templates/app/docs/errors/CAGE-BUDGET-002.md +47 -0
  243. package/templates/app/docs/errors/CAGE-BUDGET-003.md +47 -0
  244. package/templates/app/docs/errors/CAGE-CMD-002.md +47 -0
  245. package/templates/app/docs/errors/CAGE-CMD-003.md +47 -0
  246. package/templates/app/docs/errors/CAGE-CONN-001.md +47 -0
  247. package/templates/app/docs/errors/CAGE-CONN-002.md +47 -0
  248. package/templates/app/docs/errors/CAGE-CONN-003.md +47 -0
  249. package/templates/app/docs/errors/CAGE-CONN-004.md +47 -0
  250. package/templates/app/docs/errors/CAGE-CONN-005.md +47 -0
  251. package/templates/app/docs/errors/CAGE-CONN-006.md +47 -0
  252. package/templates/app/docs/errors/CAGE-CONN-007.md +47 -0
  253. package/templates/app/docs/errors/CAGE-CONN-008.md +47 -0
  254. package/templates/app/docs/errors/CAGE-CONN-009.md +47 -0
  255. package/templates/app/docs/errors/CAGE-CONN-010.md +47 -0
  256. package/templates/app/docs/errors/CAGE-CONN-011.md +47 -0
  257. package/templates/app/docs/errors/CAGE-CONN-012.md +47 -0
  258. package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
  259. package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
  260. package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
  261. package/templates/app/docs/errors/CAGE-CREATE-001.md +53 -0
  262. package/templates/app/docs/errors/CAGE-DECL-001.md +48 -0
  263. package/templates/app/docs/errors/CAGE-DECL-002.md +48 -0
  264. package/templates/app/docs/errors/CAGE-DECL-003.md +47 -0
  265. package/templates/app/docs/errors/CAGE-DECL-004.md +47 -0
  266. package/templates/app/docs/errors/CAGE-DEP-001.md +48 -0
  267. package/templates/app/docs/errors/CAGE-DEP-002.md +47 -0
  268. package/templates/app/docs/errors/CAGE-DEP-003.md +47 -0
  269. package/templates/app/docs/errors/CAGE-DEP-004.md +47 -0
  270. package/templates/app/docs/errors/CAGE-DEP-005.md +47 -0
  271. package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
  272. package/templates/app/docs/errors/CAGE-DLQ-001.md +48 -0
  273. package/templates/app/docs/errors/CAGE-ENV-001.md +52 -0
  274. package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
  275. package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
  276. package/templates/app/docs/errors/CAGE-EVENT-001.md +47 -0
  277. package/templates/app/docs/errors/CAGE-EVENT-002.md +50 -0
  278. package/templates/app/docs/errors/CAGE-FIELD-001.md +47 -0
  279. package/templates/app/docs/errors/CAGE-FIELD-002.md +47 -0
  280. package/templates/app/docs/errors/CAGE-FIELD-003.md +47 -0
  281. package/templates/app/docs/errors/CAGE-FIELD-004.md +47 -0
  282. package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
  283. package/templates/app/docs/errors/CAGE-GEN-001.md +48 -0
  284. package/templates/app/docs/errors/CAGE-GEN-002.md +47 -0
  285. package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
  286. package/templates/app/docs/errors/CAGE-GRANT-001.md +49 -0
  287. package/templates/app/docs/errors/CAGE-GRANT-002.md +48 -0
  288. package/templates/app/docs/errors/CAGE-GRANT-003.md +48 -0
  289. package/templates/app/docs/errors/CAGE-IMPACT-001.md +48 -0
  290. package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
  291. package/templates/app/docs/errors/CAGE-INIT-001.md +47 -0
  292. package/templates/app/docs/errors/CAGE-INIT-002.md +49 -0
  293. package/templates/app/docs/errors/CAGE-INIT-003.md +48 -0
  294. package/templates/app/docs/errors/CAGE-INIT-004.md +48 -0
  295. package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
  296. package/templates/app/docs/errors/CAGE-JOB-001.md +47 -0
  297. package/templates/app/docs/errors/CAGE-JOB-002.md +47 -0
  298. package/templates/app/docs/errors/CAGE-JOB-003.md +47 -0
  299. package/templates/app/docs/errors/CAGE-LINT-001.md +47 -0
  300. package/templates/app/docs/errors/CAGE-MIG-001.md +47 -0
  301. package/templates/app/docs/errors/CAGE-MIG-002.md +47 -0
  302. package/templates/app/docs/errors/CAGE-MIG-003.md +5 -0
  303. package/templates/app/docs/errors/CAGE-MIG-004.md +5 -0
  304. package/templates/app/docs/errors/CAGE-MIG-005.md +47 -0
  305. package/templates/app/docs/errors/CAGE-NAME-001.md +47 -0
  306. package/templates/app/docs/errors/CAGE-NAME-002.md +47 -0
  307. package/templates/app/docs/errors/CAGE-NAME-003.md +47 -0
  308. package/templates/app/docs/errors/CAGE-NAME-004.md +47 -0
  309. package/templates/app/docs/errors/CAGE-NAME-005.md +47 -0
  310. package/templates/app/docs/errors/CAGE-NAME-006.md +47 -0
  311. package/templates/app/docs/errors/CAGE-ORG-001.md +50 -0
  312. package/templates/app/docs/errors/CAGE-PAIR-002.md +51 -0
  313. package/templates/app/docs/errors/CAGE-QUERY-001.md +47 -0
  314. package/templates/app/docs/errors/CAGE-QUERY-002.md +47 -0
  315. package/templates/app/docs/errors/CAGE-QUERY-003.md +50 -0
  316. package/templates/app/docs/errors/CAGE-REACT-001.md +47 -0
  317. package/templates/app/docs/errors/CAGE-REACT-002.md +47 -0
  318. package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
  319. package/templates/app/docs/errors/CAGE-READS-001.md +50 -0
  320. package/templates/app/docs/errors/CAGE-REG-001.md +54 -0
  321. package/templates/app/docs/errors/CAGE-REG-002.md +49 -0
  322. package/templates/app/docs/errors/CAGE-REG-003.md +47 -0
  323. package/templates/app/docs/errors/CAGE-REL-001.md +64 -0
  324. package/templates/app/docs/errors/CAGE-ROUTE-001.md +48 -0
  325. package/templates/app/docs/errors/CAGE-SCOPE-001.md +47 -0
  326. package/templates/app/docs/errors/CAGE-SCOPE-002.md +47 -0
  327. package/templates/app/docs/errors/CAGE-SECRET-001.md +48 -0
  328. package/templates/app/docs/errors/CAGE-SECRET-002.md +47 -0
  329. package/templates/app/docs/errors/CAGE-SENS-001.md +48 -0
  330. package/templates/app/docs/errors/CAGE-SQL-001.md +47 -0
  331. package/templates/app/docs/errors/CAGE-SQL-002.md +47 -0
  332. package/templates/app/docs/errors/CAGE-STATE-001.md +49 -0
  333. package/templates/app/docs/errors/CAGE-STATE-002.md +47 -0
  334. package/templates/app/docs/errors/CAGE-STATE-003.md +47 -0
  335. package/templates/app/docs/errors/CAGE-STATE-004.md +47 -0
  336. package/templates/app/docs/errors/CAGE-STATE-005.md +49 -0
  337. package/templates/app/docs/errors/CAGE-STATE-010.md +48 -0
  338. package/templates/app/docs/errors/CAGE-STATE-011.md +48 -0
  339. package/templates/app/docs/errors/CAGE-STRUCT-001.md +51 -0
  340. package/templates/app/docs/errors/CAGE-STRUCT-002.md +51 -0
  341. package/templates/app/docs/errors/CAGE-SYNC-001.md +49 -0
  342. package/templates/app/docs/errors/CAGE-TEST-001.md +47 -0
  343. package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
  344. package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
  345. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +49 -0
  346. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +48 -0
  347. package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
  348. package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
  349. package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
  350. package/templates/app/docs/errors/README.md +357 -0
  351. package/templates/app/docs/errors/runtime.md +50 -0
  352. package/templates/app/package.json +4 -7
  353. package/templates/app/packages/contracts/package.json +1 -1
  354. package/templates/app/packages/contracts/src/{dept.ts → aggregates/dept/index.ts} +11 -11
  355. package/templates/app/packages/contracts/src/{inventory.ts → aggregates/inventory/index.ts} +6 -6
  356. package/templates/app/packages/contracts/src/{inventory-lock.ts → aggregates/inventory-lock/index.ts} +5 -5
  357. package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +86 -0
  358. package/templates/app/packages/contracts/src/{role.ts → aggregates/role/index.ts} +16 -16
  359. package/templates/app/packages/contracts/src/aggregates/user/index.ts +89 -0
  360. package/templates/app/packages/contracts/src/index.ts +20 -14
  361. package/templates/app/packages/contracts/src/{queries.ts → queries/index.ts} +2 -2
  362. package/templates/app/packages/domain/package.json +5 -4
  363. package/templates/app/packages/domain/src/index.ts +8 -7
  364. package/templates/app/packages/domain/src/{erp.ts → integrations/erp.ts} +16 -1
  365. package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
  366. package/templates/app/packages/domain/src/modules/inventory/index.ts +3 -0
  367. package/templates/app/packages/domain/src/{inventory.ts → modules/inventory/inventory.ts} +12 -0
  368. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +39 -0
  369. package/templates/app/packages/domain/src/modules/purchase/index.ts +7 -0
  370. package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
  371. package/templates/app/packages/domain/src/{jobs.ts → modules/purchase/jobs.ts} +5 -0
  372. package/templates/app/packages/domain/src/{purchase-order.test.ts → modules/purchase/purchase-order.test.ts} +11 -2
  373. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +192 -0
  374. package/templates/app/packages/domain/src/{queries.ts → modules/purchase/queries.ts} +5 -0
  375. package/templates/app/packages/domain/src/{reactions.ts → workflows/purchase-inventory.ts} +8 -2
  376. package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
  377. package/templates/blank/.dockerignore +12 -0
  378. package/templates/blank/.env.example +71 -0
  379. package/templates/blank/.github/workflows/cage.yml +44 -0
  380. package/templates/blank/AGENTS.md +136 -0
  381. package/templates/blank/Dockerfile +25 -0
  382. package/templates/blank/README.md +40 -0
  383. package/templates/blank/_gitignore +9 -0
  384. package/templates/blank/apps/api/package.json +15 -0
  385. package/templates/blank/apps/api/src/main.ts +14 -0
  386. package/templates/blank/apps/api/src/worker.ts +10 -0
  387. package/templates/blank/apps/api/tsconfig.json +5 -0
  388. package/templates/blank/apps/web/index.html +14 -0
  389. package/templates/blank/apps/web/package.json +26 -0
  390. package/templates/blank/apps/web/src/app/app.tsx +106 -0
  391. package/templates/blank/apps/web/src/app/styles/global.css +606 -0
  392. package/templates/blank/apps/web/src/app/use-session.ts +43 -0
  393. package/templates/blank/apps/web/src/app/workspace-layout.tsx +95 -0
  394. package/templates/blank/apps/web/src/main.tsx +18 -0
  395. package/templates/blank/apps/web/src/modules/auth/index.ts +5 -0
  396. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +104 -0
  397. package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
  398. package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
  399. package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
  400. package/templates/blank/apps/web/src/modules/workspace/index.ts +5 -0
  401. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +62 -0
  402. package/templates/blank/apps/web/src/shared/lib/error-message.ts +22 -0
  403. package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
  404. package/templates/blank/apps/web/src/shared/ui/brand.tsx +19 -0
  405. package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
  406. package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
  407. package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
  408. package/templates/blank/apps/web/tsconfig.json +11 -0
  409. package/templates/blank/apps/web/vite.config.ts +24 -0
  410. package/templates/blank/cage.config.json +14 -0
  411. package/templates/blank/db/migrations/0001_init.sql +63 -0
  412. package/templates/blank/deploy/nginx.conf +52 -0
  413. package/templates/blank/docs/ai/README.md +98 -0
  414. package/templates/blank/docs/ai/architecture.md +148 -0
  415. package/templates/blank/docs/ai/commenting.md +203 -0
  416. package/templates/blank/docs/ai/diagnostics.md +80 -0
  417. package/templates/blank/docs/ai/files.md +93 -0
  418. package/templates/blank/docs/ai/intelligence.md +348 -0
  419. package/templates/blank/docs/ai/ontology-context.md +172 -0
  420. package/templates/blank/docs/ai/primitives.md +282 -0
  421. package/templates/blank/docs/ai/project-structure.md +128 -0
  422. package/templates/blank/docs/ai/purchase-example.md +111 -0
  423. package/templates/blank/docs/ai/recipes.md +89 -0
  424. package/templates/blank/docs/ai/relations.md +160 -0
  425. package/templates/blank/docs/ai/routing.md +86 -0
  426. package/templates/blank/docs/ai/transfers.md +92 -0
  427. package/templates/blank/docs/ai/troubleshooting.md +65 -0
  428. package/templates/blank/docs/ai/workflow.md +152 -0
  429. package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
  430. package/templates/blank/docs/errors/CAGE-APPR-001.md +48 -0
  431. package/templates/blank/docs/errors/CAGE-APPR-002.md +47 -0
  432. package/templates/blank/docs/errors/CAGE-APPR-003.md +47 -0
  433. package/templates/blank/docs/errors/CAGE-APPR-004.md +47 -0
  434. package/templates/blank/docs/errors/CAGE-APPR-005.md +47 -0
  435. package/templates/blank/docs/errors/CAGE-APPR-006.md +53 -0
  436. package/templates/blank/docs/errors/CAGE-APPR-007.md +50 -0
  437. package/templates/blank/docs/errors/CAGE-APPR-010.md +48 -0
  438. package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
  439. package/templates/blank/docs/errors/CAGE-AUTH-001.md +47 -0
  440. package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
  441. package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
  442. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +47 -0
  443. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +47 -0
  444. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +47 -0
  445. package/templates/blank/docs/errors/CAGE-CMD-002.md +47 -0
  446. package/templates/blank/docs/errors/CAGE-CMD-003.md +47 -0
  447. package/templates/blank/docs/errors/CAGE-CONN-001.md +47 -0
  448. package/templates/blank/docs/errors/CAGE-CONN-002.md +47 -0
  449. package/templates/blank/docs/errors/CAGE-CONN-003.md +47 -0
  450. package/templates/blank/docs/errors/CAGE-CONN-004.md +47 -0
  451. package/templates/blank/docs/errors/CAGE-CONN-005.md +47 -0
  452. package/templates/blank/docs/errors/CAGE-CONN-006.md +47 -0
  453. package/templates/blank/docs/errors/CAGE-CONN-007.md +47 -0
  454. package/templates/blank/docs/errors/CAGE-CONN-008.md +47 -0
  455. package/templates/blank/docs/errors/CAGE-CONN-009.md +47 -0
  456. package/templates/blank/docs/errors/CAGE-CONN-010.md +47 -0
  457. package/templates/blank/docs/errors/CAGE-CONN-011.md +47 -0
  458. package/templates/blank/docs/errors/CAGE-CONN-012.md +47 -0
  459. package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
  460. package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
  461. package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
  462. package/templates/blank/docs/errors/CAGE-CREATE-001.md +53 -0
  463. package/templates/blank/docs/errors/CAGE-DECL-001.md +48 -0
  464. package/templates/blank/docs/errors/CAGE-DECL-002.md +48 -0
  465. package/templates/blank/docs/errors/CAGE-DECL-003.md +47 -0
  466. package/templates/blank/docs/errors/CAGE-DECL-004.md +47 -0
  467. package/templates/blank/docs/errors/CAGE-DEP-001.md +48 -0
  468. package/templates/blank/docs/errors/CAGE-DEP-002.md +47 -0
  469. package/templates/blank/docs/errors/CAGE-DEP-003.md +47 -0
  470. package/templates/blank/docs/errors/CAGE-DEP-004.md +47 -0
  471. package/templates/blank/docs/errors/CAGE-DEP-005.md +47 -0
  472. package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
  473. package/templates/blank/docs/errors/CAGE-DLQ-001.md +48 -0
  474. package/templates/blank/docs/errors/CAGE-ENV-001.md +52 -0
  475. package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
  476. package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
  477. package/templates/blank/docs/errors/CAGE-EVENT-001.md +47 -0
  478. package/templates/blank/docs/errors/CAGE-EVENT-002.md +50 -0
  479. package/templates/blank/docs/errors/CAGE-FIELD-001.md +47 -0
  480. package/templates/blank/docs/errors/CAGE-FIELD-002.md +47 -0
  481. package/templates/blank/docs/errors/CAGE-FIELD-003.md +47 -0
  482. package/templates/blank/docs/errors/CAGE-FIELD-004.md +47 -0
  483. package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
  484. package/templates/blank/docs/errors/CAGE-GEN-001.md +48 -0
  485. package/templates/blank/docs/errors/CAGE-GEN-002.md +47 -0
  486. package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
  487. package/templates/blank/docs/errors/CAGE-GRANT-001.md +49 -0
  488. package/templates/blank/docs/errors/CAGE-GRANT-002.md +48 -0
  489. package/templates/blank/docs/errors/CAGE-GRANT-003.md +48 -0
  490. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +48 -0
  491. package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
  492. package/templates/blank/docs/errors/CAGE-INIT-001.md +47 -0
  493. package/templates/blank/docs/errors/CAGE-INIT-002.md +49 -0
  494. package/templates/blank/docs/errors/CAGE-INIT-003.md +48 -0
  495. package/templates/blank/docs/errors/CAGE-INIT-004.md +48 -0
  496. package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
  497. package/templates/blank/docs/errors/CAGE-JOB-001.md +47 -0
  498. package/templates/blank/docs/errors/CAGE-JOB-002.md +47 -0
  499. package/templates/blank/docs/errors/CAGE-JOB-003.md +47 -0
  500. package/templates/blank/docs/errors/CAGE-LINT-001.md +47 -0
  501. package/templates/blank/docs/errors/CAGE-MIG-001.md +47 -0
  502. package/templates/blank/docs/errors/CAGE-MIG-002.md +47 -0
  503. package/templates/blank/docs/errors/CAGE-MIG-003.md +5 -0
  504. package/templates/blank/docs/errors/CAGE-MIG-004.md +5 -0
  505. package/templates/blank/docs/errors/CAGE-MIG-005.md +47 -0
  506. package/templates/blank/docs/errors/CAGE-NAME-001.md +47 -0
  507. package/templates/blank/docs/errors/CAGE-NAME-002.md +47 -0
  508. package/templates/blank/docs/errors/CAGE-NAME-003.md +47 -0
  509. package/templates/blank/docs/errors/CAGE-NAME-004.md +47 -0
  510. package/templates/blank/docs/errors/CAGE-NAME-005.md +47 -0
  511. package/templates/blank/docs/errors/CAGE-NAME-006.md +47 -0
  512. package/templates/blank/docs/errors/CAGE-ORG-001.md +50 -0
  513. package/templates/blank/docs/errors/CAGE-PAIR-002.md +51 -0
  514. package/templates/blank/docs/errors/CAGE-QUERY-001.md +47 -0
  515. package/templates/blank/docs/errors/CAGE-QUERY-002.md +47 -0
  516. package/templates/blank/docs/errors/CAGE-QUERY-003.md +50 -0
  517. package/templates/blank/docs/errors/CAGE-REACT-001.md +47 -0
  518. package/templates/blank/docs/errors/CAGE-REACT-002.md +47 -0
  519. package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
  520. package/templates/blank/docs/errors/CAGE-READS-001.md +50 -0
  521. package/templates/blank/docs/errors/CAGE-REG-001.md +54 -0
  522. package/templates/blank/docs/errors/CAGE-REG-002.md +49 -0
  523. package/templates/blank/docs/errors/CAGE-REG-003.md +47 -0
  524. package/templates/blank/docs/errors/CAGE-REL-001.md +64 -0
  525. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +48 -0
  526. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +47 -0
  527. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +47 -0
  528. package/templates/blank/docs/errors/CAGE-SECRET-001.md +48 -0
  529. package/templates/blank/docs/errors/CAGE-SECRET-002.md +47 -0
  530. package/templates/blank/docs/errors/CAGE-SENS-001.md +48 -0
  531. package/templates/blank/docs/errors/CAGE-SQL-001.md +47 -0
  532. package/templates/blank/docs/errors/CAGE-SQL-002.md +47 -0
  533. package/templates/blank/docs/errors/CAGE-STATE-001.md +49 -0
  534. package/templates/blank/docs/errors/CAGE-STATE-002.md +47 -0
  535. package/templates/blank/docs/errors/CAGE-STATE-003.md +47 -0
  536. package/templates/blank/docs/errors/CAGE-STATE-004.md +47 -0
  537. package/templates/blank/docs/errors/CAGE-STATE-005.md +49 -0
  538. package/templates/blank/docs/errors/CAGE-STATE-010.md +48 -0
  539. package/templates/blank/docs/errors/CAGE-STATE-011.md +48 -0
  540. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +51 -0
  541. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +51 -0
  542. package/templates/blank/docs/errors/CAGE-SYNC-001.md +49 -0
  543. package/templates/blank/docs/errors/CAGE-TEST-001.md +47 -0
  544. package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
  545. package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
  546. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +49 -0
  547. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +48 -0
  548. package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
  549. package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
  550. package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
  551. package/templates/blank/docs/errors/README.md +357 -0
  552. package/templates/blank/docs/errors/runtime.md +50 -0
  553. package/templates/blank/docs/examples/purchase-admin/README.md +5 -0
  554. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +14 -0
  555. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +17 -0
  556. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +128 -0
  557. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +743 -0
  558. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
  559. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +109 -0
  560. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +18 -0
  561. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +31 -0
  562. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +6 -0
  563. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +73 -0
  564. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +5 -0
  565. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +71 -0
  566. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +5 -0
  567. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +102 -0
  568. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
  569. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  570. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  571. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  572. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +82 -0
  573. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +7 -0
  574. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  575. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
  576. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
  577. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +240 -0
  578. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
  579. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  580. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +42 -0
  581. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +24 -0
  582. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
  583. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  584. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
  585. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  586. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  587. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
  588. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  589. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +20 -0
  590. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +35 -0
  591. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
  592. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
  593. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
  594. package/templates/blank/docs/examples/purchase-admin/cage.config.json +123 -0
  595. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +74 -0
  596. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +57 -0
  597. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
  598. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +86 -0
  599. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +85 -0
  600. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +89 -0
  601. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +87 -0
  602. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +17 -0
  603. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +10 -0
  604. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +51 -0
  605. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
  606. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +3 -0
  607. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +55 -0
  608. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +39 -0
  609. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +7 -0
  610. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
  611. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +18 -0
  612. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +146 -0
  613. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +192 -0
  614. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +15 -0
  615. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +30 -0
  616. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
  617. package/templates/blank/package.json +22 -0
  618. package/templates/blank/packages/contracts/package.json +16 -0
  619. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +74 -0
  620. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +85 -0
  621. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +89 -0
  622. package/templates/blank/packages/contracts/src/index.ts +55 -0
  623. package/templates/blank/packages/contracts/src/queries/index.ts +13 -0
  624. package/templates/blank/packages/contracts/tsconfig.json +5 -0
  625. package/templates/blank/packages/domain/package.json +24 -0
  626. package/templates/blank/packages/domain/src/index.ts +5 -0
  627. package/templates/blank/packages/domain/tsconfig.json +5 -0
  628. package/templates/blank/pnpm-workspace.yaml +10 -0
  629. package/templates/blank/renovate.json +5 -0
  630. package/templates/blank/tsconfig.base.json +8 -0
  631. package/dist/database.d.ts +0 -5
  632. package/dist/database.js +0 -70
  633. package/dist/database.js.map +0 -1
  634. package/managed/errors/CAGE-APPR-001.md +0 -32
  635. package/managed/errors/CAGE-APPR-002.md +0 -32
  636. package/managed/errors/CAGE-APPR-003.md +0 -32
  637. package/managed/errors/CAGE-APPR-004.md +0 -32
  638. package/managed/errors/CAGE-APPR-005.md +0 -32
  639. package/managed/errors/CAGE-APPR-006.md +0 -32
  640. package/managed/errors/CAGE-APPR-007.md +0 -32
  641. package/managed/errors/CAGE-APPR-010.md +0 -32
  642. package/managed/errors/CAGE-AUTH-001.md +0 -32
  643. package/managed/errors/CAGE-BUDGET-001.md +0 -32
  644. package/managed/errors/CAGE-BUDGET-002.md +0 -32
  645. package/managed/errors/CAGE-BUDGET-003.md +0 -32
  646. package/managed/errors/CAGE-CMD-002.md +0 -32
  647. package/managed/errors/CAGE-CMD-003.md +0 -34
  648. package/managed/errors/CAGE-CONN-001.md +0 -32
  649. package/managed/errors/CAGE-CONN-002.md +0 -32
  650. package/managed/errors/CAGE-CONN-003.md +0 -32
  651. package/managed/errors/CAGE-CONN-004.md +0 -32
  652. package/managed/errors/CAGE-CONN-005.md +0 -32
  653. package/managed/errors/CAGE-CONN-006.md +0 -32
  654. package/managed/errors/CAGE-CONN-007.md +0 -32
  655. package/managed/errors/CAGE-CONN-008.md +0 -32
  656. package/managed/errors/CAGE-CONN-009.md +0 -32
  657. package/managed/errors/CAGE-CONN-010.md +0 -32
  658. package/managed/errors/CAGE-CONN-011.md +0 -32
  659. package/managed/errors/CAGE-CONN-012.md +0 -32
  660. package/managed/errors/CAGE-CREATE-001.md +0 -32
  661. package/managed/errors/CAGE-DECL-001.md +0 -34
  662. package/managed/errors/CAGE-DECL-002.md +0 -34
  663. package/managed/errors/CAGE-DECL-003.md +0 -34
  664. package/managed/errors/CAGE-DECL-004.md +0 -34
  665. package/managed/errors/CAGE-DEP-001.md +0 -34
  666. package/managed/errors/CAGE-DEP-002.md +0 -34
  667. package/managed/errors/CAGE-DEP-003.md +0 -34
  668. package/managed/errors/CAGE-DEP-004.md +0 -34
  669. package/managed/errors/CAGE-DEP-005.md +0 -34
  670. package/managed/errors/CAGE-DLQ-001.md +0 -32
  671. package/managed/errors/CAGE-ENV-001.md +0 -32
  672. package/managed/errors/CAGE-EVENT-001.md +0 -32
  673. package/managed/errors/CAGE-EVENT-002.md +0 -32
  674. package/managed/errors/CAGE-FIELD-001.md +0 -32
  675. package/managed/errors/CAGE-FIELD-002.md +0 -32
  676. package/managed/errors/CAGE-FIELD-003.md +0 -32
  677. package/managed/errors/CAGE-FIELD-004.md +0 -32
  678. package/managed/errors/CAGE-GEN-001.md +0 -33
  679. package/managed/errors/CAGE-GEN-002.md +0 -33
  680. package/managed/errors/CAGE-GRANT-001.md +0 -32
  681. package/managed/errors/CAGE-GRANT-002.md +0 -32
  682. package/managed/errors/CAGE-GRANT-003.md +0 -32
  683. package/managed/errors/CAGE-IMPACT-001.md +0 -32
  684. package/managed/errors/CAGE-JOB-001.md +0 -32
  685. package/managed/errors/CAGE-JOB-002.md +0 -32
  686. package/managed/errors/CAGE-JOB-003.md +0 -32
  687. package/managed/errors/CAGE-LINT-001.md +0 -32
  688. package/managed/errors/CAGE-MIG-001.md +0 -32
  689. package/managed/errors/CAGE-MIG-002.md +0 -32
  690. package/managed/errors/CAGE-MIG-003.md +0 -32
  691. package/managed/errors/CAGE-MIG-004.md +0 -32
  692. package/managed/errors/CAGE-MIG-005.md +0 -32
  693. package/managed/errors/CAGE-NAME-001.md +0 -32
  694. package/managed/errors/CAGE-NAME-002.md +0 -32
  695. package/managed/errors/CAGE-NAME-003.md +0 -32
  696. package/managed/errors/CAGE-NAME-004.md +0 -32
  697. package/managed/errors/CAGE-NAME-005.md +0 -32
  698. package/managed/errors/CAGE-NAME-006.md +0 -32
  699. package/managed/errors/CAGE-ORG-001.md +0 -32
  700. package/managed/errors/CAGE-PAIR-002.md +0 -33
  701. package/managed/errors/CAGE-QUERY-001.md +0 -32
  702. package/managed/errors/CAGE-QUERY-002.md +0 -32
  703. package/managed/errors/CAGE-QUERY-003.md +0 -32
  704. package/managed/errors/CAGE-REACT-001.md +0 -32
  705. package/managed/errors/CAGE-REACT-002.md +0 -32
  706. package/managed/errors/CAGE-READS-001.md +0 -32
  707. package/managed/errors/CAGE-REG-001.md +0 -32
  708. package/managed/errors/CAGE-REG-002.md +0 -32
  709. package/managed/errors/CAGE-REG-003.md +0 -32
  710. package/managed/errors/CAGE-ROUTE-001.md +0 -32
  711. package/managed/errors/CAGE-SCOPE-001.md +0 -32
  712. package/managed/errors/CAGE-SCOPE-002.md +0 -32
  713. package/managed/errors/CAGE-SECRET-001.md +0 -32
  714. package/managed/errors/CAGE-SECRET-002.md +0 -32
  715. package/managed/errors/CAGE-SENS-001.md +0 -32
  716. package/managed/errors/CAGE-SQL-001.md +0 -32
  717. package/managed/errors/CAGE-SQL-002.md +0 -32
  718. package/managed/errors/CAGE-STATE-001.md +0 -32
  719. package/managed/errors/CAGE-STATE-002.md +0 -32
  720. package/managed/errors/CAGE-STATE-003.md +0 -32
  721. package/managed/errors/CAGE-STATE-004.md +0 -32
  722. package/managed/errors/CAGE-STATE-005.md +0 -32
  723. package/managed/errors/CAGE-STATE-010.md +0 -32
  724. package/managed/errors/CAGE-STATE-011.md +0 -32
  725. package/managed/errors/CAGE-SYNC-001.md +0 -35
  726. package/managed/errors/CAGE-TEST-001.md +0 -33
  727. package/managed/errors/CAGE-UNSAFE-001.md +0 -32
  728. package/managed/errors/CAGE-UPGRADE-001.md +0 -32
  729. package/managed/errors/README.md +0 -99
  730. package/templates/app/compose.yaml +0 -39
  731. package/templates/app/packages/contracts/src/purchase-order.ts +0 -72
  732. package/templates/app/packages/contracts/src/user.ts +0 -89
  733. package/templates/app/packages/domain/src/approvals.ts +0 -18
  734. package/templates/app/packages/domain/src/purchase-order.ts +0 -122
@@ -0,0 +1,160 @@
1
+ # 业务对象之间的关系
2
+
3
+ [返回学习入口](README.md) · [最小业务](primitives.md) · [开发步骤](workflow.md)
4
+
5
+ 关系和普通属性统一写在 `aggregate(...).fields` 中。业务不需要另写 `relations` 区块,也不用为单纯“便笺与用户的关联”创建 `NoteMember` 聚合。
6
+
7
+ ## 选择哪一种声明
8
+
9
+ | 业务含义 | fields 中的写法 | 数据库如何保存 | 如何修改 |
10
+ | --- | --- | --- | --- |
11
+ | 多条便笺属于同一部门(多对一) | `deptId: ref('Dept')` | 本表 UUID 外键列 | 所属对象的命令 |
12
+ | 一个目标在租户内最多被引用一次(至多一对一) | `reviewerId: ref('User').unique().optional()` | 外键列 + `(tenant_id, reviewer_id)` 唯一索引 | 所属对象的命令;重复引用返回 CONFLICT |
13
+ | 一条便笺有多条评论(一对多) | `comments: hasMany('NoteComment', { mappedBy: 'noteId' })` | 外键在评论表的 `noteId: ref('Note')` 上;父表不增加列 | 评论自己的创建/归属命令;父字段只读 |
14
+ | 便笺有多个协作人,一个人也能协作多条便笺(多对多) | `members: manyToMany('User', { description: '协作成员' })` | 框架生成中间表、同租户复合外键和组合主键 | 所属便笺的命令返回目标 ID 数组 |
15
+ | 一张单据内的 JSON 明细 | `items: list({ sku: text(), qty: int() })` | 主表 JSONB 列 | 所属对象的命令;它不是对象关联 |
16
+
17
+ `ref().unique()` 表达“至多一个”,不强制目标一定被引用,也不自动创建目标。多对一的每个来源只有一个外键,但多个来源可以填同一目标 ID。一对多需要目标本来就是有业务含义的对象,例如评论、订单行;这种业务对象有自己的字段和命令。
18
+
19
+ `hasMany` 和 `manyToMany` 是集合关系,不支持 `.optional()`、`.unique()`、`.hidden()` 或 `.sensitive()`。没有关联使用空集合;目标对象的敏感属性由目标自身的权限掩码。可以使用 `.describe()`,也可以在工厂选项中写 `description`。关系不能嵌进 `list`、事件载荷或作为 scope 的部门/创建人字段;事件需要 ID 数组时使用 `list(id())`。
20
+
21
+ ## 完整领域例子
22
+
23
+ 下面可作为 `packages/domain/src/modules/note/note.ts`。它是[最小便笺](primitives.md)的关系版本,按需要替换原文件,避免重复声明 Note。
24
+
25
+ ```ts
26
+ import {
27
+ aggregate, command, fail, hasMany, manyToMany, ref, scope, states, text,
28
+ } from '@yss123/cage-kernel';
29
+ import { z } from 'zod';
30
+
31
+ export const Note = aggregate('Note', {
32
+ description: '部门便笺',
33
+ fields: {
34
+ title: text(120),
35
+ deptId: ref('Dept'),
36
+ createdBy: ref('User'),
37
+ // 这是 ID 集合。框架负责物理中间表、约束、关联写入和事务。
38
+ members: manyToMany('User', { description: '协作成员' }),
39
+ // 从评论上的 noteId 反查;这不是一份可写的评论 ID 数组。
40
+ comments: hasMany('NoteComment', { mappedBy: 'noteId', description: '便笺评论' }),
41
+ },
42
+ states: states('active', 'archived', { terminal: ['archived'] }),
43
+ scope: scope.deptSubtree('deptId'),
44
+ invariants: { titleNotBlank: (note) => note.title.trim().length > 0 },
45
+ });
46
+
47
+ export const NoteComment = aggregate('NoteComment', {
48
+ description: '便笺评论',
49
+ fields: {
50
+ noteId: ref('Note'),
51
+ body: text(2000),
52
+ deptId: ref('Dept'),
53
+ createdBy: ref('User'),
54
+ },
55
+ scope: scope.deptSubtree('deptId'),
56
+ });
57
+
58
+ export const createNote = command(Note, {
59
+ name: 'create', from: 'new', to: 'active',
60
+ input: z.object({
61
+ title: z.string().trim().min(1).max(120),
62
+ members: z.array(z.string().uuid()).optional(),
63
+ }),
64
+ // members 不传时由内核初始化为 [];部门与创建人仍按当前身份填入。
65
+ handler: (draft) => draft,
66
+ });
67
+
68
+ export const setNoteMembers = command(Note, {
69
+ name: 'setMembers', from: 'active', to: null,
70
+ input: z.object({ id: z.string().uuid(), members: z.array(z.string().uuid()) }),
71
+ // 完整替换集合;[] 表示全部解绑。只改关系也会递增便笺版本并写审计。
72
+ handler: (_draft, input) => ({ members: input.members }),
73
+ });
74
+
75
+ export const addNoteMembers = command(Note, {
76
+ name: 'addMembers', from: 'active', to: null,
77
+ input: z.object({ id: z.string().uuid(), memberIds: z.array(z.string().uuid()) }),
78
+ // 草稿包含完整的既有关联。增量追加可以保留当前操作者看不到的旧成员。
79
+ // 数组去重与排序由框架统一处理,业务不再维护第二套集合规范化。
80
+ handler: (draft, input) => ({ members: [...draft.members, ...input.memberIds] }),
81
+ });
82
+
83
+ export const createNoteComment = command(NoteComment, {
84
+ name: 'create', from: 'new', to: 'active', reads: { notes: Note },
85
+ input: z.object({ noteId: z.string().uuid(), body: z.string().trim().min(1).max(2000) }),
86
+ handler: async (_draft, input, { notes }) => {
87
+ const note = await notes.get(input.noteId);
88
+ if (!note) return fail('NOTE_NOT_AVAILABLE');
89
+ if (note.status !== 'active') return fail('NOTE_ARCHIVED');
90
+ // 这是“评论沿用便笺部门”的业务规则,必须显式表达,框架不猜测所属关系。
91
+ return { noteId: note.id, body: input.body, deptId: note.deptId };
92
+ },
93
+ });
94
+ ```
95
+
96
+ 在 `modules/note/index.ts` 写 `export * from './note.js';`,再从 domain 的 `index.ts` 保留组织模型及已有模块,导出新模块:
97
+
98
+ ```ts
99
+ export * from '@yss123/cage-admin/domain';
100
+ export * from './modules/note/index.js';
101
+ ```
102
+
103
+ 不写双向对象导入时,可用目标聚合名字符串解决循环引用。`mappedBy` 填**目标字段的 TypeScript 名称**,例如 `noteId`;不能填 SQL 列名 `note_id`、目标表名或普通文本字段。目标 ref 需要公开且非敏感,关系接口才能通过目标安全视图反查。
104
+
105
+ ## 页面如何使用
106
+
107
+ `pnpm gen` 后,生成契约会有以下方法。命令与列表方法的结果仍是 `CageResult`,页面按 `ok/code/domainCode` 处理:
108
+
109
+ ```ts
110
+ import {
111
+ note, noteComment, useNoteRelatedMembers, useNoteRelatedComments,
112
+ } from '@app/contracts';
113
+
114
+ // 命令修改关系,第三个参数为详情上看到的版本号,过期版本返回 CONFLICT。
115
+ const changed = await note.setMembers(noteId, { members: selectedUserIds }, version);
116
+ // 目标是评论对象,不给 hasMany 赋值。
117
+ const comment = await noteComment.create({ noteId, body: '已确认需求' });
118
+
119
+ // 与普通列表一样支持目标字段筛选、分页、排序,单页最多 200 条。
120
+ const members = await note.related.members(noteId, { page: 1, pageSize: 20 });
121
+ const comments = await note.related.comments(noteId, { page: 1, sort: '-createdAt' });
122
+
123
+ // React 组件内使用;没有选中 ID 时 hook 不发请求。
124
+ const memberQuery = useNoteRelatedMembers(noteId, { page: 1 });
125
+ const commentQuery = useNoteRelatedComments(noteId, { page: 1 });
126
+ ```
127
+
128
+ 上面的 `noteId/selectedUserIds/version` 来自页面的实际选择与详情数据;hook 在 React 组件或自定义 hook 内调用。保存成功后让相关缓存失效,例如 `queryClient.invalidateQueries({ queryKey: ['note', noteId] })`;新增评论还应更新评论列表。框架不自动推断所有跨对象缓存依赖。
129
+
130
+ 自动接口为:
131
+
132
+ ```text
133
+ GET /api/note/:id/relations/members
134
+ GET /api/note/:id/relations/comments
135
+ ```
136
+
137
+ 响应是 `{ items, total, page, pageSize }`,items 为**目标对象**的普通快照。`note.get/list` 和命令响应不自动展开成员、评论或完整 ID 集合,避免普通详情无限加载与绕过目标权限。生成的普通 Note 类型也不包含虚拟关系;不能从 `note.get()` 中直接读取 `members`。
138
+
139
+ ## 权限与事务
140
+
141
+ - 修改成员需要 `Note.setMembers` 或对应增量命令能力,以及便笺范围。新增的用户还必须在调用人的 User 范围内,真人调用需要 `User.read`;范围外或其他租户目标返回 NOT_FOUND,缺能力返回 FORBIDDEN。
142
+ - 读取成员需要 `Note.read` 和 `User.read`;读取评论需要 `Note.read` 和 `NoteComment.read`。所属对象不可见返回 NOT_FOUND;目标范围外的数据不计入 items/total。目标敏感字段按其 unmask 能力返回掩码或明文。
143
+ - 角色需要分别配置 Note、NoteComment 和 User 的实际数据范围;`hasMany` 不会自动让父对象可见的人看到所有子对象,关系声明本身也不会授予能力。
144
+ - 多对多是无序集合。框架统一 UUID 大小写、去重和排序;关联表不保存排列顺序。主表版本、关系增删、审计、outbox 和同事务反应共同提交或回滚。
145
+ - 只校验本次新增的目标。某个旧成员后来变为不可见时,只修改标题仍保留其关联;公开分页只返回当前可见目标。页面不能把某一页或可见子集当作完整集合传给 setMembers,否则会解绑未列出的成员;需要保留时使用增量命令。
146
+ - `hasMany` 不出现在可写草稿中。输入或 handler 给它赋值会返回 INVALID_INPUT。子对象跨范围或跨租户归属的业务规则要在子命令/约束中明确校验;普通 ref 的行为保持不变,不会继承 manyToMany 的新增目标可见性检查。
147
+
148
+ ## 迁移、图谱与边界
149
+
150
+ 第一次声明 `members` 后执行 `pnpm gen`,会生成 `core.note__members` 草稿。表只保存 `tenant_id/source_id/target_id`,以三列组合主键避免重复;两侧 `(tenant_id, id)` 唯一键与复合外键保证同租户。解绑只删链接,不删除 User;硬删除来源时数据库级联清链接,硬删除被引用目标时外键拒绝。
151
+
152
+ 关系表不注册为业务聚合,不增加独立 CRUD、状态机、审批或角色能力点。`hasMany` 本身不产生新表,只复用目标 ref 已有外键与索引。权限读取通过 `safe.note__members` 和两侧安全视图;业务项目不直接写这些表。
153
+
154
+ 按项目流程运行 `pnpm exec cage check`、`pnpm gen`,审查后 `pnpm migrate`;不要编辑已执行迁移,不会为关系另建一个数据库。删除关系声明后迁移只提示收缩,不自动删除已有链接数据。改变目标类型、把旧 JSON 数组改为关系等操作需要专门的数据迁移;框架不会猜测如何转换历史数据。
155
+
156
+ `pnpm exec cage graph` 的对象卡片将它们标为“一对多 / 多对多”,集合关系不显示主表列的必填星号。点击连线可看 1:N、N:M、mappedBy 外键位置、中间表名称,以及为什么连接、读写方式。
157
+
158
+ 当前每个 `manyToMany` 字段拥有自己的关系。两边各写一次会生成**两份独立关联**,不会自动成为互为镜像的双向关系;本版没有 manyToMany 的 inverse/mappedBy 选项。需要反向统计时声明 query,列出双方 reads 并查询安全视图。自关联可写 `manyToMany('Note')`,仍是有方向的集合,A 关联 B 不会自动使 B 关联 A。
159
+
160
+ 如果链接本身有职位、参与时间、分摊比例、审批状态等业务属性,它已是有意义的业务对象,应建如“项目任职”的聚合并定义自己的命令,而不是把这些属性塞进自动中间表。关系字段的职责是表达单纯关联。
@@ -0,0 +1,86 @@
1
+ # 业务前端路由与浏览器验收
2
+
3
+ [返回学习入口](README.md) · [工程目录](project-structure.md) · [开发步骤](workflow.md)
4
+
5
+ 多页面业务默认使用 React Router 的 BrowserRouter。列表、详情、报表等可独立访问的页面必须有 URL;在 app 中统一组合路由和工作台布局,页面从模块 index.ts 导出。useState 用于弹窗、未提交表单和按钮忙碌状态。筛选、分页和需要分享的选项使用 useSearchParams。
6
+
7
+ 本页对应后续开发版本的模板改进;已发布的 0.2.0 项目需要按本页迁入路由实现,不能只升级依赖就认为旧页面已完成改造。框架包无需维护客户的页面地址。
8
+
9
+ ## 模板中的可运行示例
10
+
11
+ | 页面 | 空白模板 | 采购模板 |
12
+ | --- | --- | --- |
13
+ | 登录 | `/login` | `/login` |
14
+ | 工作台 | `/workspace` | `/workspace` |
15
+ | 列表 | `/directory/users?page=2` | `/procurement/orders?status=draft&page=2` |
16
+ | 详情 | `/directory/users/:id` | `/procurement/orders/:id` |
17
+ | 其他业务 | 按实际需求新增 | `/inventory`、`/approvals` |
18
+ | 404 | 未匹配页面显示“页面不存在” | 同左 |
19
+
20
+ `:id` 替换成真实记录 ID。空白模板的成员目录读取已有 User 组织模型,不注册额外业务、演示表或虚假数据;列表与详情均需要 User.read,数据范围由安全接口落实。采购待办的 businessKey 由 app 映射成采购详情链接,审批模块不直接导入采购模块。
21
+
22
+ 在应用根目录运行 pnpm dev 后访问终端打印的 Web 地址。先在系统管理配置真实账号与权限,再从列表复制某条记录的详情 URL,用于刷新和新标签页测试。
23
+
24
+ ## 新增一项业务页面
25
+
26
+ 1. 在 `apps/web/src/modules/<业务>/pages` 编写列表、详情和表单,从模块 index.ts 导出。详情用 useParams 读取 ID,再用生成的 use对象(id) 获取记录;不要求先打开列表,也不从组件状态或上一页传来的对象直接认定记录存在。
27
+ 2. 在 `apps/web/src/app/app.tsx` 注册列表与详情 Route。放在已有会话守卫和 WorkspaceLayout 之下,使页面通过 Outlet 渲染。新增实际页面时扩展路由表;不要再添加 tab/page useState 来选择整页。
28
+ 3. 导航使用 Link / NavLink;完整页面地址可收藏、复制或新标签页打开。列表筛选和分页通过 useSearchParams 更新,刷新和前进后退恢复相应查询。
29
+ 4. 需要 read 能力的页面用共享 RequireCapability 提供直接访问时的提示;服务端返回 FORBIDDEN 时显示权限提示,NOT_FOUND 显示“记录不存在,或不在当前可访问范围”。401 由会话回调进入登录。不要把 403 当成登录失效,也不要通过放宽读权限解决页面导航问题。
30
+ 5. 用下面的浏览器配方验收,并报告通过、跳过与未执行。构建和 cage verify 通过,只证明其各自检查范围,不能据此宣称路由体验正确。
31
+
32
+ ```tsx
33
+ // app 中的组合片段:页面通过所属模块的 index.ts 导出。
34
+ <Route element={<WorkspaceLayout onLogout={onLogout} />}>
35
+ <Route path="procurement/orders" element={<PurchaseOrdersPage />} />
36
+ <Route path="procurement/orders/:id" element={<PurchaseOrderDetailPage />} />
37
+ </Route>
38
+ ```
39
+
40
+ 片段只展示路由与布局关系。实际代码参考本模板 app.tsx,保留会话守卫、页面 props 和能力提示。`cage/no-manual-routes` 限制手写后端业务 HTTP 路由,不禁止 React Router;前端导航不会生成能力或授予数据访问权。
41
+
42
+ ## 登录后返回原地址
43
+
44
+ 应用启动先 loadMe 恢复会话。未登录访问详情时,守卫使用 replace 导航到 `/login?returnTo=编码后的原路径`,包含 query 和 hash。登录完成再次 replace 回原页面,避免浏览器后退反复落入登录页。
45
+
46
+ `shared/lib/navigation.ts` 的 loginReturnTo 只接受应用内页面,排除外站、登录循环及 API/admin 等服务端入口;不要直接把用户提供的任意 returnTo 交给 location.href。网络错误显示重试界面并保留地址,只有 UNAUTHENTICATED 才要求重新登录。运行中会话过期同样保存当前 URL,并清除上一账号的查询缓存。
47
+
48
+ 前端路由守卫只改善导航与提示。请求仍由 Cage HTTP 和内核检查会话、能力、租户、数据范围与掩码;直接请求接口必须得到相同约束。
49
+
50
+ ## 与系统管理及部署共存
51
+
52
+ | 路径 | 所有者 |
53
+ | --- | --- |
54
+ | `/login`、`/workspace`、客户业务页面 | React Router |
55
+ | `/admin`、`/admin/` 及其脚本/样式 | Cage 系统管理 |
56
+ | `/api/`、`/auth/`、`/hooks/` | Cage HTTP 接口 |
57
+ | `/assets/` | Vite 构建资源 |
58
+
59
+ 进入 `/admin/` 使用普通 `<a href="/admin/">`,让浏览器请求独立管理入口;应用内部页面使用 Link。不要在 React 中注册覆盖 /admin 或 /auth 的页面。Vite 配置已代理 API、认证与管理请求,开发环境支持业务深链接刷新。
60
+
61
+ 生产可选两种部署方式:
62
+
63
+ - **Cage 托管 Web**:API 启动时提供 webDir,标准入口读取 WEB_DIR;将其设置为 apps/web/dist 的绝对路径。模板 Dockerfile 已复制构建产物并设置 WEB_DIR=/app/web。浏览器 GET/HEAD 页面请求可回退到 index.html,React 决定详情或 404;API、管理和丢失资源返回各自错误,不应变成业务首页。
64
+ - **Nginx 托管 Web**:参考项目 `deploy/nginx.conf`,将 root 指向真实 dist,将 API/admin/auth/hooks 代理到 Cage;业务页面使用 try_files 回退到 index.html,/assets/ 缺失时直接 404。示例按 Nginx 与 API 在同一主机、API 端口 3000 编写;按部署拓扑修改上游。仅复制 dist 到没有 SPA 回退的静态服务器会导致详情刷新 404。
65
+
66
+ 上线前用实际反向代理地址验收深链接。Vite 开发环境成功,不代表 Nginx、CDN 或生产容器已配置正确。
67
+
68
+ ## 浏览器验收配方
69
+
70
+ 准备一条有权读取的真实记录和两个测试账号:有 read 能力及范围的账号、没有该能力的账号。测试账号和记录在独立验收环境准备,不修改生产角色。
71
+
72
+ | 操作 | 预期结果 |
73
+ | --- | --- |
74
+ | 复制列表中某条详情 URL,在新标签页粘贴 | 直接加载对应记录,无需先访问列表 |
75
+ | 在详情页刷新 | URL 和记录保持一致 |
76
+ | 列表 → 详情 → 另一页面,再点浏览器后退、前进 | 地址、页面内容与导航高亮同步变化 |
77
+ | 改变列表筛选/分页,复制地址或刷新 | 条件与列表恢复,不返回工作台或第一页 |
78
+ | 未登录打开带 query/hash 的详情 URL | 进入登录;成功后回到原 URL,保留 query/hash |
79
+ | 在业务页使测试会话过期,再触发读取 | 进入登录;重新登录后回到原页面,旧账号缓存不残留 |
80
+ | 无 read 能力账号直接访问有效详情地址 | 显示权限提示,直接请求 API 仍为 403 |
81
+ | 有 read 能力但记录位于范围外 | 显示记录不可用,直接请求 API 为 404,不泄露记录是否存在 |
82
+ | 访问不存在的业务路径 | 显示应用 404,并有返回工作台入口 |
83
+ | 访问 /admin/,以及缺失的 API/JS/CSS | 管理入口独立可用;缺失接口或资源不返回业务 index.html |
84
+ | 在实际部署地址重复深链接和刷新步骤 | 正常加载,浏览器控制台无脚本 MIME 错误 |
85
+
86
+ 验收记录写明模板、地址、操作和结果。模拟 API 的浏览器检查可以证明导航行为;真实权限、范围和数据库链路需要相应集成验收,二者分别报告。
@@ -0,0 +1,92 @@
1
+ # 在客户业务页接入导入和导出
2
+
3
+ [返回学习入口](README.md) · [开发步骤](workflow.md)
4
+
5
+ 框架提供持久化任务、CSV 处理、权限和下载接口。业务项目决定入口、列名、上传表单、任务状态与报告如何展示;不要求用户进入系统管理页,也不要求具备 Sys.ops 能力。路径中的 `/api/sys/transfers` 是通用任务接口。
6
+
7
+ 继续使用项目已有的 createServer 和 startWorker,不另写数据库连接、队列或文件服务。先审查并运行 `pnpm migrate`,同时部署 API 与 worker;只运行 API 会让任务一直等待。
8
+
9
+ ## 业务前端如何调用
10
+
11
+ 以下是业务事件处理函数,可按页面需要使用。目标导出对象与导入命令来自实际业务,不必固定为采购或库存。
12
+
13
+ ```ts
14
+ import { client, purchaseOrder } from '@app/contracts';
15
+
16
+ export async function exportApprovedOrders() {
17
+ // 同一次业务操作需要重试时,在页面保存并复用 key。
18
+ const key = crypto.randomUUID();
19
+ return purchaseOrder.export({ status: 'approved' }, { idempotencyKey: key });
20
+ }
21
+
22
+ export async function importCommandCsv(command: string, file: File, key: string) {
23
+ return client.importCsv(command, await file.text(), {
24
+ atomic: false,
25
+ idempotencyKey: key,
26
+ });
27
+ }
28
+
29
+ export async function inspectTransfer(id: string) {
30
+ const result = await client.transfer(id);
31
+ if (!result.ok) return result;
32
+ if (result.data.status !== 'completed') return result;
33
+ // 导入完成还可能有失败行,页面需展示报告中的 failed/succeeded。
34
+ if (result.data.kind === 'import') return client.importReport(id);
35
+ return client.transferDownloadUrl(id);
36
+ }
37
+ ```
38
+
39
+ 所有提交先判断 `result.ok`,再保存返回任务的 id,HTTP 202 仅表示已接受。React 可从 `@app/contracts` 引入 `useTransfer(id)`:等待、处理中和重试中每两秒刷新,完成/失败/过期停止。没有 React 时自行调用 client.transfer。
40
+
41
+ 页面返回时可用 `client.transfers('实际聚合名')` 恢复本人该对象最近任务。任务状态包括 queued、processing、retrying、completed、failed、expired;completed 的导入也可能部分失败或整批回滚,不能只按状态显示“全部成功”。
42
+
43
+ ## 导入 CSV 怎么准备
44
+
45
+ 目标命令必须已经导出、允许 user 调用、使用 Zod object 输入,并且当前用户具有对应命令能力。比如业务输入 `{ sku: string, available: number }` 的 UTF-8 CSV:
46
+
47
+ ```csv
48
+ sku,available
49
+ SKU-001,100
50
+ SKU-002,50
51
+ ```
52
+
53
+ - 表头是**命令输入字段名**,使用小驼峰,不是数据库列名或中文标题。页面可自行做中文列名映射。
54
+ - 可选列可省略;空的可选单元格表示不提供值。已有记录命令需要 id,还可提供 expectedVersion 控制乐观锁。
55
+ - 数字按数字解析,布尔使用 true/false,数组与对象写 JSON,金额按字符串输入。
56
+ - 复杂单元格仍要遵守 CSV 引号规则,例如 items 单元格可以是 `"[{""sku"":""A-01"",""qty"":1}]"`。
57
+ - 支持 BOM、CRLF、引号中的逗号/换行及双引号转义。重复/未知表头、错列和未闭合引号等文件错误会在排队前拒绝。
58
+ - 每行仍走原命令的权限、范围、状态、约束、不变量、审计、事件与同事务反应;导入不能绕过 process/external 限制。
59
+
60
+ 默认 `atomic: false`:成功行提交,失败行及其同事务反应回滚。`atomic: true`:任意行失败撤销整批业务写入,原成功行在报告中标为 ABORTED。
61
+
62
+ 报告只含记录号、ok/code/domainCode/fields,不返回原始值或命令快照。表头算第 1 条,第一条数据记录为第 2 条;带换行的引号单元格仍只算一条记录。页面用记录号帮助用户修复 CSV,不把失败文本直接拼成 HTML。
63
+
64
+ **导出文件不是导入模板。** 读侧导出包含 id/status/version 等系统列及掩码值,不能原样回写;按所选命令整理输入。
65
+
66
+ ## 接口与授权
67
+
68
+ | HTTP | 输入或结果 |
69
+ | --- | --- |
70
+ | POST `/api/{聚合短横线名}/export` | 列表筛选参数;返回 202 和任务,需要该聚合 export 能力 |
71
+ | POST `/api/sys/transfers/import` | `{ command, csv, atomic? }`,command 是 `聚合.命令` 能力标识;返回 202 和任务 |
72
+ | GET `/api/sys/transfers/options` | 本人可用的导出对象、导入命令、字段 name/required 与限制 |
73
+ | GET `/api/sys/transfers?aggregate=聚合名` | 本人最近 100 个任务,按需筛选业务对象 |
74
+ | GET `/api/sys/transfers/:id` | 本人单个任务的状态、计数及 errorCode |
75
+ | GET `/api/sys/transfers/:id/download` | 已完成导出的 CSV,或已完成导入的 JSON 报告 |
76
+
77
+ options 可用 `client.get('/api/sys/transfers/options')` 读取,没有额外假定的专用 helper。直接调用 HTTP 时,提交必须附会话、CSRF 以及 1–200 字符 Idempotency-Key;client 会处理这些协议。相同租户/用户的同键同内容返回同一任务,同键不同内容返回 CONFLICT。
78
+
79
+ 导出经过安全视图,按提交人的范围和明文权限读取。仅提交人能下载;账号停用、能力收回或范围/明文权限/部门树变化后,旧文件可能被拒绝下载,需要重新导出。系统运维权限不会自动授予他人的文件下载权。
80
+
81
+ ## 限制与排错
82
+
83
+ | 项目 | 当前限制 |
84
+ | --- | --- |
85
+ | 导入 | UTF-8 CSV,1 MiB / 1000 条数据记录 |
86
+ | 导出 | 100000 行 / 20 MiB;超限任务失败,不静默截断 |
87
+ | 导出分页参数 | page/pageSize 不限制导出范围;使用业务筛选条件缩小数据 |
88
+ | 有效期 | 提交起 24 小时,到期拒绝下载,由 worker 清理文件和结果 |
89
+ | 存储 | PostgreSQL 持久化,API 与 worker 不需要共享磁盘 |
90
+ | 暂未提供 | XLSX、对象存储、断点续传、逐行实时进度、超大文件流式导入 |
91
+
92
+ 任务一直 queued 先查 worker;failed 看 errorCode/导入报告;数据库故障耗尽重试时查原有死信链路。先修复根因再重放,别创建直接写业务表的“快速导入”接口。
@@ -0,0 +1,65 @@
1
+ # 排错方法
2
+
3
+ [返回学习入口](README.md) · [错误码册](../errors/README.md) · [HTTP 运行时错误](../errors/runtime.md)
4
+
5
+ 先保留完整诊断的 code、源码位置、reason/fix、requestId 或 outboxId。检查所在阶段,再修复原因;不要通过改业务状态、给全局权限、注释约束或禁用 lint 消除现象。
6
+
7
+ 先执行 `pnpm exec cage doctor` 查看各阶段证据;异步动作按 requestId/outboxId/业务对象用 `cage timeline` 关联实际执行记录。能力、范围、调用身份或额度不清楚时,有权诊断的管理员可使用 `cage explain`,不会执行目标命令。完整参数与权限见[诊断指南](diagnostics.md)。
8
+
9
+ ## 按现象定位
10
+
11
+ | 现象 | 先查什么 | 常见原因 |
12
+ | --- | --- | --- |
13
+ | dev 启不动 | `.env` 是否在项目根目录,数据库服务是否可连接 | 缺连接、密码/端口错误、没执行迁移、端口占用 |
14
+ | init 提示账号已存在 | CAGE-INIT-002;找已有 APP/READ/MIGRATE 连接 | 角色在 PG 集群内共享;不应覆盖原密码 |
15
+ | 新业务不出现在接口/图谱 | 顶层 export const 和 domain/index.ts | 漏导出、重名导出、放进函数/条件声明 |
16
+ | API 403 | code/detail、角色能力、调用身份、硬约束 | 能力不足、CSRF、职责分离、额度缺失/超限 |
17
+ | 详情 404 | 记录 id、租户和数据范围 | 不存在或在范围外;不能仅凭 404 断言被删除 |
18
+ | 列表为空 | read 能力、范围与相应字段 | 默认本人范围、无 owner 字段或部门不匹配 |
19
+ | 电话看不到明文 | sensitive 标注、unmask 能力 | 默认掩码是正常安全行为 |
20
+ | 有明文能力但读取报 CAGE-AUDIT-001 | requestId、审计库可用性与权限 | 可靠审计未成功,框架拒绝交付结果 |
21
+ | 生产服务拒绝启动 | CAGE-ENV-002/003、Cookie 密钥与 bootstrap 参数 | 关键配置不合格,或试图在日常启动时隐式初始化 |
22
+ | 任务时间线有 CAGE-WORKER-002 | API/worker 版本、注册指纹和消费者清单 | 旧进程或必要消费者缺失,不能把 done 当作已执行 |
23
+ | 提交成功但无待办 | worker、outbox/死信、审批路由 | 未投递、缺审批人、没有匹配的绑定/路由 |
24
+ | 已批准但 ERP 单号未回写 | worker、同步记录、死信、环境/fake | 密钥/白名单/响应错误,或异步还未完成 |
25
+ | 已取消但锁未释放 | 释放事件、反应、死信 | 先前消息阻塞、map 条件不匹配或遗漏释放 |
26
+ | 导入/导出一直 queued | worker 与任务详情 | 后台进程未启动或前序任务失败 |
27
+ | gen --check 失败 | CAGE-GEN-001/002 | 声明修改未生成、手改契约、迁移快照不一致 |
28
+
29
+ ## CAGE-APPR-007:找不到审批人
30
+
31
+ 先读所属领域模块 `approvals.ts` 的实际步骤(采购范例为 `packages/domain/src/modules/purchase/approvals.ts`),按选人器处理:
32
+
33
+ | 选人器 | 配置位置 | 常见误解 |
34
+ | --- | --- | --- |
35
+ | `approver.deptLeader('deptId')` | 单据 deptId 指向的部门,在 `/admin` 设置负责人 | 给用户经理角色不等于给部门设置负责人 |
36
+ | `approver.role('finance')` | 创建 code 为 finance 的角色,并给实际用户分配 | 选人看角色 code,不是中文显示名称 |
37
+ | `approver.user(id)` | 使用存在的用户 UUID,核对业务可用性 | 把用户名或角色名当成 UUID |
38
+
39
+ 选人成功后,再检查此人所需能力、数据范围、额度。示例中提单人不能审批自己,经理的 `PurchaseOrder.approve` 必须有 ceiling 参数。
40
+
41
+ 若事件已进入死信,在 `/admin` 查看对应 outboxId 的错误并修正配置,再点击重放。原 submit 通常已提交,单据处于 pending_approval;不要重复提交,更不要直接 SQL 改回 draft。重放后确认待办及后续事件,不把“点击重放成功”当成整条链路已经完成。
42
+
43
+ ## CAGE-PAIR-002:新增操作遗漏释放
44
+
45
+ 查看报错命令是否离开持有资源的状态,沿 `命令 → emits 事件 → reaction → releases 资源` 检查。补业务事件与真正的释放命令,声明相同资源标签,并确认 map 在这条路径能执行。
46
+
47
+ 不要只加一个不执行的反应骗过图规则,也不要删 acquires 标签。图规则检查结构,业务测试还要覆盖关键条件分支。
48
+
49
+ ## 数据库错误应提供什么信息
50
+
51
+ 提供发生于 init/migrate/API/worker 哪一步、主机/端口/库名、使用哪个角色、PostgreSQL 错误码、是否有待执行迁移。URL 中密码特殊字符需编码;修改环境变量后重启进程。
52
+
53
+ - 连接拒绝:检查数据库服务、主机端口和容器端口映射。
54
+ - 认证失败(如 28P01):核对对应角色密码;不重置其他项目共享角色。
55
+ - 无权限:核对当前账号职责;读账号不能用来执行迁移,业务进程不应改成管理员连接。
56
+ - 表/视图不存在:审查后执行 migrate,确认连接的是同一个数据库。
57
+ - 已执行迁移校验和不符:恢复原文件,新增迁移;不要改 sys.schema_migrations 的 checksum。
58
+
59
+ 不要贴出整个 `.env`、初始化凭证文件、Cookie 密钥或恢复文件内容。管理员连接只用于准备权限,日常业务继续使用独立账号。
60
+
61
+ ## 如何说明没有验证的部分
62
+
63
+ 报告构建/检查通过的命令,另列跳过和未执行的检查及原因。fake 成功、图规则通过、HTTP 202、无权限用户看不到按钮,都不能单独证明真实第三方、任务完成或后端权限正确。
64
+
65
+ 错误码册中的例子用于解释局部规则;完整业务代码以当前项目 domain 和生成 contracts 为准。错误来自内部源码时,手册给出路径和位置;独立项目无需把内部源码复制进来修补,应先修自己的声明/配置或明确报告框架缺口。
@@ -0,0 +1,152 @@
1
+ # 开发步骤与交付要求
2
+
3
+ [返回学习入口](README.md) · [范例导读](purchase-example.md) · [详细中文注释](commenting.md)
4
+
5
+ 本页命令在**应用根目录**执行,除非注明“框架根目录”。使用项目安装的 CLI:`pnpm exec cage ...`。项目脚本可简写为 `pnpm gen / pnpm migrate / pnpm dev / pnpm verify`;不要假定机器已全局安装 cage。
6
+
7
+ ## 第一次启动应用
8
+
9
+ 前提是 PostgreSQL 数据库已经存在。框架负责连接与表结构,不负责数据库服务的安装、建库或 Docker 生命周期。
10
+
11
+ ```powershell
12
+ pnpm install
13
+ # 仅首次复制;已有 .env 时编辑原文件,不覆盖配置。
14
+ Copy-Item .env.example .env
15
+ # 在 .env 填写 CAGE_ADMIN_DATABASE_URL,指向已有数据库。
16
+ pnpm exec cage init
17
+ pnpm build:app
18
+ pnpm gen
19
+ # 审查 db/migrations 中的迁移草稿,再执行:
20
+ pnpm migrate
21
+ # 迁移后显式初始化组织,目标是新的受限凭据文件;父目录需存在。
22
+ pnpm exec cage bootstrap --credentials-file .cage/admin-credentials.json
23
+ pnpm dev
24
+ ```
25
+
26
+ `init` 自动创建独立账号与随机密码,填写 APP/READ/MIGRATE 连接和 Cookie 密钥,成功后删除文件中的管理员连接。三个连接使用同一数据库。已有 Cage 集群账号时复用原连接,不能重置其他应用的账号密码。生产环境可由平台直接提供账号连接,不必执行本地 init。
27
+
28
+ `bootstrap` 独立初始化组织,不自动授予业务能力。管理员凭据只进入新的受限文件,不进入服务控制台;已有用户时不重置。交付后移除凭据文件。日常 API 启动不初始化组织;生产缺少合格 Cookie 密钥会拒绝启动。具体文件权限与诊断用法见[能力发现与状态诊断](diagnostics.md)。
29
+
30
+ `.env.example` 是配置说明,`.env` 是本机私密配置,二者不混用。CLI 自动加载应用 `.env`,部署环境同名变量优先。API 和 worker 启动需重启后读取变更;不要输出整个 `.env` 排障。
31
+
32
+ 框架仓库首次先在根目录 `pnpm install`、`pnpm build`,再进入 `examples/purchase-admin` 配置。`dev` 不自动执行迁移;生成新迁移后要审查并显式运行 migrate。
33
+
34
+ ## 做一项业务修改
35
+
36
+ 1. 读 AGENTS.md、[目录规范](project-structure.md)和[详细中文注释规范](commenting.md),确认需求落在领域模块、前端模块、组织配置还是框架。先 `pnpm exec cage context "需求关键词"`,按需 `graph search/inspect/path` 定位,确认候选入口后阅读对应源码、范例与测试;证据和边界见[本体上下文指南](ontology-context.md)。发现能力缺口先说明,不编造 API。
37
+ 2. 涉及已存在业务含义变化时,**修改前**运行 `pnpm exec cage snapshot save before-change` 保存命名基线;也可使用真实 Git 提交或独立本体图文件。
38
+ 3. 在所属领域模块写字段、状态、不变量和命令输入;再实现 handler、事件、查询与审批。跨模块反应放 workflows,第三方协议放 integrations。从模块 index 到 domain 总入口逐层导出,避免跨文件 export 名冲突。同步编写详细中文注释:文件职责与调用链、导出声明及输入字段、权限/状态/reads/事件/事务、关键步骤和失败边界;涉及已有行为时补齐受影响的上下游说明。
39
+ 4. `pnpm exec cage check` 检查声明和图规则;`pnpm gen` 更新契约与迁移草稿。聚合和命令填写中文 `description`,需要覆盖时补 `cage.config.json` 的 `graph.labels`(如 `aggregate:Note`、`command:Note.archive`、`capability:Note.export`)。这些名称同时用于图谱和 `/admin` 授权界面;修改后重启 API。不重命名实际能力点来实现翻译。在图谱确认连接与资源生命周期。
40
+ 5. 审查数据库变更,特别是非空字段、数据回填、删列和索引。已执行的迁移不可改写。需要落库时显式 `pnpm migrate`。
41
+ 6. 页面和表单放 `apps/web/src/modules/<业务>`,从模块公开入口接入 app 的 URL 路由;依赖生成 contracts,处理失败结果。列表、详情等多页面使用 React Router,筛选和分页进入 URL;组件状态只管理页面内临时交互。新增能力由管理员授权,页面按钮可用 `useCan` 控制。按[路由与浏览器验收](routing.md)检查直达、刷新、前进后退和登录回跳。
42
+ 7. 补足重要业务反例并运行相关验证;测试解释夹具目的、所保护的规则和覆盖边界。按注释规范审查本次 diff,核对页面、组件/hooks、类型字段、脚本副作用和恢复流程的说明是否完整准确。提交源声明、契约和审查过的迁移,报告跳过及未执行项。
43
+
44
+ ### 如何保存和比较基线
45
+
46
+ ```powershell
47
+ # 修改前执行;同名快照不会覆盖。
48
+ pnpm exec cage snapshot save before-change
49
+ # 修改 domain 后执行:
50
+ pnpm exec cage impact --snapshot before-change
51
+ # 或与真实可用的 Git 提交比较;下面的 main 应按仓库实际情况替换。
52
+ pnpm exec cage impact --base main
53
+ ```
54
+
55
+ 基线文件要保留到验收结束。影响分析用于找到相关命令、约束、审批、查询和候选测试,不能当作不需验证的证明。没有 Git 提交时不要为了让命令成功而擅自创建/推送远端。
56
+
57
+ `context` 和图谱查询只返回查询结果,不更新当前图文件或命名基线;`analyze/gen` 更新当前图。快照来源时间、版本与图指纹随报告保存。
58
+
59
+ ## 常见需求的具体改法
60
+
61
+ | 需求 | 做法 | 必查项 |
62
+ | --- | --- | --- |
63
+ | 增加字段 | 修改 aggregate;按命令更新 input/handler;重新生成 | 是否敏感、是否可选、旧数据如何回填、查询/事件/页面受影响吗 |
64
+ | 增加状态或撤回 | 修改 states 和 command;声明事件及资源处理 | 可达性、非终态出边、审批 cancelOn、CAGE-PAIR-002 |
65
+ | 修改审批 | 修改 route/approval;按需要增加 routable | 负责人/role code、步骤 mode、结论命令、额度和职责分离 |
66
+ | 增加报表 | 声明 query 的 reads、input 和 sql/build | 安全视图、参数化、调用人 read 权限、生成 queries 契约 |
67
+ | 接入第三方 | 声明 connector/op/outbound/inbound;配置运行环境密钥 | 请求响应白名单、幂等、超时、验签、永久/可重试错误和补偿 |
68
+ | 改后台管理配置 | 通过组织模型与系统接口修改 | 防提权、实际授权范围、角色缓存刷新、操作人权限 |
69
+ | 改脚手架 | 先修改标准范例,再同步模板并构建 CLI | 新目录实际创建结果、资料分发、凭证不入包 |
70
+
71
+ ## 前端如何消费框架
72
+
73
+ ```ts
74
+ import { purchaseOrder } from '@app/contracts';
75
+
76
+ // 普通业务接口使用生成的方法;第二个参数可传当前记录的 version。
77
+ const result = await purchaseOrder.submit(order.id, order.version);
78
+ if (!result.ok) {
79
+ // 按 code 展示通用原因;DOMAIN_ERROR 还可以按 domainCode 展示业务文案。
80
+ showError(result.domainCode ?? result.code);
81
+ } else {
82
+ refreshOrder(result.data);
83
+ }
84
+ ```
85
+
86
+ 这是页面事件处理片段,`order/showError/refreshOrder` 由业务页面提供。不要导入 domain 命令在浏览器执行,也不要复制后端权限逻辑。生成契约只包含允许 user 调用的写操作;审批通过通过待办接口进行,而不是自己增加 `purchaseOrder.approve()`。
87
+
88
+ 对自定义 HTTP 协议能力使用 `@yss123/cage-client`;它负责会话、CSRF 和类型化结果。需让多个提交共享幂等键时,按当前客户端接口显式传递同一次业务操作的 key,并在页面阻止重复进行中的提交。生成契约的方法签名以 `packages/contracts/src` 为准,不假设每个命令方法都支持自定义 options。
89
+
90
+ 生成方法最后的请求选项支持 `signal/timeoutMs/idempotencyKey`。底层返回 `CageResult`;`useCageCommand` 成功返回业务数据、失败抛出 `CageCommandError`,因此 mutation 的 `isSuccess` 表示业务成功。退出、401、切换账号时订阅 `client.subscribe` 取消用户查询并清除应用缓存,范例 `apps/web/src/app/use-session.ts` 展示了接法。
91
+
92
+ ### 导入和导出属于业务页面
93
+
94
+ 框架提供通用异步接口与任务查询,页面放在哪里由具体业务决定。
95
+
96
+ - 导出调用生成的 `purchaseOrder.export(params, options?)` 等方法,得到任务;使用 `client.transfer(id)` 或 `useTransfer(id)` 查看进度,完成后通过 `client.transferDownloadUrl(id)` 下载。
97
+ - 导入调用 `client.importCsv('PurchaseOrder.create', csv, { atomic: false })` 等,目标是已声明且支持用户调用的命令;每行执行命令,复用权限和业务校验。该例中的 `items` 等复杂字段需遵守实际 CSV 编码规则,不是任意 Excel 文件自动识别。
98
+ - `atomic: true` 请求整批原子处理,普通逐行导入需展示成功/失败计数及报告。HTTP 202 仅代表接受任务,不能立即提示处理完成。
99
+ - worker 必须运行;任务可能 queued/retrying/failed/expired。下载会再次校验当前权限。导出的系统列和掩码值不能原样回导。
100
+
101
+ CSV 编码、限制、SDK 与完整接口见本项目自带的[业务页导入导出](transfers.md)。给新业务做入口时按实际生成的签名调用,不硬编码采购单专属逻辑进框架。
102
+
103
+ ## 工具做什么,结果在哪里
104
+
105
+ | 命令 | 用途 | 主要输出 |
106
+ | --- | --- | --- |
107
+ | `pnpm exec cage analyze` | 抽取显式声明与源码位置 | `.cage/ontology.json` |
108
+ | `pnpm exec cage capabilities 关键词 --format json` | 查询当前安装版本的公开能力 | 公开签名、声明位置和学习入口 |
109
+ | `pnpm exec cage doctor` | 统一核对注册、生成、构建及可用运行证据 | pass / fail / unknown 与下一步;见[诊断指南](diagnostics.md) |
110
+ | `pnpm exec cage snapshot save 名称` | 保存不可覆盖的命名基线 | `.cage/snapshots`;配合 `impact --snapshot 名称` |
111
+ | `pnpm exec cage check` | 静态检查、注册表与图规则 | 终端 `code/at/reason/fix` |
112
+ | `pnpm exec cage graph` | 启动中文本体图谱 | 默认 `http://127.0.0.1:15418`,按终端地址访问 |
113
+ | `pnpm exec cage context "需求或节点"` | 开发前取得相关子图、原因、源码与候选验证 | 默认终端 Markdown;`--format json --out .cage/context.json` 保存结构化报告 |
114
+ | `pnpm exec cage graph search/inspect/path ...` | 检索候选 / 精确节点 / 关系路径 | 同源中文与证据;每次重新抽取,见[用法](ontology-context.md) |
115
+ | `pnpm gen` | 更新契约、结构说明、迁移草稿 | `packages/contracts/src`、`db/migrations`、`generated`、`.cage/ontology.json` |
116
+ | `pnpm exec cage gen --check` | 只比较需提交的生成物 | 不一致时报 CAGE-GEN;不是实际数据库漂移扫描 |
117
+ | `pnpm exec cage test --only project` | 项目测试 | `.cage/test-results.json` 与终端 |
118
+ | `pnpm exec cage test --only derived` | 声明派生的框架性质测试 | `generated/tests`、同一测试报告 |
119
+ | `pnpm verify` | 汇总门禁 | `.cage/verify.json` |
120
+ | `pnpm exec cage verify --skip-tests` | 执行测试以外的门禁 | 报告标明 `complete: false`,不可称全量通过 |
121
+ | `pnpm exec cage sync` / `sync --check` | 同步/比较 AGENTS 托管区 | 保留标记外的项目自有规则;不自动改写业务代码或学习资料 |
122
+ | `pnpm exec cage budget` | 体积、公共词汇和 unsafe 预算 | 终端 metrics/findings |
123
+ | `pnpm exec cage upgrade --dry-run` | 查看当前目标 CLI 所带升级改动 | 文件修改预览;应先安装正确目标版本 CLI |
124
+
125
+ `generated/` 和 `.cage/` 是可再生资料;contracts 和迁移是需要审查、提交的生成结果。生成迁移通过最后一个迁移内嵌的结构快照比较,不是创建临时数据库,也不能证明真实库从未被手工改动。
126
+
127
+ ## 验证要与改动匹配
128
+
129
+ - 文档、文案、可逆的小改动:检查链接、格式、资料分发;不需要重复运行全套数据库测试。
130
+ - 所有源码变更:按[注释交付清单](commenting.md#交付前逐项核对)人工核对中文职责、接口与关键流程说明;静态检查不能替代注释准确性检查。仅补注释时不新增复述实现的测试、不改写已执行迁移。
131
+ - 命令/约束/反应变化:针对成功路径及真正的风险增加用例,如越权拒绝、额度边界、资源释放、同事务回滚。不要写只复述实现的测试。
132
+ - 领域结构变化:check、gen、生成一致性、类型检查;有数据库影响时在独立测试库验证迁移和读写。
133
+ - 页面或导航变化:构建后按[浏览器配方](routing.md)实际操作,包含深链接、新标签页、刷新、前进后退、登录回跳、无权限和 404。check/verify 不自动执行浏览器验收;未操作时明确报告未执行,不能写“页面功能完整”。
134
+ - 发布前:按项目要求执行完整 verify/build/test,核对分发包。没有执行的项目明确写出原因。
135
+
136
+ 测试使用真实 PostgreSQL。`CAGE_TEST_DATABASE_URL` 供独立测试集群使用,测试工具会准备角色和临时数据库;不要指向业务/生产集群。没有设置时 testkit 可使用内嵌的真实 PostgreSQL,这与 dev 的固定已有库流程不同。
137
+
138
+ 派生测试无法凭空推断所有业务合法输入,会报告跳过。它们证明的是通用性质,不能代替采购 happy path、审批配置和第三方真实联调。
139
+
140
+ ## 可以交给 AI 的任务描述
141
+
142
+ ```text
143
+ 先读 AGENTS.md 和它指定的 docs/ai/README.md,再参考对应标准范例。
144
+ 需求:为某业务增加……
145
+ 先用 cage context 查询现有业务,必要时 graph inspect/path,确认候选与关系后阅读实现。
146
+ 说明字段、状态、能力与范围、事件/资源的影响,再修改 domain、生成契约和迁移草稿、接入业务页面。
147
+ 使用真实公开 API;不要手写业务路由、直接写表或新增本地数据库生命周期命令。
148
+ 按 docs/ai/commenting.md 给新建和修改代码写详细中文注释,覆盖职责、API/字段、步骤、原因和边界,同步修正相关上下游说明。
149
+ 按改动运行必要检查,报告通过/跳过/未执行项和需要的管理员配置。
150
+ ```
151
+
152
+ 交付说明至少包含行为变化、源文件、生成物/迁移、角色授权需求、详细中文注释覆盖的主要职责与边界、验证结果,以及尚未做的真实外部联调。注释未覆盖项如实说明,不能用聊天中的解释代替源码注释。遇到错误先修复根因;不把待办未生成、任务已接受或 fake 成功写成业务全部完成。
@@ -0,0 +1,61 @@
1
+ # CAGE-AI-001:智能运行时声明无效
2
+
3
+ [返回错误码册](README.md) · [业务排错](../ai/troubleshooting.md)
4
+
5
+ > 本页由框架生成。正反例为局部声明或操作说明,完整写法见业务开发指南及本项目 domain。
6
+
7
+ ## 何时出现
8
+
9
+ 阶段:领域声明 / 模型与运行预算配置。
10
+
11
+ 模型引用未配置、重复启用 AI 运行时,或上下文预算、重试、并发、超时、队列参数非法。
12
+
13
+ ## 修复步骤
14
+
15
+ 1. 在 domain 顶层导出一个 ai({ models, assistant }) 声明,审批 step 的 model 引用同名模型。
16
+ 2. 预算与并发为正整数;maxModelRetries 为 0 至 8,context.maxTools 最多 128(包含通用工具)。并发最多 32,单次运行 timeoutMs 最多 300000。API 与 worker 使用相同声明和模型配置。
17
+
18
+ ## 正例
19
+
20
+ ```text
21
+ ai({ models: { main: provider }, assistant: { model: 'main', limits: { maxSteps: 8 } } })
22
+ ```
23
+
24
+ ## 反例
25
+
26
+ ```text
27
+ ai({ models: {}, assistant: { model: 'missing', limits: { maxSteps: 0 } } })
28
+ ```
29
+
30
+ ## 修复后验证
31
+
32
+ 重跑 cage check、迁移与相关测试,再以真实角色验证助理和审批;fake 成功不代表真实模型联调完成。
33
+
34
+ ## 框架内的检查位置
35
+
36
+ 以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
37
+
38
+ - `packages/ai/src/index.ts:54`
39
+ - `packages/ai/src/index.ts:61`
40
+ - `packages/ai/src/index.ts:74`
41
+ - `packages/ai/src/index.ts:82`
42
+ - `packages/ai/src/index.ts:86`
43
+ - `packages/ai/src/index.ts:88`
44
+ - `packages/ai/src/index.ts:89`
45
+ - `packages/ai/src/index.ts:90`
46
+ - `packages/ai/src/index.ts:92`
47
+ - `packages/ai/src/index.ts:94`
48
+ - `packages/ai/src/index.ts:96`
49
+ - `packages/ai/src/index.ts:126`
50
+ - `packages/ai/src/index.ts:130`
51
+ - `packages/ai/src/index.ts:132`
52
+
53
+ 实现片段(位置随框架版本更新):
54
+
55
+ ```ts
56
+ /**
57
+ * 校验扩展唯一性与审批模型引用,无效配置以 CAGE-AI-001 拒绝。
58
+ */
59
+ validate(registry: Registry): void;
60
+ }
61
+ ```