@yss123/cage-cli 0.1.0 → 0.2.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 (540) hide show
  1. package/README.md +23 -1
  2. package/dist/analyze.js +2 -0
  3. package/dist/analyze.js.map +1 -1
  4. package/dist/config.d.ts +2 -2
  5. package/dist/config.js +0 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/context.d.ts +72 -0
  8. package/dist/context.js +202 -0
  9. package/dist/context.js.map +1 -0
  10. package/dist/create-prompt.d.ts +5 -0
  11. package/dist/create-prompt.js +50 -0
  12. package/dist/create-prompt.js.map +1 -0
  13. package/dist/create.d.ts +18 -1
  14. package/dist/create.js +30 -13
  15. package/dist/create.js.map +1 -1
  16. package/dist/dev.js +12 -51
  17. package/dist/dev.js.map +1 -1
  18. package/dist/gen/contracts.js +34 -13
  19. package/dist/gen/contracts.js.map +1 -1
  20. package/dist/gen/index.js +43 -3
  21. package/dist/gen/index.js.map +1 -1
  22. package/dist/gen/zod-code.d.ts +1 -1
  23. package/dist/gen/zod-code.js +3 -1
  24. package/dist/gen/zod-code.js.map +1 -1
  25. package/dist/graph-command.d.ts +11 -0
  26. package/dist/graph-command.js +67 -0
  27. package/dist/graph-command.js.map +1 -0
  28. package/dist/graph-model.d.ts +21 -0
  29. package/dist/graph-model.js +101 -0
  30. package/dist/graph-model.js.map +1 -0
  31. package/dist/graph-presentation.d.ts +11 -0
  32. package/dist/graph-presentation.js +25 -0
  33. package/dist/graph-presentation.js.map +1 -0
  34. package/dist/graph-query.d.ts +171 -0
  35. package/dist/graph-query.js +242 -0
  36. package/dist/graph-query.js.map +1 -0
  37. package/dist/graph-relations.d.ts +14 -0
  38. package/dist/graph-relations.js +142 -0
  39. package/dist/graph-relations.js.map +1 -0
  40. package/dist/graph-search.d.ts +21 -0
  41. package/dist/graph-search.js +63 -0
  42. package/dist/graph-search.js.map +1 -0
  43. package/dist/graph-snapshot.d.ts +2 -4
  44. package/dist/graph-snapshot.js +2 -19
  45. package/dist/graph-snapshot.js.map +1 -1
  46. package/dist/graph.js +19 -1
  47. package/dist/graph.js.map +1 -1
  48. package/dist/impact.d.ts +6 -0
  49. package/dist/impact.js +28 -16
  50. package/dist/impact.js.map +1 -1
  51. package/dist/index.d.ts +5 -1
  52. package/dist/index.js +5 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/init.d.ts +6 -0
  55. package/dist/init.js +131 -0
  56. package/dist/init.js.map +1 -0
  57. package/dist/main.js +77 -32
  58. package/dist/main.js.map +1 -1
  59. package/dist/migrate.d.ts +3 -6
  60. package/dist/migrate.js +14 -53
  61. package/dist/migrate.js.map +1 -1
  62. package/dist/ontology.d.ts +3 -1
  63. package/dist/ontology.js +13 -3
  64. package/dist/ontology.js.map +1 -1
  65. package/dist/project-structure.d.ts +8 -0
  66. package/dist/project-structure.js +94 -0
  67. package/dist/project-structure.js.map +1 -0
  68. package/dist/static-check.js +1 -4
  69. package/dist/static-check.js.map +1 -1
  70. package/dist/sync.js +82 -10
  71. package/dist/sync.js.map +1 -1
  72. package/graph-ui/app.js +46 -8
  73. package/graph-ui/graph-model.js +100 -0
  74. package/graph-ui/graph-relations.js +141 -0
  75. package/graph-ui/graph-search.js +62 -0
  76. package/graph-ui/model.js +19 -77
  77. package/graph-ui/relations.js +2 -125
  78. package/graph-ui/structure.js +4 -1
  79. package/graph-ui/style.css +21 -0
  80. package/package.json +8 -8
  81. package/templates/app/.env.example +58 -14
  82. package/templates/app/AGENTS.md +95 -12
  83. package/templates/app/Dockerfile +2 -0
  84. package/templates/app/README.md +46 -16
  85. package/templates/app/_gitignore +8 -0
  86. package/templates/app/apps/api/package.json +2 -2
  87. package/templates/app/apps/web/src/app/app.tsx +18 -0
  88. package/templates/app/apps/web/src/app/workspace-layout.tsx +70 -0
  89. package/templates/app/apps/web/src/main.tsx +4 -543
  90. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +20 -0
  91. package/templates/app/apps/web/src/modules/approval/index.ts +2 -0
  92. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +54 -0
  93. package/templates/app/apps/web/src/modules/auth/index.ts +1 -0
  94. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +59 -0
  95. package/templates/app/apps/web/src/modules/inventory/index.ts +1 -0
  96. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +74 -0
  97. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +60 -0
  98. package/templates/app/apps/web/src/modules/purchase/index.ts +2 -0
  99. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +210 -0
  100. package/templates/app/apps/web/src/shared/hooks/use-command.ts +29 -0
  101. package/templates/app/apps/web/src/shared/lib/error-message.ts +15 -0
  102. package/templates/app/apps/web/src/shared/ui/notice.tsx +13 -0
  103. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +28 -0
  104. package/templates/app/apps/web/vite.config.ts +3 -0
  105. package/templates/app/cage.config.json +1 -1
  106. package/templates/app/docs/ai/README.md +77 -0
  107. package/templates/app/docs/ai/architecture.md +122 -0
  108. package/templates/app/docs/ai/ontology-context.md +117 -0
  109. package/templates/app/docs/ai/primitives.md +249 -0
  110. package/templates/app/docs/ai/project-structure.md +123 -0
  111. package/templates/app/docs/ai/purchase-example.md +97 -0
  112. package/templates/app/docs/ai/recipes.md +81 -0
  113. package/templates/app/docs/ai/relations.md +160 -0
  114. package/templates/app/docs/ai/transfers.md +92 -0
  115. package/templates/app/docs/ai/troubleshooting.md +60 -0
  116. package/templates/app/docs/ai/workflow.md +139 -0
  117. package/templates/app/docs/errors/CAGE-APPR-001.md +47 -0
  118. package/templates/app/docs/errors/CAGE-APPR-002.md +47 -0
  119. package/templates/app/docs/errors/CAGE-APPR-003.md +47 -0
  120. package/templates/app/docs/errors/CAGE-APPR-004.md +47 -0
  121. package/templates/app/docs/errors/CAGE-APPR-005.md +47 -0
  122. package/templates/app/docs/errors/CAGE-APPR-006.md +47 -0
  123. package/templates/app/docs/errors/CAGE-APPR-007.md +50 -0
  124. package/templates/app/docs/errors/CAGE-APPR-010.md +48 -0
  125. package/templates/app/docs/errors/CAGE-AUTH-001.md +47 -0
  126. package/templates/app/docs/errors/CAGE-BUDGET-001.md +47 -0
  127. package/templates/app/docs/errors/CAGE-BUDGET-002.md +47 -0
  128. package/templates/app/docs/errors/CAGE-BUDGET-003.md +47 -0
  129. package/templates/app/docs/errors/CAGE-CMD-002.md +47 -0
  130. package/templates/app/docs/errors/CAGE-CMD-003.md +47 -0
  131. package/templates/app/docs/errors/CAGE-CONN-001.md +47 -0
  132. package/templates/app/docs/errors/CAGE-CONN-002.md +47 -0
  133. package/templates/app/docs/errors/CAGE-CONN-003.md +47 -0
  134. package/templates/app/docs/errors/CAGE-CONN-004.md +47 -0
  135. package/templates/app/docs/errors/CAGE-CONN-005.md +47 -0
  136. package/templates/app/docs/errors/CAGE-CONN-006.md +47 -0
  137. package/templates/app/docs/errors/CAGE-CONN-007.md +47 -0
  138. package/templates/app/docs/errors/CAGE-CONN-008.md +47 -0
  139. package/templates/app/docs/errors/CAGE-CONN-009.md +47 -0
  140. package/templates/app/docs/errors/CAGE-CONN-010.md +47 -0
  141. package/templates/app/docs/errors/CAGE-CONN-011.md +47 -0
  142. package/templates/app/docs/errors/CAGE-CONN-012.md +47 -0
  143. package/templates/app/docs/errors/CAGE-CREATE-001.md +52 -0
  144. package/templates/app/docs/errors/CAGE-DECL-001.md +48 -0
  145. package/templates/app/docs/errors/CAGE-DECL-002.md +47 -0
  146. package/templates/app/docs/errors/CAGE-DECL-003.md +47 -0
  147. package/templates/app/docs/errors/CAGE-DECL-004.md +47 -0
  148. package/templates/app/docs/errors/CAGE-DEP-001.md +48 -0
  149. package/templates/app/docs/errors/CAGE-DEP-002.md +47 -0
  150. package/templates/app/docs/errors/CAGE-DEP-003.md +47 -0
  151. package/templates/app/docs/errors/CAGE-DEP-004.md +47 -0
  152. package/templates/app/docs/errors/CAGE-DEP-005.md +47 -0
  153. package/templates/app/docs/errors/CAGE-DLQ-001.md +48 -0
  154. package/templates/app/docs/errors/CAGE-ENV-001.md +52 -0
  155. package/templates/app/docs/errors/CAGE-EVENT-001.md +47 -0
  156. package/templates/app/docs/errors/CAGE-EVENT-002.md +50 -0
  157. package/templates/app/docs/errors/CAGE-FIELD-001.md +47 -0
  158. package/templates/app/docs/errors/CAGE-FIELD-002.md +47 -0
  159. package/templates/app/docs/errors/CAGE-FIELD-003.md +47 -0
  160. package/templates/app/docs/errors/CAGE-FIELD-004.md +47 -0
  161. package/templates/app/docs/errors/CAGE-GEN-001.md +48 -0
  162. package/templates/app/docs/errors/CAGE-GEN-002.md +47 -0
  163. package/templates/app/docs/errors/CAGE-GRANT-001.md +49 -0
  164. package/templates/app/docs/errors/CAGE-GRANT-002.md +48 -0
  165. package/templates/app/docs/errors/CAGE-GRANT-003.md +47 -0
  166. package/templates/app/docs/errors/CAGE-IMPACT-001.md +48 -0
  167. package/templates/app/docs/errors/CAGE-INIT-001.md +47 -0
  168. package/templates/app/docs/errors/CAGE-INIT-002.md +49 -0
  169. package/templates/app/docs/errors/CAGE-INIT-003.md +48 -0
  170. package/templates/app/docs/errors/CAGE-INIT-004.md +48 -0
  171. package/templates/app/docs/errors/CAGE-JOB-001.md +47 -0
  172. package/templates/app/docs/errors/CAGE-JOB-002.md +47 -0
  173. package/templates/app/docs/errors/CAGE-JOB-003.md +47 -0
  174. package/templates/app/docs/errors/CAGE-LINT-001.md +47 -0
  175. package/templates/app/docs/errors/CAGE-MIG-001.md +47 -0
  176. package/templates/app/docs/errors/CAGE-MIG-002.md +47 -0
  177. package/templates/app/docs/errors/CAGE-MIG-003.md +5 -0
  178. package/templates/app/docs/errors/CAGE-MIG-004.md +5 -0
  179. package/templates/app/docs/errors/CAGE-MIG-005.md +47 -0
  180. package/templates/app/docs/errors/CAGE-NAME-001.md +47 -0
  181. package/templates/app/docs/errors/CAGE-NAME-002.md +47 -0
  182. package/templates/app/docs/errors/CAGE-NAME-003.md +47 -0
  183. package/templates/app/docs/errors/CAGE-NAME-004.md +47 -0
  184. package/templates/app/docs/errors/CAGE-NAME-005.md +47 -0
  185. package/templates/app/docs/errors/CAGE-NAME-006.md +47 -0
  186. package/templates/app/docs/errors/CAGE-ORG-001.md +49 -0
  187. package/templates/app/docs/errors/CAGE-PAIR-002.md +50 -0
  188. package/templates/app/docs/errors/CAGE-QUERY-001.md +47 -0
  189. package/templates/app/docs/errors/CAGE-QUERY-002.md +47 -0
  190. package/templates/app/docs/errors/CAGE-QUERY-003.md +49 -0
  191. package/templates/app/docs/errors/CAGE-REACT-001.md +47 -0
  192. package/templates/app/docs/errors/CAGE-REACT-002.md +47 -0
  193. package/templates/app/docs/errors/CAGE-READS-001.md +47 -0
  194. package/templates/app/docs/errors/CAGE-REG-001.md +53 -0
  195. package/templates/app/docs/errors/CAGE-REG-002.md +48 -0
  196. package/templates/app/docs/errors/CAGE-REG-003.md +47 -0
  197. package/templates/app/docs/errors/CAGE-REL-001.md +64 -0
  198. package/templates/app/docs/errors/CAGE-ROUTE-001.md +47 -0
  199. package/templates/app/docs/errors/CAGE-SCOPE-001.md +47 -0
  200. package/templates/app/docs/errors/CAGE-SCOPE-002.md +47 -0
  201. package/templates/app/docs/errors/CAGE-SECRET-001.md +48 -0
  202. package/templates/app/docs/errors/CAGE-SECRET-002.md +47 -0
  203. package/templates/app/docs/errors/CAGE-SENS-001.md +48 -0
  204. package/templates/app/docs/errors/CAGE-SQL-001.md +47 -0
  205. package/templates/app/docs/errors/CAGE-SQL-002.md +47 -0
  206. package/templates/app/docs/errors/CAGE-STATE-001.md +49 -0
  207. package/templates/app/docs/errors/CAGE-STATE-002.md +47 -0
  208. package/templates/app/docs/errors/CAGE-STATE-003.md +47 -0
  209. package/templates/app/docs/errors/CAGE-STATE-004.md +47 -0
  210. package/templates/app/docs/errors/CAGE-STATE-005.md +48 -0
  211. package/templates/app/docs/errors/CAGE-STATE-010.md +48 -0
  212. package/templates/app/docs/errors/CAGE-STATE-011.md +48 -0
  213. package/templates/app/docs/errors/CAGE-STRUCT-001.md +51 -0
  214. package/templates/app/docs/errors/CAGE-STRUCT-002.md +51 -0
  215. package/templates/app/docs/errors/CAGE-SYNC-001.md +48 -0
  216. package/templates/app/docs/errors/CAGE-TEST-001.md +47 -0
  217. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +48 -0
  218. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +48 -0
  219. package/templates/app/docs/errors/README.md +307 -0
  220. package/templates/app/docs/errors/runtime.md +50 -0
  221. package/templates/app/package.json +4 -7
  222. package/templates/app/packages/contracts/package.json +1 -1
  223. package/templates/app/packages/contracts/src/{dept.ts → aggregates/dept/index.ts} +3 -3
  224. package/templates/app/packages/contracts/src/{inventory.ts → aggregates/inventory/index.ts} +3 -3
  225. package/templates/app/packages/contracts/src/{inventory-lock.ts → aggregates/inventory-lock/index.ts} +3 -3
  226. package/templates/app/packages/contracts/src/{purchase-order.ts → aggregates/purchase-order/index.ts} +3 -3
  227. package/templates/app/packages/contracts/src/{role.ts → aggregates/role/index.ts} +3 -3
  228. package/templates/app/packages/contracts/src/{user.ts → aggregates/user/index.ts} +3 -3
  229. package/templates/app/packages/contracts/src/index.ts +14 -14
  230. package/templates/app/packages/domain/package.json +4 -4
  231. package/templates/app/packages/domain/src/index.ts +4 -7
  232. package/templates/app/packages/domain/src/{erp.ts → integrations/erp.ts} +1 -1
  233. package/templates/app/packages/domain/src/modules/inventory/index.ts +2 -0
  234. package/templates/app/packages/domain/src/modules/purchase/index.ts +6 -0
  235. package/templates/app/packages/domain/src/{purchase-order.test.ts → modules/purchase/purchase-order.test.ts} +2 -2
  236. package/templates/app/packages/domain/src/{purchase-order.ts → modules/purchase/purchase-order.ts} +1 -1
  237. package/templates/app/packages/domain/src/{reactions.ts → workflows/purchase-inventory.ts} +2 -2
  238. package/templates/blank/.dockerignore +10 -0
  239. package/templates/blank/.env.example +61 -0
  240. package/templates/blank/.github/workflows/cage.yml +44 -0
  241. package/templates/blank/AGENTS.md +96 -0
  242. package/templates/blank/Dockerfile +25 -0
  243. package/templates/blank/README.md +37 -0
  244. package/templates/blank/_gitignore +8 -0
  245. package/templates/blank/apps/api/package.json +15 -0
  246. package/templates/blank/apps/api/src/main.ts +11 -0
  247. package/templates/blank/apps/api/src/worker.ts +8 -0
  248. package/templates/blank/apps/api/tsconfig.json +5 -0
  249. package/templates/blank/apps/web/index.html +13 -0
  250. package/templates/blank/apps/web/package.json +22 -0
  251. package/templates/blank/apps/web/src/app/app.tsx +44 -0
  252. package/templates/blank/apps/web/src/app/styles/global.css +516 -0
  253. package/templates/blank/apps/web/src/app/workspace-layout.tsx +70 -0
  254. package/templates/blank/apps/web/src/main.tsx +13 -0
  255. package/templates/blank/apps/web/src/modules/auth/index.ts +1 -0
  256. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +87 -0
  257. package/templates/blank/apps/web/src/modules/workspace/index.ts +1 -0
  258. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +45 -0
  259. package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
  260. package/templates/blank/apps/web/src/shared/ui/brand.tsx +11 -0
  261. package/templates/blank/apps/web/tsconfig.json +11 -0
  262. package/templates/blank/apps/web/vite.config.ts +19 -0
  263. package/templates/blank/cage.config.json +14 -0
  264. package/templates/blank/db/migrations/0001_init.sql +63 -0
  265. package/templates/blank/docs/ai/README.md +77 -0
  266. package/templates/blank/docs/ai/architecture.md +122 -0
  267. package/templates/blank/docs/ai/ontology-context.md +117 -0
  268. package/templates/blank/docs/ai/primitives.md +249 -0
  269. package/templates/blank/docs/ai/project-structure.md +123 -0
  270. package/templates/blank/docs/ai/purchase-example.md +97 -0
  271. package/templates/blank/docs/ai/recipes.md +81 -0
  272. package/templates/blank/docs/ai/relations.md +160 -0
  273. package/templates/blank/docs/ai/transfers.md +92 -0
  274. package/templates/blank/docs/ai/troubleshooting.md +60 -0
  275. package/templates/blank/docs/ai/workflow.md +139 -0
  276. package/templates/blank/docs/errors/CAGE-APPR-001.md +47 -0
  277. package/templates/blank/docs/errors/CAGE-APPR-002.md +47 -0
  278. package/templates/blank/docs/errors/CAGE-APPR-003.md +47 -0
  279. package/templates/blank/docs/errors/CAGE-APPR-004.md +47 -0
  280. package/templates/blank/docs/errors/CAGE-APPR-005.md +47 -0
  281. package/templates/blank/docs/errors/CAGE-APPR-006.md +47 -0
  282. package/templates/blank/docs/errors/CAGE-APPR-007.md +50 -0
  283. package/templates/blank/docs/errors/CAGE-APPR-010.md +48 -0
  284. package/templates/blank/docs/errors/CAGE-AUTH-001.md +47 -0
  285. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +47 -0
  286. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +47 -0
  287. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +47 -0
  288. package/templates/blank/docs/errors/CAGE-CMD-002.md +47 -0
  289. package/templates/blank/docs/errors/CAGE-CMD-003.md +47 -0
  290. package/templates/blank/docs/errors/CAGE-CONN-001.md +47 -0
  291. package/templates/blank/docs/errors/CAGE-CONN-002.md +47 -0
  292. package/templates/blank/docs/errors/CAGE-CONN-003.md +47 -0
  293. package/templates/blank/docs/errors/CAGE-CONN-004.md +47 -0
  294. package/templates/blank/docs/errors/CAGE-CONN-005.md +47 -0
  295. package/templates/blank/docs/errors/CAGE-CONN-006.md +47 -0
  296. package/templates/blank/docs/errors/CAGE-CONN-007.md +47 -0
  297. package/templates/blank/docs/errors/CAGE-CONN-008.md +47 -0
  298. package/templates/blank/docs/errors/CAGE-CONN-009.md +47 -0
  299. package/templates/blank/docs/errors/CAGE-CONN-010.md +47 -0
  300. package/templates/blank/docs/errors/CAGE-CONN-011.md +47 -0
  301. package/templates/blank/docs/errors/CAGE-CONN-012.md +47 -0
  302. package/templates/blank/docs/errors/CAGE-CREATE-001.md +52 -0
  303. package/templates/blank/docs/errors/CAGE-DECL-001.md +48 -0
  304. package/templates/blank/docs/errors/CAGE-DECL-002.md +47 -0
  305. package/templates/blank/docs/errors/CAGE-DECL-003.md +47 -0
  306. package/templates/blank/docs/errors/CAGE-DECL-004.md +47 -0
  307. package/templates/blank/docs/errors/CAGE-DEP-001.md +48 -0
  308. package/templates/blank/docs/errors/CAGE-DEP-002.md +47 -0
  309. package/templates/blank/docs/errors/CAGE-DEP-003.md +47 -0
  310. package/templates/blank/docs/errors/CAGE-DEP-004.md +47 -0
  311. package/templates/blank/docs/errors/CAGE-DEP-005.md +47 -0
  312. package/templates/blank/docs/errors/CAGE-DLQ-001.md +48 -0
  313. package/templates/blank/docs/errors/CAGE-ENV-001.md +52 -0
  314. package/templates/blank/docs/errors/CAGE-EVENT-001.md +47 -0
  315. package/templates/blank/docs/errors/CAGE-EVENT-002.md +50 -0
  316. package/templates/blank/docs/errors/CAGE-FIELD-001.md +47 -0
  317. package/templates/blank/docs/errors/CAGE-FIELD-002.md +47 -0
  318. package/templates/blank/docs/errors/CAGE-FIELD-003.md +47 -0
  319. package/templates/blank/docs/errors/CAGE-FIELD-004.md +47 -0
  320. package/templates/blank/docs/errors/CAGE-GEN-001.md +48 -0
  321. package/templates/blank/docs/errors/CAGE-GEN-002.md +47 -0
  322. package/templates/blank/docs/errors/CAGE-GRANT-001.md +49 -0
  323. package/templates/blank/docs/errors/CAGE-GRANT-002.md +48 -0
  324. package/templates/blank/docs/errors/CAGE-GRANT-003.md +47 -0
  325. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +48 -0
  326. package/templates/blank/docs/errors/CAGE-INIT-001.md +47 -0
  327. package/templates/blank/docs/errors/CAGE-INIT-002.md +49 -0
  328. package/templates/blank/docs/errors/CAGE-INIT-003.md +48 -0
  329. package/templates/blank/docs/errors/CAGE-INIT-004.md +48 -0
  330. package/templates/blank/docs/errors/CAGE-JOB-001.md +47 -0
  331. package/templates/blank/docs/errors/CAGE-JOB-002.md +47 -0
  332. package/templates/blank/docs/errors/CAGE-JOB-003.md +47 -0
  333. package/templates/blank/docs/errors/CAGE-LINT-001.md +47 -0
  334. package/templates/blank/docs/errors/CAGE-MIG-001.md +47 -0
  335. package/templates/blank/docs/errors/CAGE-MIG-002.md +47 -0
  336. package/templates/blank/docs/errors/CAGE-MIG-003.md +5 -0
  337. package/templates/blank/docs/errors/CAGE-MIG-004.md +5 -0
  338. package/templates/blank/docs/errors/CAGE-MIG-005.md +47 -0
  339. package/templates/blank/docs/errors/CAGE-NAME-001.md +47 -0
  340. package/templates/blank/docs/errors/CAGE-NAME-002.md +47 -0
  341. package/templates/blank/docs/errors/CAGE-NAME-003.md +47 -0
  342. package/templates/blank/docs/errors/CAGE-NAME-004.md +47 -0
  343. package/templates/blank/docs/errors/CAGE-NAME-005.md +47 -0
  344. package/templates/blank/docs/errors/CAGE-NAME-006.md +47 -0
  345. package/templates/blank/docs/errors/CAGE-ORG-001.md +49 -0
  346. package/templates/blank/docs/errors/CAGE-PAIR-002.md +50 -0
  347. package/templates/blank/docs/errors/CAGE-QUERY-001.md +47 -0
  348. package/templates/blank/docs/errors/CAGE-QUERY-002.md +47 -0
  349. package/templates/blank/docs/errors/CAGE-QUERY-003.md +49 -0
  350. package/templates/blank/docs/errors/CAGE-REACT-001.md +47 -0
  351. package/templates/blank/docs/errors/CAGE-REACT-002.md +47 -0
  352. package/templates/blank/docs/errors/CAGE-READS-001.md +47 -0
  353. package/templates/blank/docs/errors/CAGE-REG-001.md +53 -0
  354. package/templates/blank/docs/errors/CAGE-REG-002.md +48 -0
  355. package/templates/blank/docs/errors/CAGE-REG-003.md +47 -0
  356. package/templates/blank/docs/errors/CAGE-REL-001.md +64 -0
  357. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +47 -0
  358. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +47 -0
  359. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +47 -0
  360. package/templates/blank/docs/errors/CAGE-SECRET-001.md +48 -0
  361. package/templates/blank/docs/errors/CAGE-SECRET-002.md +47 -0
  362. package/templates/blank/docs/errors/CAGE-SENS-001.md +48 -0
  363. package/templates/blank/docs/errors/CAGE-SQL-001.md +47 -0
  364. package/templates/blank/docs/errors/CAGE-SQL-002.md +47 -0
  365. package/templates/blank/docs/errors/CAGE-STATE-001.md +49 -0
  366. package/templates/blank/docs/errors/CAGE-STATE-002.md +47 -0
  367. package/templates/blank/docs/errors/CAGE-STATE-003.md +47 -0
  368. package/templates/blank/docs/errors/CAGE-STATE-004.md +47 -0
  369. package/templates/blank/docs/errors/CAGE-STATE-005.md +48 -0
  370. package/templates/blank/docs/errors/CAGE-STATE-010.md +48 -0
  371. package/templates/blank/docs/errors/CAGE-STATE-011.md +48 -0
  372. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +51 -0
  373. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +51 -0
  374. package/templates/blank/docs/errors/CAGE-SYNC-001.md +48 -0
  375. package/templates/blank/docs/errors/CAGE-TEST-001.md +47 -0
  376. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +48 -0
  377. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +48 -0
  378. package/templates/blank/docs/errors/README.md +307 -0
  379. package/templates/blank/docs/errors/runtime.md +50 -0
  380. package/templates/blank/docs/examples/purchase-admin/README.md +5 -0
  381. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +10 -0
  382. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +14 -0
  383. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +18 -0
  384. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +663 -0
  385. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +70 -0
  386. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +13 -0
  387. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +20 -0
  388. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +2 -0
  389. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +54 -0
  390. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +1 -0
  391. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +59 -0
  392. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +1 -0
  393. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +74 -0
  394. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +60 -0
  395. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +2 -0
  396. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +210 -0
  397. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +29 -0
  398. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +15 -0
  399. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +13 -0
  400. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +28 -0
  401. package/templates/blank/docs/examples/purchase-admin/cage.config.json +114 -0
  402. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +74 -0
  403. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +57 -0
  404. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
  405. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +72 -0
  406. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +85 -0
  407. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +89 -0
  408. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +81 -0
  409. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +17 -0
  410. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +6 -0
  411. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +36 -0
  412. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +2 -0
  413. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +43 -0
  414. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +18 -0
  415. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +6 -0
  416. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +13 -0
  417. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +137 -0
  418. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +122 -0
  419. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +10 -0
  420. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +24 -0
  421. package/templates/blank/package.json +22 -0
  422. package/templates/blank/packages/contracts/package.json +16 -0
  423. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +74 -0
  424. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +85 -0
  425. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +89 -0
  426. package/templates/blank/packages/contracts/src/index.ts +55 -0
  427. package/templates/blank/packages/contracts/src/queries/index.ts +13 -0
  428. package/templates/blank/packages/contracts/tsconfig.json +5 -0
  429. package/templates/blank/packages/domain/package.json +23 -0
  430. package/templates/blank/packages/domain/src/index.ts +4 -0
  431. package/templates/blank/packages/domain/tsconfig.json +5 -0
  432. package/templates/blank/pnpm-workspace.yaml +10 -0
  433. package/templates/blank/renovate.json +5 -0
  434. package/templates/blank/tsconfig.base.json +8 -0
  435. package/dist/database.d.ts +0 -5
  436. package/dist/database.js +0 -70
  437. package/dist/database.js.map +0 -1
  438. package/managed/errors/CAGE-APPR-001.md +0 -32
  439. package/managed/errors/CAGE-APPR-002.md +0 -32
  440. package/managed/errors/CAGE-APPR-003.md +0 -32
  441. package/managed/errors/CAGE-APPR-004.md +0 -32
  442. package/managed/errors/CAGE-APPR-005.md +0 -32
  443. package/managed/errors/CAGE-APPR-006.md +0 -32
  444. package/managed/errors/CAGE-APPR-007.md +0 -32
  445. package/managed/errors/CAGE-APPR-010.md +0 -32
  446. package/managed/errors/CAGE-AUTH-001.md +0 -32
  447. package/managed/errors/CAGE-BUDGET-001.md +0 -32
  448. package/managed/errors/CAGE-BUDGET-002.md +0 -32
  449. package/managed/errors/CAGE-BUDGET-003.md +0 -32
  450. package/managed/errors/CAGE-CMD-002.md +0 -32
  451. package/managed/errors/CAGE-CMD-003.md +0 -34
  452. package/managed/errors/CAGE-CONN-001.md +0 -32
  453. package/managed/errors/CAGE-CONN-002.md +0 -32
  454. package/managed/errors/CAGE-CONN-003.md +0 -32
  455. package/managed/errors/CAGE-CONN-004.md +0 -32
  456. package/managed/errors/CAGE-CONN-005.md +0 -32
  457. package/managed/errors/CAGE-CONN-006.md +0 -32
  458. package/managed/errors/CAGE-CONN-007.md +0 -32
  459. package/managed/errors/CAGE-CONN-008.md +0 -32
  460. package/managed/errors/CAGE-CONN-009.md +0 -32
  461. package/managed/errors/CAGE-CONN-010.md +0 -32
  462. package/managed/errors/CAGE-CONN-011.md +0 -32
  463. package/managed/errors/CAGE-CONN-012.md +0 -32
  464. package/managed/errors/CAGE-CREATE-001.md +0 -32
  465. package/managed/errors/CAGE-DECL-001.md +0 -34
  466. package/managed/errors/CAGE-DECL-002.md +0 -34
  467. package/managed/errors/CAGE-DECL-003.md +0 -34
  468. package/managed/errors/CAGE-DECL-004.md +0 -34
  469. package/managed/errors/CAGE-DEP-001.md +0 -34
  470. package/managed/errors/CAGE-DEP-002.md +0 -34
  471. package/managed/errors/CAGE-DEP-003.md +0 -34
  472. package/managed/errors/CAGE-DEP-004.md +0 -34
  473. package/managed/errors/CAGE-DEP-005.md +0 -34
  474. package/managed/errors/CAGE-DLQ-001.md +0 -32
  475. package/managed/errors/CAGE-ENV-001.md +0 -32
  476. package/managed/errors/CAGE-EVENT-001.md +0 -32
  477. package/managed/errors/CAGE-EVENT-002.md +0 -32
  478. package/managed/errors/CAGE-FIELD-001.md +0 -32
  479. package/managed/errors/CAGE-FIELD-002.md +0 -32
  480. package/managed/errors/CAGE-FIELD-003.md +0 -32
  481. package/managed/errors/CAGE-FIELD-004.md +0 -32
  482. package/managed/errors/CAGE-GEN-001.md +0 -33
  483. package/managed/errors/CAGE-GEN-002.md +0 -33
  484. package/managed/errors/CAGE-GRANT-001.md +0 -32
  485. package/managed/errors/CAGE-GRANT-002.md +0 -32
  486. package/managed/errors/CAGE-GRANT-003.md +0 -32
  487. package/managed/errors/CAGE-IMPACT-001.md +0 -32
  488. package/managed/errors/CAGE-JOB-001.md +0 -32
  489. package/managed/errors/CAGE-JOB-002.md +0 -32
  490. package/managed/errors/CAGE-JOB-003.md +0 -32
  491. package/managed/errors/CAGE-LINT-001.md +0 -32
  492. package/managed/errors/CAGE-MIG-001.md +0 -32
  493. package/managed/errors/CAGE-MIG-002.md +0 -32
  494. package/managed/errors/CAGE-MIG-003.md +0 -32
  495. package/managed/errors/CAGE-MIG-004.md +0 -32
  496. package/managed/errors/CAGE-MIG-005.md +0 -32
  497. package/managed/errors/CAGE-NAME-001.md +0 -32
  498. package/managed/errors/CAGE-NAME-002.md +0 -32
  499. package/managed/errors/CAGE-NAME-003.md +0 -32
  500. package/managed/errors/CAGE-NAME-004.md +0 -32
  501. package/managed/errors/CAGE-NAME-005.md +0 -32
  502. package/managed/errors/CAGE-NAME-006.md +0 -32
  503. package/managed/errors/CAGE-ORG-001.md +0 -32
  504. package/managed/errors/CAGE-PAIR-002.md +0 -33
  505. package/managed/errors/CAGE-QUERY-001.md +0 -32
  506. package/managed/errors/CAGE-QUERY-002.md +0 -32
  507. package/managed/errors/CAGE-QUERY-003.md +0 -32
  508. package/managed/errors/CAGE-REACT-001.md +0 -32
  509. package/managed/errors/CAGE-REACT-002.md +0 -32
  510. package/managed/errors/CAGE-READS-001.md +0 -32
  511. package/managed/errors/CAGE-REG-001.md +0 -32
  512. package/managed/errors/CAGE-REG-002.md +0 -32
  513. package/managed/errors/CAGE-REG-003.md +0 -32
  514. package/managed/errors/CAGE-ROUTE-001.md +0 -32
  515. package/managed/errors/CAGE-SCOPE-001.md +0 -32
  516. package/managed/errors/CAGE-SCOPE-002.md +0 -32
  517. package/managed/errors/CAGE-SECRET-001.md +0 -32
  518. package/managed/errors/CAGE-SECRET-002.md +0 -32
  519. package/managed/errors/CAGE-SENS-001.md +0 -32
  520. package/managed/errors/CAGE-SQL-001.md +0 -32
  521. package/managed/errors/CAGE-SQL-002.md +0 -32
  522. package/managed/errors/CAGE-STATE-001.md +0 -32
  523. package/managed/errors/CAGE-STATE-002.md +0 -32
  524. package/managed/errors/CAGE-STATE-003.md +0 -32
  525. package/managed/errors/CAGE-STATE-004.md +0 -32
  526. package/managed/errors/CAGE-STATE-005.md +0 -32
  527. package/managed/errors/CAGE-STATE-010.md +0 -32
  528. package/managed/errors/CAGE-STATE-011.md +0 -32
  529. package/managed/errors/CAGE-SYNC-001.md +0 -35
  530. package/managed/errors/CAGE-TEST-001.md +0 -33
  531. package/managed/errors/CAGE-UNSAFE-001.md +0 -32
  532. package/managed/errors/CAGE-UPGRADE-001.md +0 -32
  533. package/managed/errors/README.md +0 -99
  534. package/templates/app/compose.yaml +0 -39
  535. /package/templates/app/apps/web/src/{style.css → app/styles/global.css} +0 -0
  536. /package/templates/app/packages/contracts/src/{queries.ts → queries/index.ts} +0 -0
  537. /package/templates/app/packages/domain/src/{inventory.ts → modules/inventory/inventory.ts} +0 -0
  538. /package/templates/app/packages/domain/src/{approvals.ts → modules/purchase/approvals.ts} +0 -0
  539. /package/templates/app/packages/domain/src/{jobs.ts → modules/purchase/jobs.ts} +0 -0
  540. /package/templates/app/packages/domain/src/{queries.ts → modules/purchase/queries.ts} +0 -0
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  import { z } from 'zod';
5
- import { client, useCageList, useCageQuery } from '@yss123/cage-client';
5
+ import { client, useCageList, useCageQuery, type TransferTask } from '@yss123/cage-client';
6
6
 
7
7
  /** 部门:读侧快照(敏感字段是按权限掩码后的值) */
8
8
  export const DeptSchema = z.object({
@@ -60,8 +60,8 @@ export const dept = {
60
60
  create: (input: z.input<typeof DeptInputs.create>) => client.post<Dept, DeptCreateError>('/api/dept/create', input),
61
61
  /** 修改部门名称、编码、负责人 */
62
62
  update: (id: string, input: Omit<z.input<typeof DeptInputs.update>, 'id'>, expectedVersion?: number) => client.post<Dept, DeptUpdateError>(`/api/dept/${encodeURIComponent(id)}/update`, { ...input, expectedVersion }),
63
- /** 导出 CSV:需要 Dept.export 能力 */
64
- export: (params: DeptListParams = {}) => client.post<string, never>('/api/dept/export', params),
63
+ /** 异步导出 CSV:返回任务,使用 client.transfer(id) 查状态,完成后下载。需要 Dept.export 能力。 */
64
+ export: (params: DeptListParams = {}, options: { idempotencyKey?: string } = {}) => client.post<TransferTask, 'CONFLICT'>('/api/dept/export', params, options),
65
65
  get: (id: string) => client.get<Dept>(`/api/dept/${encodeURIComponent(id)}`),
66
66
  list: (params: DeptListParams = {}) => client.get<{ items: Dept[]; total: number; page: number; pageSize: number }>('/api/dept', params as Record<string, unknown>),
67
67
  };
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  import { z } from 'zod';
5
- import { client, useCageList, useCageQuery } from '@yss123/cage-client';
5
+ import { client, useCageList, useCageQuery, type TransferTask } from '@yss123/cage-client';
6
6
 
7
7
  /** Inventory:读侧快照(敏感字段是按权限掩码后的值) */
8
8
  export const InventorySchema = z.object({
@@ -43,8 +43,8 @@ export interface InventoryListParams {
43
43
  /** 调用方法:每个命令一个;client 自动生成并附带幂等键和 CSRF 令牌 */
44
44
  export const inventory = {
45
45
  create: (input: z.input<typeof InventoryInputs.create>) => client.post<Inventory, InventoryCreateError>('/api/inventory/create', input),
46
- /** 导出 CSV:需要 Inventory.export 能力 */
47
- export: (params: InventoryListParams = {}) => client.post<string, never>('/api/inventory/export', params),
46
+ /** 异步导出 CSV:返回任务,使用 client.transfer(id) 查状态,完成后下载。需要 Inventory.export 能力。 */
47
+ export: (params: InventoryListParams = {}, options: { idempotencyKey?: string } = {}) => client.post<TransferTask, 'CONFLICT'>('/api/inventory/export', params, options),
48
48
  get: (id: string) => client.get<Inventory>(`/api/inventory/${encodeURIComponent(id)}`),
49
49
  list: (params: InventoryListParams = {}) => client.get<{ items: Inventory[]; total: number; page: number; pageSize: number }>('/api/inventory', params as Record<string, unknown>),
50
50
  };
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  import { z } from 'zod';
5
- import { client, useCageList, useCageQuery } from '@yss123/cage-client';
5
+ import { client, useCageList, useCageQuery, type TransferTask } from '@yss123/cage-client';
6
6
 
7
7
  /** InventoryLock:读侧快照(敏感字段是按权限掩码后的值) */
8
8
  export const InventoryLockSchema = z.object({
@@ -38,8 +38,8 @@ export interface InventoryLockListParams {
38
38
 
39
39
  /** 调用方法:每个命令一个;client 自动生成并附带幂等键和 CSRF 令牌 */
40
40
  export const inventoryLock = {
41
- /** 导出 CSV:需要 InventoryLock.export 能力 */
42
- export: (params: InventoryLockListParams = {}) => client.post<string, never>('/api/inventory-lock/export', params),
41
+ /** 异步导出 CSV:返回任务,使用 client.transfer(id) 查状态,完成后下载。需要 InventoryLock.export 能力。 */
42
+ export: (params: InventoryLockListParams = {}, options: { idempotencyKey?: string } = {}) => client.post<TransferTask, 'CONFLICT'>('/api/inventory-lock/export', params, options),
43
43
  get: (id: string) => client.get<InventoryLock>(`/api/inventory-lock/${encodeURIComponent(id)}`),
44
44
  list: (params: InventoryLockListParams = {}) => client.get<{ items: InventoryLock[]; total: number; page: number; pageSize: number }>('/api/inventory-lock', params as Record<string, unknown>),
45
45
  };
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  import { z } from 'zod';
5
- import { client, useCageList, useCageQuery } from '@yss123/cage-client';
5
+ import { client, useCageList, useCageQuery, type TransferTask } from '@yss123/cage-client';
6
6
 
7
7
  /** PurchaseOrder:读侧快照(敏感字段是按权限掩码后的值) */
8
8
  export const PurchaseOrderSchema = z.object({
@@ -58,8 +58,8 @@ export const purchaseOrder = {
58
58
  cancel: (id: string, expectedVersion?: number) => client.post<PurchaseOrder, PurchaseOrderCancelError>(`/api/purchase-order/${encodeURIComponent(id)}/cancel`, { expectedVersion }),
59
59
  create: (input: z.input<typeof PurchaseOrderInputs.create>) => client.post<PurchaseOrder, PurchaseOrderCreateError>('/api/purchase-order/create', input),
60
60
  submit: (id: string, expectedVersion?: number) => client.post<PurchaseOrder, PurchaseOrderSubmitError>(`/api/purchase-order/${encodeURIComponent(id)}/submit`, { expectedVersion }),
61
- /** 导出 CSV:需要 PurchaseOrder.export 能力 */
62
- export: (params: PurchaseOrderListParams = {}) => client.post<string, never>('/api/purchase-order/export', params),
61
+ /** 异步导出 CSV:返回任务,使用 client.transfer(id) 查状态,完成后下载。需要 PurchaseOrder.export 能力。 */
62
+ export: (params: PurchaseOrderListParams = {}, options: { idempotencyKey?: string } = {}) => client.post<TransferTask, 'CONFLICT'>('/api/purchase-order/export', params, options),
63
63
  get: (id: string) => client.get<PurchaseOrder>(`/api/purchase-order/${encodeURIComponent(id)}`),
64
64
  list: (params: PurchaseOrderListParams = {}) => client.get<{ items: PurchaseOrder[]; total: number; page: number; pageSize: number }>('/api/purchase-order', params as Record<string, unknown>),
65
65
  };
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  import { z } from 'zod';
5
- import { client, useCageList, useCageQuery } from '@yss123/cage-client';
5
+ import { client, useCageList, useCageQuery, type TransferTask } from '@yss123/cage-client';
6
6
 
7
7
  /** 角色:读侧快照(敏感字段是按权限掩码后的值) */
8
8
  export const RoleSchema = z.object({
@@ -71,8 +71,8 @@ export const role = {
71
71
  revokeCapability: (id: string, input: Omit<z.input<typeof RoleInputs.revokeCapability>, 'id'>, expectedVersion?: number) => client.post<Role, RoleRevokeCapabilityError>(`/api/role/${encodeURIComponent(id)}/revoke-capability`, { ...input, expectedVersion }),
72
72
  /** 设置角色在某个聚合上的数据范围(不能授出比自己更宽的范围) */
73
73
  setScope: (id: string, input: Omit<z.input<typeof RoleInputs.setScope>, 'id'>, expectedVersion?: number) => client.post<Role, RoleSetScopeError>(`/api/role/${encodeURIComponent(id)}/set-scope`, { ...input, expectedVersion }),
74
- /** 导出 CSV:需要 Role.export 能力 */
75
- export: (params: RoleListParams = {}) => client.post<string, never>('/api/role/export', params),
74
+ /** 异步导出 CSV:返回任务,使用 client.transfer(id) 查状态,完成后下载。需要 Role.export 能力。 */
75
+ export: (params: RoleListParams = {}, options: { idempotencyKey?: string } = {}) => client.post<TransferTask, 'CONFLICT'>('/api/role/export', params, options),
76
76
  get: (id: string) => client.get<Role>(`/api/role/${encodeURIComponent(id)}`),
77
77
  list: (params: RoleListParams = {}) => client.get<{ items: Role[]; total: number; page: number; pageSize: number }>('/api/role', params as Record<string, unknown>),
78
78
  };
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  import { z } from 'zod';
5
- import { client, useCageList, useCageQuery } from '@yss123/cage-client';
5
+ import { client, useCageList, useCageQuery, type TransferTask } from '@yss123/cage-client';
6
6
 
7
7
  /** 用户:读侧快照(敏感字段是按权限掩码后的值) */
8
8
  export const UserSchema = z.object({
@@ -75,8 +75,8 @@ export const user = {
75
75
  setPassword: (id: string, input: Omit<z.input<typeof UserInputs.setPassword>, 'id'>, expectedVersion?: number) => client.post<User, UserSetPasswordError>(`/api/user/${encodeURIComponent(id)}/set-password`, { ...input, expectedVersion }),
76
76
  /** 修改用户信息 */
77
77
  update: (id: string, input: Omit<z.input<typeof UserInputs.update>, 'id'>, expectedVersion?: number) => client.post<User, UserUpdateError>(`/api/user/${encodeURIComponent(id)}/update`, { ...input, expectedVersion }),
78
- /** 导出 CSV:需要 User.export 能力 */
79
- export: (params: UserListParams = {}) => client.post<string, never>('/api/user/export', params),
78
+ /** 异步导出 CSV:返回任务,使用 client.transfer(id) 查状态,完成后下载。需要 User.export 能力。 */
79
+ export: (params: UserListParams = {}, options: { idempotencyKey?: string } = {}) => client.post<TransferTask, 'CONFLICT'>('/api/user/export', params, options),
80
80
  get: (id: string) => client.get<User>(`/api/user/${encodeURIComponent(id)}`),
81
81
  list: (params: UserListParams = {}) => client.get<{ items: User[]; total: number; page: number; pageSize: number }>('/api/user', params as Record<string, unknown>),
82
82
  };
@@ -1,21 +1,21 @@
1
1
  // 生成物:由 cage gen 从 domain 声明生成,不要手改。
2
2
  /* eslint-disable */
3
3
 
4
- export * from './dept';
5
- export * from './inventory';
6
- export * from './inventory-lock';
7
- export * from './purchase-order';
8
- export * from './role';
9
- export * from './user';
4
+ export * from './aggregates/dept';
5
+ export * from './aggregates/inventory';
6
+ export * from './aggregates/inventory-lock';
7
+ export * from './aggregates/purchase-order';
8
+ export * from './aggregates/role';
9
+ export * from './aggregates/user';
10
10
  export * from './queries';
11
11
  import { can as baseCan, useCan as baseUseCan } from '@yss123/cage-client';
12
- import { DeptInputs } from './dept';
13
- import { InventoryInputs } from './inventory';
14
- import { InventoryLockInputs } from './inventory-lock';
15
- import { PurchaseOrderInputs } from './purchase-order';
16
- import { RoleInputs } from './role';
17
- import { UserInputs } from './user';
18
- export { client, configureClient, loadMe, currentUser, CageQueryError, type CageResult, type CommonError } from '@yss123/cage-client';
12
+ import { DeptInputs } from './aggregates/dept';
13
+ import { InventoryInputs } from './aggregates/inventory';
14
+ import { InventoryLockInputs } from './aggregates/inventory-lock';
15
+ import { PurchaseOrderInputs } from './aggregates/purchase-order';
16
+ import { RoleInputs } from './aggregates/role';
17
+ import { UserInputs } from './aggregates/user';
18
+ export { client, configureClient, loadMe, currentUser, CageQueryError, useTransfer, type CageResult, type CommonError, type TransferTask, type ImportReport } from '@yss123/cage-client';
19
19
 
20
20
  /** 能力目录(由代码派生):写错能力点名会编译失败 */
21
21
  export const capabilities = [
@@ -70,7 +70,7 @@ export type Capability = (typeof capabilities)[number];
70
70
  export const can = (capability: Capability): boolean => baseCan(capability);
71
71
  export const useCan = (capability: Capability): boolean => baseUseCan(capability);
72
72
 
73
- /** 各聚合的命令输入 schema:schemas.PurchaseOrder.create 可以直接给表单库做校验 */
73
+ /** 各聚合的命令输入 schema:按聚合名、命令名访问,可直接供表单库校验 */
74
74
  export const schemas = {
75
75
  Dept: DeptInputs,
76
76
  Inventory: InventoryInputs,
@@ -14,10 +14,10 @@
14
14
  "typecheck": "tsc -p tsconfig.json --noEmit"
15
15
  },
16
16
  "dependencies": {
17
- "@yss123/cage-kernel": "0.1.0",
18
- "@yss123/cage-admin": "0.1.0",
19
- "@yss123/cage-approval": "0.1.0",
20
- "@yss123/cage-connectors": "0.1.0",
17
+ "@yss123/cage-kernel": "0.2.0",
18
+ "@yss123/cage-admin": "0.2.0",
19
+ "@yss123/cage-approval": "0.2.0",
20
+ "@yss123/cage-connectors": "0.2.0",
21
21
  "zod": "^4.1.5"
22
22
  }
23
23
  }
@@ -1,9 +1,6 @@
1
1
  // 单一导出入口:CLI 抽取器、API 和 worker 都加载同一套声明。
2
2
  export * from '@yss123/cage-admin/domain';
3
- export * from './inventory.js';
4
- export * from './purchase-order.js';
5
- export * from './reactions.js';
6
- export * from './approvals.js';
7
- export * from './erp.js';
8
- export * from './queries.js';
9
- export * from './jobs.js';
3
+ export * from './modules/inventory/index.js';
4
+ export * from './modules/purchase/index.js';
5
+ export * from './workflows/purchase-inventory.js';
6
+ export * from './integrations/erp.js';
@@ -2,7 +2,7 @@
2
2
  // 本地由 worker 注册 fake;这里始终只写声明,不发送请求或读取环境变量。
3
3
  import { z } from 'zod';
4
4
  import { connector, hmacSha256, inbound, op, outbound } from '@yss123/cage-connectors';
5
- import { OrderApproved, recordErpNo, markReceived } from './purchase-order.js';
5
+ import { OrderApproved, recordErpNo, markReceived } from '../modules/purchase/index.js';
6
6
 
7
7
  export const erp = connector('erp', {
8
8
  hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' },
@@ -0,0 +1,2 @@
1
+ // 库存模块的公开声明:台账和占用记录共同属于库存业务。
2
+ export * from './inventory.js';
@@ -0,0 +1,6 @@
1
+ // 采购模块的公开声明;其他模块通过本入口依赖它,不穿透内部文件。
2
+ // index 只转导出,避免在组装入口里隐藏业务行为或产生初始化副作用。
3
+ export * from './purchase-order.js';
4
+ export * from './approvals.js';
5
+ export * from './queries.js';
6
+ export * from './jobs.js';
@@ -5,7 +5,7 @@ import { createTestEnv, type TestEnv, type TestUser } from '@yss123/cage-testkit
5
5
  import { readMigrations } from '@yss123/cage-kernel/db';
6
6
  import { systemCtx } from '@yss123/cage-kernel';
7
7
  import { fileURLToPath } from 'node:url';
8
- import * as domain from './index.js';
8
+ import * as domain from '../../index.js';
9
9
 
10
10
  let env: TestEnv;
11
11
  let buyer: TestUser;
@@ -13,7 +13,7 @@ let manager: TestUser;
13
13
  beforeAll(async () => {
14
14
  env = await createTestEnv({
15
15
  domain,
16
- migrations: readMigrations(fileURLToPath(new URL('../../../db/migrations/', import.meta.url))),
16
+ migrations: readMigrations(fileURLToPath(new URL('../../../../../db/migrations/', import.meta.url))),
17
17
  });
18
18
  buyer = await env.user({
19
19
  caps: ['PurchaseOrder.create', 'PurchaseOrder.submit', 'PurchaseOrder.cancel', 'PurchaseOrder.read'],
@@ -18,7 +18,7 @@ import {
18
18
  text,
19
19
  } from '@yss123/cage-kernel';
20
20
  import { z } from 'zod';
21
- import { Inventory } from './inventory.js';
21
+ import { Inventory } from '../inventory/index.js';
22
22
 
23
23
  export const POStatus = states('draft', 'pending_approval', 'approved', 'received', 'rejected', 'cancelled', {
24
24
  terminal: ['received', 'rejected', 'cancelled'],
@@ -1,8 +1,8 @@
1
1
  // 跨聚合资源配对:审批时同事务建锁,取消/收货时通过 outbox 释放。
2
2
  // acquires/releases 供图规则检查;map 返回 null 表示该次事件没有需要释放的资源。
3
3
  import { reaction } from '@yss123/cage-kernel';
4
- import { OrderApproved, OrderCancelled, OrderReceived } from './purchase-order.js';
5
- import { acquireLock, releaseLock } from './inventory.js';
4
+ import { OrderApproved, OrderCancelled, OrderReceived } from '../modules/purchase/index.js';
5
+ import { acquireLock, releaseLock } from '../modules/inventory/index.js';
6
6
 
7
7
  export const lockOnApprove = reaction(OrderApproved, {
8
8
  command: acquireLock,
@@ -0,0 +1,10 @@
1
+ node_modules
2
+ **/node_modules
3
+ **/dist
4
+ .git
5
+ .cage
6
+ **/.cage
7
+ generated
8
+ .env
9
+ .env.*
10
+ *.log
@@ -0,0 +1,61 @@
1
+ # Cage 业务项目配置:复制此文件为同目录的 .env,首次只填写管理员数据库连接。
2
+ # .env 位于业务项目根目录,与 package.json、cage.config.json 同级。
3
+ # pnpm exec cage init / pnpm dev / pnpm migrate 自动读取它;同名外部环境变量优先。
4
+ # 修改后重启 dev;migrate 在下次执行时读取新值。不要把 .env 提交到 Git。
5
+ # 数据库需已经存在并能连接;框架不安装 PostgreSQL、不创建数据库、不管理 Docker。
6
+
7
+ # ===== 第一步:提供已有数据库的管理员连接,执行 pnpm exec cage init =====
8
+ # 格式:postgresql://用户名:密码@主机:端口/数据库名
9
+ # 将 127.0.0.1、5432、business_db 换成实际地址、端口和已有数据库名。
10
+ # 密码中的特殊字符必须 URL 编码,例如 @ 写成 %40、# 写成 %23、% 写成 %25。
11
+ # [首次初始化必填] 管理员通常叫 postgres;若你的管理员叫 root,使用实际账号名。
12
+ # 管理员需要创建角色、schema 和授权的权限。连接的数据库必须已经存在。
13
+ # 将下面的管理员密码、主机、端口和库名改为实际值,再执行 pnpm exec cage init。
14
+ # init 会创建框架账号、生成独立随机密码和 Cookie 密钥,并自动填好下面的配置。
15
+ # 成功后管理员连接会从 .env 移除;日常开发不用再提供管理员密码。
16
+ CAGE_ADMIN_DATABASE_URL=postgresql://postgres:REPLACE_WITH_ADMIN_PASSWORD@127.0.0.1:5432/business_db
17
+
18
+ # ===== 第二步:以下配置由 init 自动填充,无需手动创建账号或编写授权 SQL =====
19
+ # 三个连接使用同一个数据库,主机、端口、库名一致,账号权限不同。
20
+ # 重复 init 会验证并复用已保存的账号,不重置密码。
21
+ # 若集群已有 Cage 账号且本项目未保存连接,需复用原凭证,不能仅凭管理员重置其他项目的密码。
22
+
23
+ # [必填] 业务写入账号 cage_app:API 和 worker 执行命令、审计和后台任务使用。
24
+ # 它有业务所需读写权限,不应使用 postgres 超级用户替代。
25
+ # CAGE_APP_DATABASE_URL=
26
+
27
+ # [必填] 安全查询账号 cage_read:仅通过安全视图读取,经数据范围过滤和敏感字段掩码。
28
+ # 不要与写入账号混用,否则会破坏读写权限隔离。
29
+ # CAGE_READ_DATABASE_URL=
30
+
31
+ # [执行迁移时必填] 迁移账号 cage_migrate:pnpm migrate 用它更新表、索引、视图和权限。
32
+ # 它连接上述同一个数据库;迁移只在手动执行命令时发生,dev 不自动执行迁移。
33
+ # 生产环境只给迁移任务配置此项,API / worker 无需获得此账号。
34
+ # CAGE_MIGRATE_DATABASE_URL=
35
+
36
+ # ===== 应用配置 =====
37
+ # [init 自动生成] Cookie 签名密钥,不是数据库密码,也不是网页登录密码。
38
+ # 自动生成 32 字节随机值;已有值保留。同一应用的多个实例使用同一值。
39
+ # CAGE_COOKIE_SECRET=
40
+
41
+ # [可选,开发默认 fake] 第三方连接器阶段:fake 使用模拟实现;test / prod 使用真实适配器。
42
+ # 本项只影响第三方外部服务,fake 阶段仍连接真实 PostgreSQL。
43
+ # test / prod 需另行配置业务连接器要求的地址与密钥,不是修改此值就完成对接。
44
+ CAGE_STAGE=fake
45
+
46
+ # [可选,Vite 默认 5173] 本地 Web 页面端口。这里选 15173,减少 Windows 保留端口冲突。
47
+ # 多个应用同时运行时,各选一个空闲端口;它与数据库端口无关。
48
+ CAGE_WEB_PORT=15173
49
+
50
+ # [可选,默认 3000] API 服务端口;本地 Web 代理自动转发到这个端口。
51
+ PORT=3000
52
+
53
+ # [可选,范例默认 0.0.0.0] API 监听地址;这里使用 127.0.0.1,仅允许本机访问。
54
+ # 需要容器内或局域网访问时改为 0.0.0.0,并按部署环境配置网络访问权限。
55
+ HOST=127.0.0.1
56
+
57
+ # ===== 仅执行数据库测试时使用;正常启动不需要 =====
58
+ # [可选] 独立、可丢弃 PostgreSQL 测试集群的管理连接,需有建库和管理角色权限。
59
+ # 测试会创建/删除临时库、初始化集群级角色;不能指向业务或生产数据库所在的集群。
60
+ # 不填写时测试工具使用内嵌真实 PostgreSQL;这仅是测试行为,dev 不会自动启动数据库。
61
+ # CAGE_TEST_DATABASE_URL=postgresql://test_admin:REPLACE_WITH_TEST_PASSWORD@127.0.0.1:5433/postgres
@@ -0,0 +1,44 @@
1
+ # 尚未配置框架发布地址时直接调用同一个 CLI 门禁。
2
+ # 框架发布后可将此任务替换为远端 app-verify.yml 的 uses 引用。
3
+ name: Cage application
4
+ on: [push, pull_request]
5
+ permissions:
6
+ contents: read
7
+ jobs:
8
+ verify:
9
+ runs-on: ubuntu-latest
10
+ services:
11
+ postgres:
12
+ image: postgres:18
13
+ env: { POSTGRES_PASSWORD: cage_ci }
14
+ ports: ['5432:5432']
15
+ options: --health-cmd "pg_isready -U postgres" --health-interval 5s --health-timeout 5s --health-retries 10
16
+ env:
17
+ CAGE_TEST_DATABASE_URL: postgres://postgres:cage_ci@localhost:5432/postgres
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with: { fetch-depth: 0 }
21
+ - uses: pnpm/action-setup@v4
22
+ with: { version: 10.14.0 }
23
+ - uses: actions/setup-node@v4
24
+ with: { node-version: 24 }
25
+ - run: pnpm install --frozen-lockfile
26
+ - run: pnpm build:app
27
+ - run: pnpm cage verify
28
+ - name: Pull request impact
29
+ if: github.event_name == 'pull_request'
30
+ env:
31
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
32
+ run: |
33
+ pnpm cage impact --base "$BASE_SHA" --format md --out .cage/impact.md
34
+ cat .cage/impact.md >> "$GITHUB_STEP_SUMMARY"
35
+ - run: pnpm audit --prod --audit-level high
36
+ - uses: actions/upload-artifact@v4
37
+ if: always()
38
+ with:
39
+ name: cage-report
40
+ include-hidden-files: true
41
+ path: |
42
+ .cage/verify.json
43
+ .cage/test-results.json
44
+ .cage/impact.md
@@ -0,0 +1,96 @@
1
+ # 本项目的业务开发说明
2
+
3
+ 这是 create-cage-app 的空白业务项目。真实运行的 domain 仅包含用户、部门和角色组织模型;从 packages/domain/src 新建客户自己的业务,再从 index.ts 导出。框架通过 @yss123/cage-* 依赖提供。
4
+
5
+ 先读 [业务开发指南](docs/ai/README.md)、[任务配方](docs/ai/recipes.md) 和 [错误码册](docs/errors/README.md)。[采购范例参考源码](docs/examples/purchase-admin/README.md) 只用于学习,未注册到应用;导读中的采购路径在 docs/examples/purchase-admin 下查找。普通业务路径仍相对项目根目录。
6
+
7
+ ## 项目自己的业务约定
8
+
9
+ 客户术语、角色权限、状态规则、第三方协议和验收标准写在本节或链接到独立文档。按客户需求新增业务,不要为了让空白页面有内容而复制采购演示、演示数据或伪造统计。
10
+
11
+ 本节位于托管区之外,cage sync 会保留。下面的托管区提供框架工作方法。
12
+
13
+ <!-- cage:begin v0.2.0 -->
14
+ ## Cage 业务开发约定(框架托管)
15
+
16
+ ### 先读,再按需求改业务
17
+
18
+ 本项目由 create-cage-app 创建。框架来自 `@yss123/cage-*` 依赖,业务写在本项目;不需要克隆框架仓库,也不要复制框架内部实现。
19
+
20
+ 先读项目说明指定的学习资料,默认入口为 `docs/ai/README.md`。第一次读 `architecture.md`、`project-structure.md` 和 `primitives.md`;具体任务读 `recipes.md`,采购全链路读 `purchase-example.md`,错误查 `docs/errors/README.md` 和 `docs/ai/troubleshooting.md`。资料相对该学习目录,项目说明可指定源码仓库中的规范资料位置。
21
+
22
+ ### 业务代码放在哪里
23
+
24
+ | 位置 | 职责 |
25
+ | --- | --- |
26
+ | `packages/domain/src/modules/<业务>` | 同业务聚合、状态、命令、事件、审批、查询、任务;模块 index.ts 公开导出 |
27
+ | `packages/domain/src/workflows`、`integrations` | 跨模块反应 / 第三方协议与映射;不堆到全局 reactions.ts、queries.ts |
28
+ | `packages/domain/src/index.ts` | 统一导出全部业务及组织模型;没导出的声明不会注册 |
29
+ | `packages/contracts/src/aggregates/<聚合>`、`queries` | 生成协议;根 index.ts 提供 @app/contracts 公共入口,只用 cage gen 更新 |
30
+ | `apps/api/src` | API/worker 薄启动入口,普通业务不手写 HTTP 路由 |
31
+ | `apps/web/src/app` | 会话、导航、布局、模块组合;main.tsx 只挂载和装配 Provider |
32
+ | `apps/web/src/modules/<业务>` | 页面、表单、专用 hooks/API/样式;从模块 index.ts 暴露页面 |
33
+ | `apps/web/src/shared` | 跨模块复用且不绑定业务的 UI、hooks、纯辅助函数 |
34
+ | `db/migrations` | 审查过的结构迁移,作用于已配置的数据库 |
35
+ | `cage.config.json` | 项目路径、检查配置、graph.labels 中文图谱名称 |
36
+ | `.env` | 本机真实连接和密钥;不提交、不输出完整内容 |
37
+
38
+ 新增业务不得继续平铺在 src 根目录。前端模块只依赖自己和 shared,由 app 通过公开入口组合;shared 不反向依赖业务。领域模块间确有读取依赖时走目标模块 index.ts;跨模块反应写 workflows。小模块不创建空层级,已有独立职责再拆文件。完整命名、目录树和示例见 `docs/ai/project-structure.md`。新模板启用 `structure: modular`,check/verify 检查目录和导入边界,遇到 CAGE-STRUCT 错误按职责修正。
39
+
40
+ ### 实现一项需求的顺序
41
+
42
+ 1. 先运行 `pnpm exec cage context "需求关键词"`;按需 `graph search` 查候选、`graph inspect` 查完整节点、`graph path` 看关系路径。确认中文匹配入口后按源码位置阅读实现;候选和子图不是全部依赖,具体条件不能凭连线推断。完整用法见 `docs/ai/ontology-context.md`。从用户需求确定字段、状态/动作、角色/范围、约束与后续动作;能由业务声明表达的不改框架。
43
+ 2. 已有业务含义变化时,修改前保存本体图基线:`pnpm exec cage analyze` 后将 `.cage/ontology.json` 另存为独立文件;或使用真实 Git 基线。
44
+ 3. 先声明 aggregate/states/command/constraints/event,再写 handler、reaction/query/approval/connector,最后接业务页面。声明使用模块顶层 `export const`,从 domain 入口导出,跨文件导出名保持唯一。
45
+ 4. 运行 `pnpm exec cage check` 和 `pnpm gen`,审查 contracts 和迁移草稿。按需运行 `pnpm exec cage impact --base-file 旧图.json`,补中文图谱名。
46
+ 5. 页面使用生成方法并处理 code/domainCode;新增能力由管理员授权。数据库结构变化审查后显式 `pnpm migrate`,dev 不代办迁移。
47
+ 6. 按改动运行必要验证,交付时说明体验步骤、授权配置、迁移,以及通过/跳过/未执行项。
48
+
49
+ ### 必守边界
50
+
51
+ - 聚合定义对象字段、状态、范围字段与不变量;命令是业务写入口。handler 只计算业务变化和读取 reads 中的依赖,不直接操作数据库、网络或文件。
52
+ - 对象关系统一放在 fields:ref 为外键,hasMany 为只读反查,manyToMany 自动生成中间表并随所属对象命令提交。前端用生成的 related 方法分页读取;不手写纯中间表聚合,不把单页结果当完整集合替换。完整例子见 docs/ai/relations.md。
53
+ - command 的 input 使用 Zod;已有记录输入必须含 id。from/to 表达状态迁移;`to: null` 只适用于已有记录并保留状态,不能靠 handler 改 status 绕过状态机。
54
+ - 写入、审计、版本、幂等和事务交给内核;不要在业务项目重建 repository、连接池或权限流水线。
55
+ - 自定义查询声明 reads,二选一使用 sql/build,只读 `safe.*`;值参数化。不得拼接 SQL、查询基表绕过范围或硬编码密钥。
56
+ - scope 描述范围字段,角色数据决定实际范围;`scope.none()` 不代表所有人可访问。`can/useCan` 只控制按钮,后端负责授权。
57
+ - 前端从 `@app/contracts` 导入生成 API/类型,按需使用 `@yss123/cage-client`;不导入 domain、内核或数据库包。
58
+ - 跨聚合写入通过 reaction 调用命令。`tx: 'same'` 共同提交/回滚,默认 outbox 异步执行。资源 acquires/releases 是图规则标签,实际占用/释放仍由命令完成;离开持有状态要检查每条释放路径。
59
+ - 审批通过 approval + route 配置,结论是 process 命令;选中审批人不等于已具备能力、范围和额度。第三方 IO 通过连接器,回调验签后调用 external 命令。
60
+ - job 的读取与调用必须列入 reads/calls。业务导入/导出放在需要的业务页面调用通用任务接口,202 只代表任务已接受;worker 必须运行。
61
+ - 已部署事件只做兼容扩展;新增字段设为 optional,不兼容含义用新事件。已执行/已发布迁移不能改写,结构更新新增迁移。
62
+ - 不手改生成物,不关闭门禁掩盖错误,不因方便自动授予生产角色新能力。unsafe 必须写明 reason/owner,不能替代普通业务声明。
63
+ - 代码注释说明职责、关键流程和设计原因;避免无业务价值的防御分支和静默兜底。维护脚本用 TypeScript,不新增 .mjs。
64
+
65
+ ### 最小命令形状
66
+
67
+ ```ts
68
+ // 片段:Order 为已导出的聚合,OrderSubmitted 为事件,业务校验按需求添加。
69
+ export const submitOrder = command(Order, {
70
+ name: 'submit',
71
+ from: 'draft',
72
+ to: 'pending_approval',
73
+ emits: [OrderSubmitted],
74
+ handler: (draft) => draft,
75
+ });
76
+ ```
77
+
78
+ 完整可添加的普通管理对象见 `docs/ai/primitives.md` 的 Note;采购模板的审批、资源、第三方示例在 `packages/domain/src`,空白模板的参考源码在 `docs/examples/purchase-admin`。先读本项目 AGENTS.md 中的模板说明,区分运行代码与参考资料。API 以当前包公开导出和生成契约为准,不发明不存在的配置和方法。
79
+
80
+ ### 启动、验证与排错
81
+
82
+ 在项目根目录执行:首次 `pnpm install`,复制并编辑 .env.example,仅提供已有库管理员连接后 `pnpm exec cage init`;再 `pnpm build:app`、`pnpm gen`,审查后 `pnpm migrate`,最后 `pnpm dev`。已有配置不能覆盖。
83
+
84
+ init 只准备账号/schema/授权并填写三个连接,不创建数据库;APP/READ/MIGRATE 指向同一个库。已有集群账号复用原密码,日常启动不用管理员。普通项目不新增 Docker 生命周期命令。
85
+
86
+ - `pnpm exec cage graph`:浏览器图谱,默认端口 15418,以终端为准。
87
+ - `pnpm exec cage context command:对象.命令 --format json --out .cage/context.json`:按完整 key 取精简上下文;默认 Markdown,可用 --depth/--limit 调整范围。CLI 每次重新抽取;Web“复制 AI 上下文”使用当前页面快照,改代码后先刷新图谱。
88
+ - `graph inspect/path` 有歧义时复制候选完整 key;path 默认沿箭头,--direction both 的逆向遍历不表示执行方向。报告中的测试/前端文件是候选,须核对;查询也会覆盖当前 .cage/ontology.json,旧基线务必另存。
89
+ - `pnpm exec cage gen --check`:生成一致性;`pnpm exec cage sync --check`:本托管区一致性。
90
+ - `pnpm exec cage test --only project`:业务测试;`pnpm verify`:类型、依赖、lint、图规则、生成、托管区、预算和测试。
91
+ - `pnpm exec cage verify --skip-tests` 表示不完整门禁;派生测试跳过不能当作通过。测试连接只用独立测试集群。
92
+ - 重要业务改动验证成功路径及有风险的反例;文档或可逆的小改动不反复跑全量数据库测试。
93
+ - CLI 报错先看 code/at/reason/fix,再查错误码册;HTTP 错误查 runtime.md。异步失败先看 worker、同步记录和死信,修复后重放,不能直接 SQL 改状态。
94
+
95
+ 框架托管区由 cage sync 更新;项目独有的业务规则写在标记之外,避免升级覆盖。
96
+ <!-- cage:end -->
@@ -0,0 +1,25 @@
1
+ # 独立业务仓库使用已发布的 @yss123/cage-* 依赖;先提交 pnpm-lock.yaml。
2
+ # --framework-path 创建的 link: 本地依赖只用于源码开发,不能拷贝进独立镜像。
3
+ FROM node:24-bookworm-slim AS build
4
+ RUN corepack enable && corepack prepare pnpm@10.14.0 --activate
5
+ WORKDIR /app
6
+ COPY . .
7
+ RUN pnpm install --frozen-lockfile && pnpm build:app
8
+ RUN pnpm --filter @app/api deploy --prod --legacy /out/api
9
+
10
+ # 发布过程先单独运行此 target,迁移账号只注入迁移任务。
11
+ FROM build AS migration
12
+ CMD ["pnpm", "cage", "migrate"]
13
+
14
+ # API 与 worker 共用运行时镜像,通过启动命令区分职责。
15
+ FROM node:24-bookworm-slim AS runtime
16
+ WORKDIR /app
17
+ COPY --from=build --chown=node:node /out/api /app
18
+ COPY --from=build --chown=node:node /app/apps/web/dist /app/web
19
+ # 系统管理与图谱共享中文显示配置;运行时工作目录同样保持为 /app。
20
+ COPY --from=build --chown=node:node /app/cage.config.json /app/cage.config.json
21
+ ENV NODE_ENV=production PORT=3000 WEB_DIR=/app/web
22
+ USER node
23
+ EXPOSE 3000
24
+ CMD ["node", "dist/main.js"]
25
+ # worker 启动命令:node dist/worker.js
@@ -0,0 +1,37 @@
1
+ # Cage 空白业务项目
2
+
3
+ 这是可直接开发业务的 TypeScript + React 项目,框架由 `@yss123/cage-*` npm 包提供。当前仅注册用户、部门、角色基础模型,保留登录、权限、系统管理、审计和异步任务;没有采购、库存、审批演示声明或演示业务表。
4
+
5
+ 先读 [AGENTS.md](AGENTS.md) 和 [业务开发指南](docs/ai/README.md)。给 Codex 等工具描述自己的业务需求,按 [任务配方](docs/ai/recipes.md) 开发即可。[采购范例导读](docs/ai/purchase-example.md) 对应 `docs/examples/purchase-admin` 中的参考源码;这些文件不参与编译、领域注册或迁移。
6
+
7
+ ## 首次启动
8
+
9
+ 需要 Node.js 24、pnpm 10,以及一个**已经存在**的 PostgreSQL 数据库。框架负责连接和表结构,不创建数据库,不管理 Docker。
10
+
11
+ 1. 在项目根目录执行 `pnpm install`。
12
+ 2. 复制 `.env.example` 为 `.env`。按其中注释,仅填写 `CAGE_ADMIN_DATABASE_URL`,指向已有数据库。密码含特殊字符时需 URL 编码。
13
+ 3. 执行 `pnpm exec cage init`。自动创建运行、只读、迁移账号和随机密码,填写 `.env` 并移除管理员连接;已有配置不会重置密码。
14
+ 4. 执行 `pnpm build:app`、`pnpm gen`。审查 `db/migrations` 后执行 `pnpm migrate`,创建本项目需要的组织与系统表。
15
+ 5. 执行 `pnpm dev`,在浏览器打开终端打印的 Web 地址。初始管理员凭证在 API 终端显示一次,请自行妥善保存。
16
+
17
+ 登录后可从“系统管理”配置用户、部门、角色与权限,再按业务需求添加模块。页面不会显示虚构业务数据。`.env` 中三个账号连接同一个数据库;日常运行不需要管理员账号。首次迁移应在为本项目准备的库中执行,接管历史业务表需要额外映射和迁移审查。
18
+
19
+ ## 添加第一个业务模块
20
+
21
+ 先读[工程目录与代码组织](docs/ai/project-structure.md)。在 `packages/domain/src/modules/<业务>` 新建声明,通过模块 index.ts 从领域总入口导出;运行 `pnpm exec cage check`、`pnpm gen`,审查生成契约和迁移。在 `apps/web/src/modules/<业务>` 使用 `@app/contracts` 实现页面和表单,通过模块公开入口接入 `app` 导航;共享 UI/工具放 `shared`。最后按需迁移,并由管理员分配新增能力。完整的 Note 对象示例见 [原语与最小业务](docs/ai/primitives.md)。
22
+
23
+ `src/main.tsx` 只挂载 React 和全局 Provider,业务不平铺到 src 根目录。`cage.config.json` 已启用 `structure: modular`,check/verify 会检查目录和依赖边界;不要关闭检查或将所有业务移入 shared 来消除提示。
24
+
25
+ ## 常用命令
26
+
27
+ | 命令 | 用途 |
28
+ | --- | --- |
29
+ | `pnpm dev` | 连接已配置的数据库,启动 API、worker 与 Web |
30
+ | `pnpm build:app` | 构建领域、API 和 Web |
31
+ | `pnpm gen` | 生成契约、SQL、图谱和迁移草稿 |
32
+ | `pnpm migrate` | 在已配置库中执行审查后的迁移 |
33
+ | `pnpm exec cage graph` | 查看本体图谱;勾选“包含系统组织模型”可看初始组织模型 |
34
+ | `pnpm verify` | 完整门禁,数据库测试须使用独立测试集群 |
35
+ | `pnpm exec cage verify --skip-tests` | 仅静态门禁,会明确标为不完整 |
36
+
37
+ 配置错误看 `.env.example`,业务错误查 [错误码册](docs/errors/README.md)。不要编辑生成契约或已执行迁移;新增业务需要生成新的迁移。
@@ -0,0 +1,8 @@
1
+ node_modules/
2
+ dist/
3
+ .cage/
4
+ generated/
5
+ .env
6
+ .env.*
7
+ !.env.example
8
+ *.log
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@app/api",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -p tsconfig.json",
7
+ "typecheck": "tsc -p tsconfig.json --noEmit",
8
+ "start": "node dist/main.js",
9
+ "worker": "node dist/worker.js"
10
+ },
11
+ "dependencies": {
12
+ "@app/domain": "workspace:*",
13
+ "@yss123/cage-http": "0.2.0"
14
+ }
15
+ }
@@ -0,0 +1,11 @@
1
+ // 业务声明决定接口。这个入口只装配框架,不需要另建连接池或手写 CRUD 路由。
2
+ // 数据库连接由框架读取项目 .env;生产环境的 WEB_DIR 指向前端构建目录。
3
+ import { createServer } from '@yss123/cage-http';
4
+ import * as domain from '@app/domain';
5
+
6
+ const server = createServer({ domain, webDir: process.env.WEB_DIR, title: 'Cage 业务工作台' });
7
+ await server.listen();
8
+
9
+ // 退出时释放连接池及数据库通知连接,便于部署时平滑替换进程。
10
+ process.once('SIGINT', () => void server.close());
11
+ process.once('SIGTERM', () => void server.close());
@@ -0,0 +1,8 @@
1
+ // worker 处理框架异步任务;增加事件反应、审批或数据导入导出后也沿用此入口。
2
+ // 空白项目没有第三方演示连接器,真实外部服务按业务需求声明和配置。
3
+ import { startWorker } from '@yss123/cage-http/worker';
4
+ import * as domain from '@app/domain';
5
+
6
+ const worker = await startWorker({ domain });
7
+ process.once('SIGINT', () => void worker.stop());
8
+ process.once('SIGTERM', () => void worker.stop());
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": { "outDir": "dist", "rootDir": "src" },
4
+ "include": ["src"]
5
+ }