@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,282 @@
1
+ # 原语与最小业务
2
+
3
+ [返回学习入口](README.md) · [开发步骤](workflow.md)
4
+
5
+ 本页代码使用当前公开导出。完整文件示例可直接放入应用;标为“片段”的代码需要结合采购范例已有符号使用。不要把片段中的变量名当成新的框架 API。
6
+
7
+ 文件字段使用 `file({ maxBytes, accept }).optional()` 或 `files({ maxBytes, accept, maxCount })`。字段保存文件 ID,上传/续传先获得临时文件,最终通过业务命令绑定;完整流程、限制和存储配置见[文件指南](files.md)。
8
+
9
+ ## 最小的增、查、改、归档业务
10
+
11
+ 下面是完整的 `packages/domain/src/modules/note/note.ts`。它演示带部门范围的便笺,不影响采购范例原有业务;需要此业务时才添加文件。
12
+
13
+ ```ts
14
+ import { aggregate, command, ref, scope, states, text } from '@yss123/cage-kernel';
15
+ import { z } from 'zod';
16
+
17
+ export const Note = aggregate('Note', {
18
+ description: '部门便笺',
19
+ fields: {
20
+ title: text(120),
21
+ deptId: ref('Dept'),
22
+ createdBy: ref('User'),
23
+ },
24
+ states: states('active', 'archived', { terminal: ['archived'] }),
25
+ // 指明部门字段。最终能看哪个部门,由角色的数据范围决定。
26
+ scope: scope.deptSubtree('deptId'),
27
+ invariants: { titleNotBlank: (o) => o.title.trim().length > 0 },
28
+ });
29
+
30
+ export const createNote = command(Note, {
31
+ // 使用独立导出名避免多个文件 export * 时 create 重名;能力仍叫 Note.create。
32
+ name: 'create',
33
+ from: 'new',
34
+ to: 'active',
35
+ input: z.object({ title: z.string().trim().min(1).max(120) }),
36
+ // 新建草稿已有输入字段;deptId 和 createdBy 由内核按当前主体填入。
37
+ handler: (draft) => draft,
38
+ });
39
+
40
+ export const updateNote = command(Note, {
41
+ name: 'update',
42
+ from: 'active',
43
+ to: null,
44
+ input: z.object({ id: z.string().uuid(), title: z.string().trim().min(1).max(120) }),
45
+ // 只返回业务变化,状态、版本及审计仍由内核维护。
46
+ handler: (_draft, input) => ({ title: input.title }),
47
+ });
48
+
49
+ export const archiveNote = command(Note, {
50
+ name: 'archive',
51
+ from: 'active',
52
+ to: 'archived',
53
+ // 省略 input 时,已有记录命令默认使用 { id: uuid }。
54
+ handler: (draft) => draft,
55
+ });
56
+ ```
57
+
58
+ 先在 `packages/domain/src/modules/note/index.ts` 写 `export * from './note.js';`,再在 `packages/domain/src/index.ts` 保留组织模型及已有模块,加入新模块:
59
+
60
+ ```ts
61
+ export * from '@yss123/cage-admin/domain';
62
+ export * from './modules/note/index.js';
63
+ ```
64
+
65
+ 随后 `pnpm exec cage check`、`pnpm gen`,审查迁移后 `pnpm migrate`。管理员给目标角色配置 `Note.create / Note.update / Note.archive / Note.read` 和 `Note` 数据范围;前端使用生成的 `note.create({ title })`、`note.update(id, { title }, version)`、`note.archive(id, version)`、`note.list()`、`note.get(id)`。
66
+
67
+ 这里的删除选择“归档”这一业务命令,没有硬删表行。读侧列表默认行为以生成契约与实际过滤参数为准,页面要按需求选择是否展示归档记录。系统默认状态并不意味着自动拥有完整 CRUD 命令。
68
+
69
+ ## 字段速查
70
+
71
+ | 字段工厂 | TypeScript 值/用途 | 注意 |
72
+ | --- | --- | --- |
73
+ | `text(max?)` | 字符串 | 最大长度;非空、格式等业务输入规则用 Zod 明确表达 |
74
+ | `int()`、`number()` | 整数、普通数值 | 金额不要用普通浮点运算代替业务金额规则 |
75
+ | `money()` | 十进制字符串 | 输入如 `'1200.00'`,PG numeric 读出仍是字符串 |
76
+ | `id()` | UUID 字符串 | 业务引用没有声明关系时的 UUID 字段 |
77
+ | `ref('Dept')` | 引用聚合的 UUID | 用字符串名可避免循环导入;目标聚合需从入口导出 |
78
+ | `ref('User').unique()` | 租户内至多一对一 | 外键加租户复合唯一索引;不要求目标一定被引用 |
79
+ | `hasMany('NoteComment', { mappedBy: 'noteId' })` | 一对多反查 | 只读集合,外键在目标上;不占主表列 |
80
+ | `manyToMany('User', { description: '协作成员' })` | 多对多关联 | 命令草稿为 ID 数组;中间表由框架生成,读取独立分页 |
81
+ | `date()`、`datetime()` | 日期/时间字符串 | 遵守字段 schema,计算时明确时区 |
82
+ | `bool()`、`enumOf(...)` | 布尔、枚举 | 有状态迁移语义时用 `states` 而非普通枚举代替 |
83
+ | `list({ sku: text(), qty: int() })` | 对象列表 | 可以表达单据明细;不是自动生成独立子表 |
84
+ | `json()` | 结构不固定的 JSON 对象 | 用于结构化扩展;输入规则用命令 Zod 表达,不要把全部领域结构藏进任意 JSON |
85
+
86
+ 字段可链式使用 `.optional()`、`.unique()`、`.sensitive('phone')`、`.hidden()` 等。可用敏感种类以包导出的 `SENSITIVE_KINDS` 为准;hidden 字段不会作为普通公开读字段,sensitive 字段按权限掩码。不要通过前端隐藏来替代它们。
87
+
88
+ 集合关系也放在 `fields` 中,但不是普通 SQL 列,不支持上述四种修饰。完整声明、成员命令、分页接口、权限与迁移见[对象关系指南](relations.md)。纯关联不手写 NoteMember 聚合,具有职位、状态等业务属性的关联仍应建业务聚合。
89
+
90
+ 不要定义 `id/version/status/createdAt/updatedAt/tenantId` 同名业务字段。聚合名和事件名用大驼峰,字段、命令、查询和任务名用小驼峰,状态名用小写下划线。
91
+
92
+ ## 命令的几个关键选项
93
+
94
+ | 选项 | 当前用法 | AI 常见错误 |
95
+ | --- | --- | --- |
96
+ | `from` | `'new'` 或已有状态/状态数组 | 直接在 handler 改状态,绕过生命周期 |
97
+ | `to` | 声明的状态;已有记录可用 `null` 保留状态 | 新建用 `null`,或误认为 null 不检查状态 |
98
+ | `input` | Zod schema;已有记录必须包含 id | 用聚合字段 schema 当成任意命令输入 |
99
+ | `name` | 能力和接口中的命令名覆盖 | 混淆导出变量名与最终 `Aggregate.command` |
100
+ | `invokedBy` | 默认 user;可声明 process/job/external 或数组 | 为了从前端审批而给内部结论加 user |
101
+ | `reads` | `{ 别名: 聚合 }` | 不声明依赖,直接读仓库或连接数据库 |
102
+ | `constraints` | 执行前的硬约束 | 在页面上判断一次就认为后端安全 |
103
+ | `emits` | 事件或 `emit(事件, 映射)` | 已提交后另写消息,失去事务一致性 |
104
+
105
+ handler 参数依次是 `draft, input, deps, { now, actorUserId }`。可返回草稿、部分业务字段或 void;`return fail('STOCK_SHORT', detail)` 表示业务拒绝,整个事务回滚。
106
+
107
+ 片段:采购审批读取已声明的库存依赖。
108
+
109
+ ```ts
110
+ reads: { stock: Inventory },
111
+ handler: async (order, _input, { stock }) => {
112
+ for (const item of order.items) {
113
+ const row = await stock.findOne({ sku: item.sku });
114
+ if (!row || row.available < item.qty) return fail('STOCK_SHORT', [item.sku]);
115
+ }
116
+ return order;
117
+ },
118
+ ```
119
+
120
+ 使用 `deps.stock.get/findOne/find` 读取声明的依赖;不要将其扩展为写仓库。这个片段只是单次库存检查,不保证多订单并发扣减安全;生产扣减需要专门设计库存命令和并发控制。
121
+
122
+ ## 约束与不变量
123
+
124
+ ```ts
125
+ // 片段:放在采购 approve 的配置中。
126
+ invokedBy: 'process',
127
+ constraints: [sod.notSameAs('createdBy'), ceiling('amount')],
128
+ ```
129
+
130
+ `sod` 防止提单人审批自己;`ceiling` 读取审批人该能力上的额度参数,没有额度也拒绝。管理员在 `/admin` 给角色配置 `PurchaseOrder.approve` 的 `ceiling`,不是把额度写死进页面。
131
+
132
+ 不变量写在 `aggregate(..., { invariants: { 名称: 对象 => boolean } })`,在最终结果合并和目标状态确定后检查。例如 `Number(o.amount) > 0`。约束回答“这次操作允许吗”,不变量回答“结果对象合法吗”。可用 `Constraint` 类型定义自定义约束对象;先核对公开导出,不假设所有内部 helper 都是公共 API。
133
+
134
+ ## 事件与资源反应
135
+
136
+ 片段来自采购范例,完整版本见 `modules/purchase/purchase-order.ts`、`workflows/purchase-inventory.ts`(相对 domain src)。
137
+
138
+ ```ts
139
+ // 事件中只放下游真正需要的信息;不要拷贝整个对象。
140
+ export const OrderCancelled = event('OrderCancelled', {
141
+ orderId: id(),
142
+ previousStatus: text(),
143
+ });
144
+
145
+ // 命令中通过 emit 显式提供旧状态,用它判断此前是否持有资源。
146
+ emits: [emit(OrderCancelled, (order, _input, previous) => ({
147
+ orderId: order.id,
148
+ previousStatus: previous.status,
149
+ }))],
150
+ ```
151
+
152
+ ```ts
153
+ export const lockOnApprove = reaction(OrderApproved, {
154
+ command: acquireLock,
155
+ tx: 'same',
156
+ acquires: 'inventory.lock',
157
+ map: (e) => ({ id: e.orderId, orderId: e.orderId, items: e.items }),
158
+ });
159
+
160
+ export const releaseOnCancel = reaction(OrderCancelled, {
161
+ command: releaseLock,
162
+ releases: 'inventory.lock',
163
+ // 草稿取消时从未建锁,不应对不存在的锁调用释放命令。
164
+ map: (e) => e.previousStatus === 'approved' ? { id: e.orderId } : null,
165
+ });
166
+ ```
167
+
168
+ `map` 是纯映射,可返回 null 表示此次不执行;不能在映射中调用 HTTP。每条离开持有状态的迁移都应释放资源,或进入同样持有资源的状态。新增“撤回”时别只复制状态迁移,还要检查释放路径。
169
+
170
+ 事件默认载荷映射的具体命名规则见真实 `event.ts` 与范例;映射不明确时使用 `emit` 显式声明。已部署事件只做兼容扩展,新增字段设 optional;不兼容含义用新事件并考虑旧 outbox 消费,不能只改消费者。
171
+
172
+ ### 有界集合与步骤顺序
173
+
174
+ 同一事件需要对 20 台设备调用相同命令时,用 `reactionEach` 声明一次。下面为局部片段,`EquipmentAllocated` 事件含 `assets: [{ assetId }]`,`acquireAsset` 为已导出的目标命令:
175
+
176
+ ```ts
177
+ import { reactionEach } from '@yss123/cage-kernel';
178
+
179
+ export const acquireAllocatedAssets = reactionEach(EquipmentAllocated, {
180
+ command: acquireAsset,
181
+ items: event => event.assets,
182
+ maxItems: 20,
183
+ orderBy: 'assetId',
184
+ order: 20,
185
+ tx: 'same',
186
+ acquires: 'asset.use',
187
+ map: (item, _event, _index) => ({ id: item.assetId }),
188
+ });
189
+ ```
190
+
191
+ `maxItems` 是执行上限,输入 schema 也应表达业务上限。`orderBy` 必须是各项真实存在、非空、同类型且唯一的字符串或有限数值键;按键升序串行执行,以稳定资源锁顺序。`map` 收到排序后的索引,可返回 null 跳过;映射和选择器都是纯函数。
192
+
193
+ 失败诊断中的 `itemIndex` 是跳过 null 后的实际执行输入索引;`sortedIndex` 是排序后原项位置,`originalIndex` 是事件数组原位置,`itemKey` 是稳定排序键,均使用零基索引。诊断不附完整项载荷。
194
+
195
+ 多个跨对象步骤用 `order` 表达预算 → 设备 → 占用明细等依赖。同事件同 `tx` 分组一旦使用 order,所有步骤必须提供互不重复的非负整数。普通 `reaction` 也支持 order;不要靠导出变量的编号表达流程顺序。
196
+
197
+ `tx: 'same'` 的集合仍走每一条目标命令的授权、约束、审计与版本流水线,任一失败使主命令及整个同事务链回滚。默认 outbox 集合由 worker 串行调用并随该消费者事务提交;重试与死信仍按事件处理。图谱和 context 展示目标、上限、排序键、顺序和事务。框架不替业务决定整单或分批:配发整单可用一个命令及其同事务集合,分批归还则每次提交的一批共同回滚。
198
+
199
+ ## 两种查询写法
200
+
201
+ 下面两段均为完整声明,可选择需要的写法。它们都走只读连接与安全视图;调用人需要 `PurchaseOrder.read`,并受其范围与掩码限制。
202
+
203
+ ```ts
204
+ import { query } from '@yss123/cage-kernel';
205
+ import { z } from 'zod';
206
+ import { PurchaseOrder } from './purchase-order.js';
207
+
208
+ export const poByStatus = query('poByStatus', {
209
+ reads: [PurchaseOrder],
210
+ input: z.object({ status: z.string() }),
211
+ sql: `select dept_id, count(*)::int as n
212
+ from safe.purchase_order where status = :status group by dept_id`,
213
+ });
214
+ ```
215
+
216
+ ```ts
217
+ import { query } from '@yss123/cage-kernel';
218
+ import { z } from 'zod';
219
+ import { PurchaseOrder } from './purchase-order.js';
220
+
221
+ export const recentOrders = query('recentOrders', {
222
+ reads: [PurchaseOrder],
223
+ input: z.object({ status: z.string() }),
224
+ build: (db, input) => db.selectFrom('safe.purchase_order')
225
+ .select(['id', 'amount', 'status'])
226
+ .where('status', '=', input.status)
227
+ .orderBy('created_at', 'desc')
228
+ .limit(20),
229
+ });
230
+ ```
231
+
232
+ `sql` 与 `build` 必须二选一。SQL 用数据库的 snake_case 列名和 `:参数名`;不要拼接输入,也不要查询 `core.*`/`sys.*` 基表。`reads` 列出所有涉及的聚合,不能漏掉 join 的对象。业务前端调用生成的 `queries.*`,不复制查询 SQL。
233
+
234
+ 有目的级审计要求时,在 query 中声明 `audit: { purpose: '月度结算核对' }`。目的应为固定说明,不包含敏感输入。查询会先可靠写入用途审计再交付结果;潜在敏感明文还按 `reads` 保守审计,不假定任意 SQL 投影能精确推导字段和对象。审计故障返回 `CAGE-AUDIT-001`,不交付查询数据。完整保证见[审计矩阵](architecture.md#审计保证)。
235
+
236
+ 通用列表参数要求正安全整数 page/pageSize;数值筛选必须有限并满足字段 schema,布尔只接受 true/false,日期必须合法,排序字段必须来自公开字段。非法值返回字段级 `INVALID_INPUT`,不会把任意非 true 字符串转成 false。当前仍采用 offset 分页及精确计数,大规模分页成本需按实际数据测量。
237
+
238
+ ## 审批绑定与选人
239
+
240
+ 下面是完整的采购路由文件形状,使用同目录现有的采购符号:
241
+
242
+ ```ts
243
+ import { approval } from '@yss123/cage-kernel';
244
+ import { approver, gt, route, step, when } from '@yss123/cage-approval';
245
+ import { PurchaseOrder, OrderSubmitted, OrderCancelled, approve, reject } from './purchase-order.js';
246
+
247
+ export const poApproval = approval(PurchaseOrder, {
248
+ process: 'po-approval',
249
+ start: OrderSubmitted,
250
+ cancelOn: [OrderCancelled],
251
+ routable: ['amount', 'deptId'],
252
+ onApproved: approve,
253
+ onRejected: reject,
254
+ });
255
+
256
+ export const poRoute = route('po-approval', [
257
+ step('部门经理审批', approver.deptLeader('deptId')),
258
+ when(gt('amount', 50000), step('财务审批', approver.role('finance'), { mode: 'any' })),
259
+ ]);
260
+ ```
261
+
262
+ `approval` 绑定事件与结论命令;`route` 决定步骤与人;`routable` 限制交给路由的数据字段。`onApproved/onRejected` 必须属于同一聚合,且允许 process 调用。
263
+
264
+ 内置选人器是 `approver.deptLeader(字段名)`、`approver.role(角色code)`、`approver.user(用户id)`。条件使用 `gt/gte/lt/lte/eq/ne/isIn` 等封闭表达式。`mode: 'any'/'all'` 描述一步内的人如何完成,不表示任意并行分支。可以在代码组合这些能力;任意函数选人、转签和加签需框架扩展或外部审批适配器,当前不能直接写成现成 API。
265
+
266
+ 被选中的审批人还要具备结论命令所需能力、范围和额度。部门负责人为空会产生 `CAGE-APPR-007`,详见[排错](troubleshooting.md)。
267
+
268
+ ## 连接器、定时任务和逃生口
269
+
270
+ | 能力 | 声明结构 | 标准范例 |
271
+ | --- | --- | --- |
272
+ | 连接器 | `connector(name, { hosts, secret: 密钥名, operations: { 操作: op(...) } })` | `integrations/erp.ts` |
273
+ | 出站 | `outbound(事件, 操作, { map, idempotencyKey, onSuccess })` | ERP 推单,成功用 external 命令回写 |
274
+ | 入站 | `inbound(连接器, 事件名, { verify, payload, command, map })` | HMAC 验签的收货回调 |
275
+ | 定时任务 | `job(name, { cron, reads, calls, run })` | `jobs.ts` 过期草稿取消 |
276
+ | 逃生口 | `unsafe({ reason, owner }, () => ...)` | 仅用于声明无法表达且评审过的特殊情况 |
277
+
278
+ 连接器 host 写主机名而非完整 URL,操作 path 从 `/` 开始,request/response 均用 schema 白名单,密钥只写环境变量名。`effect: 'retryableWrite'` 仍需要第三方幂等协议,不是承诺远端恰好一次。
279
+
280
+ job 的 `run({ query, call, now })` 只能读 `reads` 和调用 `calls` 中的命令。用户命令可以被显式声明了它的系统任务调用;仅允许内部身份的命令还需包含 job 身份。最终仍走写流水线。不要通过新增脚本直接扫表改业务状态。
281
+
282
+ `unsafe` 只记录原因和负责人并进入预算,不自动授予数据库、网络或用户权限,也不让 lint 边界失效。能用声明表达的普通业务不应使用它。
@@ -0,0 +1,128 @@
1
+ # 工程目录与代码组织
2
+
3
+ 本规范针对 create-cage-app 生成的业务项目。目录首先表达业务归属,其次才是页面、组件、hooks 等技术用途。新增报销功能时,应在报销模块内找到它的页面和表单,而不是在整个 src 中搜索一批散落文件。
4
+
5
+ 两种模板使用同一规则:采购模板提供完整业务,空白模板保留认证和工作台。不要为小功能创建空目录;文件确实承担独立职责时再拆分。
6
+
7
+ 目录表达代码归属,[详细中文注释规范](commenting.md)说明每个文件及接口如何被理解和使用。框架与脚手架应用的新建、修改源码都必须执行这份规范,职责说明和实现一起交付。
8
+
9
+ ## 项目分工
10
+
11
+ ```text
12
+ 项目根目录/
13
+ ├─ apps/
14
+ │ ├─ api/src/
15
+ │ │ ├─ main.ts # 启动 HTTP,装配 domain,处理退出
16
+ │ │ └─ worker.ts # 启动异步任务,按环境装配连接器 fake
17
+ │ └─ web/src/
18
+ │ ├─ main.tsx # 挂载 React、全局 Provider 和样式
19
+ │ ├─ app/ # 会话恢复、URL 路由、布局、模块组合
20
+ │ │ ├─ app.tsx
21
+ │ │ ├─ use-session.ts # 会话恢复和 401 回跳,不把网络故障当成未登录
22
+ │ │ ├─ workspace-layout.tsx
23
+ │ │ └─ styles/global.css
24
+ │ ├─ modules/ # 按业务命名,一个模块内管理它的页面和交互
25
+ │ │ ├─ auth/
26
+ │ │ │ ├─ index.ts
27
+ │ │ │ └─ pages/login-page.tsx
28
+ │ │ └─ purchase/
29
+ │ │ ├─ index.ts # 模块对应用壳公开的入口
30
+ │ │ ├─ pages/purchase-orders-page.tsx
31
+ │ │ └─ components/purchase-order-form.tsx
32
+ │ └─ shared/ # 已被复用、与具体业务无关的前端代码
33
+ │ ├─ ui/ # 提示容器等通用组件
34
+ │ ├─ hooks/ # 通用交互 hooks
35
+ │ └─ lib/ # 格式化、通用错误展示等纯辅助函数
36
+ ├─ packages/
37
+ │ ├─ domain/src/
38
+ │ │ ├─ index.ts # 全部声明的统一导出,仅负责注册组合
39
+ │ │ ├─ modules/
40
+ │ │ │ ├─ purchase/
41
+ │ │ │ │ ├─ index.ts
42
+ │ │ │ │ ├─ purchase-order.ts # 聚合、状态、事件、命令
43
+ │ │ │ │ ├─ approvals.ts # 本业务审批绑定和代码路由
44
+ │ │ │ │ ├─ queries.ts # 本业务自定义安全查询
45
+ │ │ │ │ ├─ jobs.ts # 本业务定时任务
46
+ │ │ │ │ └─ purchase-order.test.ts
47
+ │ │ │ └─ inventory/
48
+ │ │ │ ├─ index.ts
49
+ │ │ │ └─ inventory.ts
50
+ │ │ ├─ workflows/ # 跨模块事件反应,例如采购通过后锁库存
51
+ │ │ │ └─ purchase-inventory.ts
52
+ │ │ ├─ integrations/ # 第三方协议、出站映射和入站验签声明
53
+ │ │ │ └─ erp.ts
54
+ │ │ └─ shared/ # 按需创建:跨领域模块的纯校验或业务值定义
55
+ │ └─ contracts/src/ # 全部由 cage gen 维护
56
+ │ ├─ index.ts # @app/contracts 统一公共入口
57
+ │ ├─ aggregates/
58
+ │ │ ├─ purchase-order/index.ts
59
+ │ │ ├─ inventory/index.ts
60
+ │ │ └─ user/index.ts
61
+ │ └─ queries/index.ts
62
+ ├─ db/migrations/
63
+ └─ docs/ai/、docs/errors/
64
+ ```
65
+
66
+ 树中的采购文件可在采购模板中运行;空白模板把它们作为离线参考放在 `docs/examples/purchase-admin`,真实源码只有认证、工作台和组织模型。空白项目没有需要用到的目录可以不创建。
67
+
68
+ ## 新需求具体写到哪里
69
+
70
+ 以“报销单列表、新建报销、经理审批”为例:
71
+
72
+ 1. 在 `packages/domain/src/modules/expense/expense.ts` 声明 Expense、状态、事件和命令;小模块可先放在这个文件,不强制把每条命令拆成一个文件。
73
+ 2. 审批声明放同模块 `approvals.ts`;查询、定时任务有实际需求再增加 `queries.ts`、`jobs.ts`。通过模块 `index.ts` 导出,再从 domain 根入口转导出。导出名全局唯一,命令重名时用显式 `name` 保留能力点语义。
74
+ 3. 需要驱动其他模块时,把 reaction 放在 `workflows/expense-xxx.ts`,从双方模块公开入口取声明。第三方接口放 `integrations/<系统名>.ts`,声明 hosts、schema、secret 名、outbound/inbound,不直接发网络请求。
75
+ 4. 运行 `pnpm gen`,审查 `contracts/src/aggregates/expense/index.ts` 和迁移草稿。根 `@app/contracts` 自动导出 Expense API/类型。不要在 contracts 里手工建“报销 service”。
76
+ 5. 在 `apps/web/src/modules/expense/pages/expense-list-page.tsx` 使用生成 hooks。新建表单放该模块 `components/expense-form.tsx`,模块专用 hooks 放自己的 `hooks`,专用接口封装按需放自己的 `api`,专用常量留在模块内。
77
+ 6. 从前端模块 `index.ts` 导出页面,应用壳从 `../modules/expense` 引入并注册列表、详情 URL,通过 Outlet 放入工作台布局。导航用 Link/NavLink,筛选和分页用 useSearchParams;弹窗和提交状态留在页面,不把整个页面切换写成 useState。按[路由指南](routing.md)验收深链接、刷新、前进后退和登录回跳。
78
+
79
+ 前后端可以有相同的业务模块名,但文件不混放:领域定义授权和行为,前端管理交互,通过生成契约连接。API 启动入口维持薄壳,普通业务无需新增 controller/service/repository。
80
+
81
+ ## 依赖方向与模块入口
82
+
83
+ | 来源 | 可以依赖 | 不应依赖 |
84
+ | --- | --- | --- |
85
+ | Web `main.tsx` | app、共享基础设施、框架前端 Provider | 各项业务页面与表单 |
86
+ | Web `app` | 模块公开入口、shared、应用内部布局 | 模块内部表单/hooks 文件 |
87
+ | Web `modules/<业务>` | 自己的内部文件、shared、contracts/client | 其他前端模块、app、domain/数据库包 |
88
+ | Web `shared` | shared 内部文件、通用前端库与通用 client 类型 | app、具体业务模块 |
89
+ | Domain `modules/<业务>` | 自己内部文件、其他领域模块的公开声明、纯 shared、框架声明 API | workflows、integrations、domain 总入口、IO、contracts |
90
+ | Domain `workflows` | 领域模块公开声明、纯 shared、框架 reaction API | HTTP 实现、页面、数据库写入 |
91
+ | Domain `integrations` | 领域模块公开声明、纯 shared、连接器 API | workflows、HTTP 实现、直接网络请求 |
92
+ | Domain `shared` | 纯 shared、基础值/校验库 | 具体模块和组合层、IO |
93
+
94
+ 前端两项业务需要一起展示时,由 app 同时取它们的公开组件/hooks,通过 props 和回调传数据。采购页的“我的待办”数量就是由应用壳传入的,不让采购模块导入审批页面。遇到真实复用的业务组件,先明确归属和输入输出,不把整页挪到 shared 来绕过边界。
95
+
96
+ 领域模块允许单向业务依赖,例如采购审核声明 `reads: { stock: Inventory }`,通过 `../inventory/index.js` 导入。不要从 domain 总入口反向导入,否则容易形成循环注册。双向依赖优先改为 workflows 组合或共享值,不用层层转导出掩盖循环。
97
+
98
+ `index.ts` 只列出对外导出。禁止把模块的全部内部实现都公开来规避边界;不在 index 中启动服务、读环境变量或初始化业务。
99
+
100
+ ## 什么放 shared
101
+
102
+ 一个辅助函数只被报销使用,就先留在报销模块。多个模块实际复用、且没有绑定某项业务时,再移到 shared。例如通用提示容器、命令结果反馈 hook、金额格式化可以共享;报销状态文案、采购请求、审批选人规则属于各自模块。
103
+
104
+ 不要新增包罗万象的 `utils.ts`、`common.tsx`、`lists.tsx`、`api.ts` 收集所有业务。用能说明职责的文件名,例如 `error-message.ts`、`purchase-order-form.tsx`、`use-approval-tasks.ts`。
105
+
106
+ ## 命名、文件与注释
107
+
108
+ - 目录和源码文件用 `kebab-case`;React 组件/类型用 `PascalCase`,函数、变量与 hook 用 `camelCase`,hook 以 `use` 开头。聚合、命令、事件名是稳定的业务标识,目录改名不顺便改能力点、API 或表名。
109
+ - 页面放 `pages/*-page.tsx`,模块专用组件放 `components`,专用 hooks 放 `hooks`。小模块只有一个页面时可以直接 `modules/<业务>/<业务>-page.tsx` 并配公开 index;不强制创建所有子目录。
110
+ - 入口只挂载或组合;页面主要描述页面流程。表单、表格或交互已承担独立职责时再抽取,避免一个大组件处理所有业务,也避免每个按钮都新建文件。
111
+ - 全局主题、reset、基础布局放 `app/styles`;业务专用样式与组件就近放置,可用 CSS Modules。不要把所有新增业务样式长期追加进一个全局文件。当前范例保留既有全局主题,结构调整不重新设计界面。
112
+ - 单测与被测代码相邻,使用 `*.test.ts(x)`。需要真实业务链路的集成用例与所属业务模块相邻;框架的测试发现递归查找,不必为它回到 src 根目录。
113
+ - 新建和修改的手写源码文件必须有中文职责、主要调用链与运行边界说明;模块入口也要说明公开职责。导出函数/类/声明、React 组件/hooks、接口及类型字段使用中文 JSDoc,复杂私有函数与关键分支解释具体步骤、原因和边界,详细要求见[注释规范](commenting.md)。
114
+ - 业务字段说明单位、格式、空值与来源;命令说明输入、权限、状态、读依赖、事件、事务与失败行为;页面说明 URL、数据加载、权限和错误交互;测试说明意图与覆盖边界;脚本说明前置条件、写入/覆盖等副作用。修改已有代码时同步补齐受影响的上下游注释,不能只更新当前实现。
115
+ - 注释必须准确、充分,不以“代码自解释”免除必要说明,不用每行语法翻译、注释字数或比例充数。生成注释从声明/生成器维护,已执行或已发布迁移不可因补注释而重写。不加无业务价值的防御分支和静默兜底;脚本使用 TypeScript,不新增 `.mjs`。
116
+
117
+ ## 自动约束与整理已有项目
118
+
119
+ 新模板在 `cage.config.json` 设置 `"structure": "modular"`。`pnpm exec cage check` 与 `pnpm verify` 自动检查:
120
+
121
+ - `CAGE-STRUCT-001`:domain src 根目录只保留领域入口,web src 根目录只保留 `main.tsx`;其他运行源码使用上述顶层目录。`*.d.ts` 类型声明与相邻测试不受入口限制。
122
+ - `CAGE-STRUCT-002`:阻止共享层反向依赖、前端模块直接互相导入、领域模块依赖流程/连接器、跨模块穿透内部文件。相对路径、tsconfig 别名和转导出都参与模块解析。
123
+
124
+ 这些检查约束目录和可见导入,不能替代评审,也不按行数强制拆文件。通过错误码定位文件,再按职责整理,不要关闭门禁或把文件塞进 shared 来消除提示。框架已有的依赖门禁继续约束 IO、前端依赖和生成物边界。
125
+
126
+ 已有项目可以先移动文件并修正导入,再启用该配置;CLI 升级不会自动搬动客户代码。生成契约布局由新版 `cage gen` 更新:保留 `@app/contracts` 公共 API,清理带 Cage 生成签名的过期文件,用户手写文件保留。不要依赖 contracts 内部路径导入。
127
+
128
+ 目录调整后运行类型检查、`cage check`、`pnpm gen` 和生成一致性检查;有改动页面时检查相应操作。目录整理不应产生数据库结构变化,若出现迁移草稿应核实原因,已执行的迁移不要改写。
@@ -0,0 +1,111 @@
1
+ # 标准采购范例:从声明到业务页面
2
+
3
+ [返回学习入口](README.md) · [业务任务配方](recipes.md)
4
+
5
+ 选择 `--template purchase` 创建的是可运行的采购应用,下面的路径相对应用根目录;选择 `--template blank` 时,同一份范例仅作为参考源码保存在 `docs/examples/purchase-admin`,下面路径相对该参考目录,它不参与当前应用的编译、注册或迁移。框架能力来自 npm 依赖。先沿一条真实链路读代码,再把需要的模式应用到自己的业务。
6
+
7
+ ## 按这个顺序读文件
8
+
9
+ | 文件(相对应用根目录) | 看懂的业务能力 | 改造时关注什么 |
10
+ | --- | --- | --- |
11
+ | `packages/domain/src/index.ts` | 哪些声明真正被注册 | 保留组织模型,导出新增业务,避免导出名冲突 |
12
+ | `packages/domain/src/modules/inventory/inventory.ts` | 最简字段、创建命令、资源锁聚合 | scope.none 不等于无需授权;创建与释放都是命令 |
13
+ | `packages/domain/src/modules/purchase/purchase-order.ts` | 单据生命周期、金额、明细、约束、事件 | 哪些字段由输入提供,哪些由内核维护;每个状态的允许操作 |
14
+ | `packages/domain/src/workflows/purchase-inventory.ts` | 同事务建锁、异步释放 | acquires/releases 的配对及 map 返回 null 的原因 |
15
+ | `packages/domain/src/modules/purchase/approvals.ts` | 启动/取消审批、条件步骤与选人 | routable、部门负责人、角色 code、结论命令 |
16
+ | `packages/domain/src/integrations/erp.ts` | 出站推单、成功回写、入站回调 | 白名单、secret 名、schema、幂等与 HMAC |
17
+ | `packages/domain/src/integrations/intelligence.ts` | 消费框架托管模型和本体助理 | Admin 配置连接,通用工具由框架生成 |
18
+ | `packages/domain/src/modules/purchase/queries.ts` | 按状态汇总 | reads、安全视图、命名参数 |
19
+ | `packages/domain/src/modules/purchase/jobs.ts` | 过期草稿取消 | reads/calls 和 job 调用身份 |
20
+ | `apps/api/src/main.ts`、`apps/api/src/worker.ts` | 如何启动框架与 worker | 保持薄装配,fake 只用于相应环境 |
21
+ | `packages/contracts/src/aggregates/purchase-order/index.ts` | 生成的前端协议与类型 | 只读它,不手改;process/external 命令不生成浏览器写方法 |
22
+ | `apps/web/src/main.tsx`、`app` | 挂载、全局 Provider、会话与导航组合 | 入口保持简洁,从模块公开入口组装页面 |
23
+ | `apps/web/src/modules/purchase`、`inventory`、`approval` | 各业务页面与交互 | 调契约、处理错误、刷新列表、展示导出任务;不互相穿透 |
24
+ | `packages/domain/src/modules/purchase/purchase-order.test.ts` | 有业务数据的成功/拒绝用例 | 越权、自审批、额度、库存锁、晚到 ERP 回执 |
25
+
26
+ ## 一次正常采购发生了什么
27
+
28
+ ```text
29
+ 采购员新建 → draft
30
+ → submit → pending_approval + OrderSubmitted(同事务提交)
31
+ → worker 消费事件 → AI 材料预审
32
+ → 材料不足:returnForChanges → draft,补充用途后重新提交、从头审核
33
+ → 疑难材料:在本节点创建人工接管待办
34
+ → 材料清楚:通过本节点,创建经理待办
35
+ → 经理审批;金额 > 50000 时还有财务步骤
36
+ → 流程完成 → 调用 approve
37
+ → 职责分离、额度、库存检查
38
+ → approved + OrderApproved
39
+ → 同事务 lockOnApprove → InventoryLock.held
40
+ → worker 消费 OrderApproved → fake/真实 ERP 推单
41
+ → recordErpNo(external,保持当前状态)
42
+ → 收货回调 → markReceived → received + OrderReceived
43
+ → worker 释放锁 → InventoryLock.released
44
+ ```
45
+
46
+ submit 返回成功只表示单据和事件已提交,不表示待办、ERP 或其他异步工作已经完成。worker 未运行时,单据可以已经处于待审批,但没有待办。
47
+
48
+ ### 为什么分三个聚合
49
+
50
+ - `PurchaseOrder` 管单据、审批结论和采购状态。
51
+ - `Inventory` 是物料台账,提供库存检查的数据。
52
+ - `InventoryLock` 记录某张订单的资源占用,使用订单 id 作为锁 id,让释放目标明确。
53
+
54
+ 审批通过和建锁放在同一事务,是为了避免“单据已批准却没拿到资源”。ERP 网络请求放到 outbox,是因为远端调用无法与本地 PostgreSQL 共同回滚。
55
+
56
+ ### 取消为什么要带 previousStatus
57
+
58
+ 草稿或待审批取消时还没有库存锁,不应释放不存在的锁;已批准取消才需要释放。因此 `OrderCancelled` 的显式 emit 映射携带旧状态,反应通过 `previousStatus === 'approved'` 决定是否调用释放命令。
59
+
60
+ 新增撤回、作废等动作时,每一条离开已批准状态的路径都要考虑资源。仅把命令 `to` 改成新状态,可能被 `CAGE-PAIR-002` 拦下;补了标签也仍要确保真正的释放命令会执行。
61
+
62
+ ### ERP 回执为什么用 to: null
63
+
64
+ 网络应答可能晚于取消或收货到达。`recordErpNo` 允许从 approved/received/cancelled 更新单号,用 `to: null` 保持加锁时的当前状态;不会把取消单重新变成已批准。它仍受调用身份、允许状态、版本和审计约束。
65
+
66
+ 本例没有真实 ERP 取消补偿。上线时需另外设计远端撤销、退货或人工补偿,不能把“本地取消成功”当成“远端订单已撤销”。
67
+
68
+ ## 首次体验所需业务配置
69
+
70
+ 以下体验需要采购模板;空白模板不会出现采购页面和审批配置。先按[开发步骤](workflow.md)准备已有数据库并启动 API、worker、Web。首次管理员凭证按 API 提示获取,不把凭证写到仓库。以下是业务配置,不是需要写进框架内核的逻辑。
71
+
72
+ | 对象 | 配置要点 |
73
+ | --- | --- |
74
+ | 采购员 | 创建/查看/提交/取消采购单等所需能力,所属部门,以及采购单数据范围 |
75
+ | 智能助理使用人 | 显式授予 `Sys.ai.use`;编辑用途还需 `PurchaseOrder.explainPurpose` |
76
+ | 模型管理者 | `Sys.ai.models.manage`;在 `/admin/#/models` 配置并启用 `main`,部署主密钥见[智能能力指南](intelligence.md) |
77
+ | 助理性格管理者 | `Sys.ai.personalities.manage`;在 `/admin/#/personalities` 编辑预设、自定义性格、设置默认并试聊 |
78
+ | AI 预审角色 | 创建 code 为 `purchase_ai_reviewer` 的角色,授予 `PurchaseOrder.read/returnForChanges` 及覆盖申请范围的数据权限;本例 AI 仅预审,不执行最终 approve |
79
+ | 经理 | `PurchaseOrder.read/approve/reject/returnForChanges`,适当数据范围,`approve` 的 `ceiling` 额度参数 |
80
+ | 部门 | 将采购员所属部门的负责人设为经理;不能为空 |
81
+ | 财务 | 角色 **code** 为 `finance`,给实际用户分配;配置审批所需权限、范围及额度 |
82
+ | 库存台账 | 预先登记与采购明细相同的 sku,数量满足演示检查 |
83
+ | 连接器环境 | fake 阶段使用 worker 注册的 fake;真实环境另配 host 对应密钥及回调签名密钥 |
84
+
85
+ 经理与提单人必须是不同用户。配置“负责人”决定选谁;配置角色能力与范围决定此人能否完成结论命令,两者都需要。金额 **大于** 50,000 才追加财务步骤,恰好 50,000 不满足 gt 条件。
86
+
87
+ 可分别准备“采购办公用品”、说明实际使用场景的完整用途、含“紧急采购”的用途,体验退回、通过本节点和转人工。真实模型的判定应按实际样例验收;故障默认转人工,不能当作正常审查通过。详情页显示历史理由、修改建议及审核轮次;用途编辑框的未保存内容会经 SDK 一起传给助理,服务端重新核对当前单据与权限。
88
+
89
+ 拥有 `Sys.ai.use` 的用户在所有业务页面右下角都有助理入口,点击打开悬浮对话窗,收起后继续执行当前任务。工作台、采购列表/详情、库存和待办分别提供页面语义;列表带筛选与可见记录,详情带单据引用和未保存用途。应用壳只挂载一个 `AssistantScope`,业务页面通过 `AssistantPage` 注册上下文,所以站内切页保留对话,但下一条消息使用新页面的快照。不同页面拥有独立的 `AiPageContext` 身份,旧任务要求补充页面时不能提交新页面代替。登录页和独立的 `/admin/` 不挂载业务助理。
90
+
91
+ 悬浮窗的“相处方式”选择器消费框架 `useAssistant` 的性格目录和切换接口。默认跟随 Admin 设置,也可为当前会话选择其他已启用性格;切换不清空对话,旧回复保留生成时的性格名称。采购范例没有单独的性格表或 Prompt 拼接逻辑,AI 审批继续使用原节点策略。
92
+
93
+ ## 页面如何使用框架
94
+
95
+ 采购页和库存页通过 `@app/contracts` 获取方法、快照类型和查询 hooks。命令成功后刷新相应列表;失败时按 code/domainCode 展示原因。只有允许 user 调用的命令才生成页面方法,因此审批通过应使用待办接口。
96
+
97
+ `apps/web` 中对字段和按钮的中文名称属于业务文案。图谱名称来自 `cage.config.json` 的 `graph.labels`,比如 `command:PurchaseOrder.submit` 对应“提交审批”。替换业务时别忘了更新这些名称,不要改英文能力标识来做翻译。
98
+
99
+ 导出按钮是调用通用异步接口的一个例子;框架不规定所有业务都要放相同的按钮。导入、导出、任务列表与错误报告应按客户页面需要接入,参考[开发步骤](workflow.md)中的客户端方法。
100
+
101
+ ## 把示例改成自己的业务
102
+
103
+ 先按[目录规范](project-structure.md)新增自己的领域模块和前端模块,完成一条完整链路,再逐步移除不需要的采购导出、路由、反应、连接器和页面引用。`@app/domain`、`@app/contracts` 是应用内包名,可以保留;npm 框架包也不需要重命名。
104
+
105
+ 若数据库尚未投入使用,可为新应用审查和规划初始结构;只要迁移已执行或已发布,就不能通过覆盖 `0001_init.sql` 来假装采购表从未存在。用新迁移表达后续变更,并明确已有数据处理方式。
106
+
107
+ ## 本例可以证明和不能证明的事
108
+
109
+ 它演示了真实 PG 上的命令与安全读侧、审批结论约束、同事务建锁、异步释放、连接器 fake 和签名回调。`Inventory.available` 是演示台账数量,尚未实现多订单并发扣减、实物出入库和退货核算;fake ERP 不证明第三方生产联调完成。
110
+
111
+ 扩展业务时把这些边界写进实现说明,补必要的业务规则与有意义的回归用例,而不是直接给范例换标题后声称生产需求已经全部覆盖。
@@ -0,0 +1,89 @@
1
+ # 业务任务配方
2
+
3
+ [返回学习入口](README.md) · [原语示例](primitives.md) · [开发步骤](workflow.md)
4
+
5
+ 本页用于把用户的业务描述转成 Cage 项目的可执行修改。按需要读对应配方即可,不需要修改框架内部。
6
+
7
+ 需要 AI 审批、业务助理、随页聊天、模型管理或性格配置时,先用 `cage capabilities` 查框架能力,再按[原生智能化指南](intelligence.md)接入。普通业务建模仍按下文声明聚合和命令;接入已有框架服务无需另建一套通用后端。
8
+
9
+ ## 先把需求落到一张业务表
10
+
11
+ 开始编码前,从用户需求或现有业务中确定以下信息。能从上下文确认的直接使用;真正缺失且影响实现的再询问,不要为技术细节反复让用户确认。
12
+
13
+ | 业务问题 | 落到什么声明 | 例如 |
14
+ | --- | --- | --- |
15
+ | 管理什么对象?有哪些字段? | aggregate、字段与 Zod 输入 | 报销单:金额、事由、部门、提单人、明细 |
16
+ | 有哪些阶段?谁能做什么? | states、command、invokedBy | 草稿可编辑、提交后审批、完成后不可撤回 |
17
+ | 数据属于谁/哪个部门? | 范围字段 + 角色数据范围 | 申请人看本人,经理看部门及下级 |
18
+ | 每次操作有什么硬规则? | constraints、invariants、fail | 提单人不可审批、额度上限、金额必须为正 |
19
+ | 成功后还要发生什么? | event、reaction、approval、outbound | 启动审批、登记额度占用、推送财务系统 |
20
+ | 取消/失败要撤销什么? | cancelOn、释放命令、补偿流程 | 取消待办、释放占用、远端撤销或人工补偿 |
21
+ | 页面需要看什么? | 生成的 list/get、query、业务页面 | 分页、详情、按状态汇总、导出与导入 |
22
+
23
+ ## 新增一个普通管理对象
24
+
25
+ 按[最小便笺业务](primitives.md)新增 `packages/domain/src/modules/<业务>/<对象>.ts`:字段、范围、不变量、create/update/archive 命令。采用唯一的导出名和必要的 `name` 覆盖,避免 index 的 `export *` 丢失重名符号。
26
+
27
+ 从模块 index 到 domain 入口导出后运行 check/gen,审查迁移,再在 `apps/web/src/modules/<业务>` 使用生成 contracts 做列表、详情、表单和操作按钮,经模块公开入口注册到 app 路由。列表和详情都有独立 URL,筛选/分页进入 query,按[浏览器配方](routing.md)检查导航。最后给角色授权并补图谱中文名。完整归属规则见[目录规范](project-structure.md)。不要手写后端增删改查路由、ORM 实体与 repository,也不要复制框架鉴权代码。
28
+
29
+ 完成标准:授权用户能创建和修改,范围外数据不可见,归档后的允许行为符合业务要求,生成契约和迁移一致。没有审批需求时不必添加审批;没有外部系统时不必添加连接器。
30
+
31
+ ## 增加一对多或多对多
32
+
33
+ 参考[对象关系](relations.md),在聚合的同一个 fields 中添加 `hasMany/manyToMany`。纯关联交给框架生成中间表;关系本身有职位、状态等业务属性时再建立有意义的聚合。hasMany 反查目标上的 ref,修改归属执行子对象命令;manyToMany 用所属对象的命令返回 ID 数组。
34
+
35
+ 生成后前端通过 `对象.related.字段(id, params)` 或 `use对象Related字段` 分页读取,不从普通 get 响应猜测已加载关联。给角色配置两侧 read 能力与范围;添加成员时也检查目标可见性。修改关系执行版本检查,不能把当前一页当作完整集合替换。不要创建新的业务连接池、ORM 中间实体或手写关系路由。
36
+
37
+ ## 给业务单据加审批
38
+
39
+ 1. 为单据补草稿、待审批、通过、驳回等真实状态及命令;提交时发事件。
40
+ 2. 通过/驳回使用 process 命令,根据业务添加职责分离、额度等约束。
41
+ 3. 添加 approval 绑定和 route;只将需要的字段放进 routable,取消命令发事件并配置 cancelOn。
42
+ 4. 配置实际部门负责人、角色或指定用户;给审批人配置能力、范围和额度。
43
+ 5. 页面通过待办接口操作。通过后需占用资源时用反应调用资源命令,按业务一致性选择同事务。
44
+
45
+ 完成标准:提交生成待办、正确的人审批、越权和自审批拒绝、取消能结束待办、资源配对完整。任意流程设计器、动态 JS 选人、转签/加签不属于当前现成能力,需要明确扩展范围。
46
+
47
+ ## 加入 AI 审批或随页助理
48
+
49
+ 先检查 domain 是否已经导出 `ai()`,再按需求修改已有声明或启用一次。AI 审批配置在业务模块的现有 `step` 内,填写 `kind: 'ai'`、审核策略、取证字段/查询与 `handoff`,由 `approval` 绑定自动执行角色和结论命令。业务助理使用框架生成的工具,前端通过 `useAssistant` 与 `useAiPageContext` 接入当前页面;悬浮窗、Markdown 和确认交互由应用实现。
50
+
51
+ 模型地址、协议和密钥通过 `managedModel` 对应的 Admin 配置管理,性格也使用框架现有管理页。先完成系统迁移和必要授权,按[智能化指南](intelligence.md)的接入顺序、SDK 示例和验收步骤验证。分别说明框架支持、应用已启用和真实联调结果;空白模板中的参考代码不参与运行。
52
+
53
+ ## 增加报表或复杂列表
54
+
55
+ 普通分页和详情先使用生成的 list/get;汇总、联表等需求再添加 query。写清 reads、输入 schema,选择参数化 SQL 或 build;只查对应 safe 视图,不为“报表方便”切到管理员连接。
56
+
57
+ 重新生成后使用 `queries.你的查询()` 或生成 hook。检查真实调用人的 read 能力和数据范围;管理员能看到结果不能证明普通用户的报表正确。
58
+
59
+ ## 接入外部系统
60
+
61
+ 沿 `packages/domain/src/integrations/erp.ts` 的结构声明 host、密钥名、操作 schema、outbound 和 inbound。远端成功后的字段回写也走 external 命令。先用 fake 完成本地链路,再在测试环境做真实联调。
62
+
63
+ 明确重复请求如何识别、哪些错误重试、回执晚到怎么办、取消后如何补偿。不要假设本地事务可以回滚已经提交给第三方的写入。
64
+
65
+ ## 增加导入或导出
66
+
67
+ 在客户实际需要的业务页调用客户端/生成契约,展示任务进行中、完成和失败。导入映射到用户可调用的命令,准备与该命令输入匹配的 CSV;不要生成直接写业务表的上传接口。
68
+
69
+ 明确逐行还是整批原子模式、失败报告如何呈现、任务过期如何处理。任务提交成功不能立即标成导入/导出完成,worker 与下载时授权也是链路的一部分。完整方法、CSV 例子与协议见[业务页导入导出](transfers.md)。
70
+
71
+ ## 由采购演示换成客户业务
72
+
73
+ 空白模板不需要清理采购业务,直接从 `packages/domain/src` 新增自己的声明和页面;参考源码在 `docs/examples/purchase-admin`,不在运行入口中。下面的替换步骤只适用于采购模板。
74
+
75
+ 建议先保留运行薄壳和一条可验证的演示链路,新增真实业务并接通页面,再移除不需要的演示引用。清理时沿领域导出、反应、审批、连接器、查询、任务、页面和 graph.labels 一起检查,避免残留仍在运行的自动任务。
76
+
77
+ 组织模型仍从 `@yss123/cage-admin/domain` 导出。已执行迁移作为历史保留,新表/删表通过新迁移表达;需要保存旧数据时先制定迁移方案,不能只把整个 migrations 文件夹删除。
78
+
79
+ ## 给编程工具的任务模板
80
+
81
+ ```text
82
+ 阅读当前项目 AGENTS.md,按 docs/ai/README.md 找到本次需求对应的原语和标准范例。
83
+ 遵守 docs/ai/project-structure.md:领域和前端按业务建 modules,app 组合页面,shared 只放通用代码,不平铺 src 或堆进 main.tsx。
84
+ 业务:……;角色与数据范围:……;状态与允许动作:……;审批/外部系统/资源占用:……。
85
+ 先列出需要修改的 domain、页面、契约、迁移和授权,再直接完成实现。
86
+ 使用当前公开 API;对无法表达的需求说明具体缺口,不编造方法。
87
+ 生成文件通过 cage gen 更新,数据库使用已有 .env 配置,按改动完成必要验证。
88
+ 交付时说明用户如何体验、管理员需配置什么,以及通过/跳过/未执行的检查。
89
+ ```