@yss123/cage-cli 0.2.0 → 0.3.1

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 (629) hide show
  1. package/README.md +47 -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 +18 -2
  6. package/dist/analyze.js.map +1 -1
  7. package/dist/approval-tree.d.ts +88 -0
  8. package/dist/approval-tree.js +18 -0
  9. package/dist/approval-tree.js.map +1 -0
  10. package/dist/baseline.d.ts +8 -0
  11. package/dist/baseline.js +13 -0
  12. package/dist/baseline.js.map +1 -1
  13. package/dist/bootstrap.d.ts +20 -0
  14. package/dist/bootstrap.js +75 -0
  15. package/dist/bootstrap.js.map +1 -0
  16. package/dist/budget.d.ts +7 -0
  17. package/dist/budget.js +49 -5
  18. package/dist/budget.js.map +1 -1
  19. package/dist/capabilities.d.ts +38 -0
  20. package/dist/capabilities.js +148 -0
  21. package/dist/capabilities.js.map +1 -0
  22. package/dist/config.d.ts +31 -2
  23. package/dist/config.js +22 -0
  24. package/dist/config.js.map +1 -1
  25. package/dist/context.d.ts +14 -0
  26. package/dist/context.js +35 -2
  27. package/dist/context.js.map +1 -1
  28. package/dist/create-prompt.d.ts +7 -0
  29. package/dist/create-prompt.js +12 -0
  30. package/dist/create-prompt.js.map +1 -1
  31. package/dist/create.d.ts +21 -1
  32. package/dist/create.js +23 -1
  33. package/dist/create.js.map +1 -1
  34. package/dist/derive.d.ts +23 -0
  35. package/dist/derive.js +40 -0
  36. package/dist/derive.js.map +1 -1
  37. package/dist/dev.d.ts +6 -0
  38. package/dist/dev.js +11 -0
  39. package/dist/dev.js.map +1 -1
  40. package/dist/doctor.d.ts +98 -0
  41. package/dist/doctor.js +93 -0
  42. package/dist/doctor.js.map +1 -0
  43. package/dist/env.d.ts +6 -0
  44. package/dist/env.js +11 -0
  45. package/dist/env.js.map +1 -1
  46. package/dist/findings.d.ts +27 -0
  47. package/dist/findings.js +20 -0
  48. package/dist/findings.js.map +1 -1
  49. package/dist/gen/contracts.d.ts +28 -0
  50. package/dist/gen/contracts.js +52 -12
  51. package/dist/gen/contracts.js.map +1 -1
  52. package/dist/gen/index.d.ts +26 -0
  53. package/dist/gen/index.js +69 -1
  54. package/dist/gen/index.js.map +1 -1
  55. package/dist/gen/zod-code.d.ts +42 -0
  56. package/dist/gen/zod-code.js +178 -16
  57. package/dist/gen/zod-code.js.map +1 -1
  58. package/dist/graph-approvals.d.ts +70 -0
  59. package/dist/graph-approvals.js +93 -0
  60. package/dist/graph-approvals.js.map +1 -0
  61. package/dist/graph-business.d.ts +135 -0
  62. package/dist/graph-business.js +404 -0
  63. package/dist/graph-business.js.map +1 -0
  64. package/dist/graph-command.d.ts +17 -0
  65. package/dist/graph-command.js +21 -0
  66. package/dist/graph-command.js.map +1 -1
  67. package/dist/graph-model.d.ts +44 -0
  68. package/dist/graph-model.js +36 -3
  69. package/dist/graph-model.js.map +1 -1
  70. package/dist/graph-presentation.d.ts +16 -0
  71. package/dist/graph-presentation.js +10 -1
  72. package/dist/graph-presentation.js.map +1 -1
  73. package/dist/graph-query.d.ts +95 -0
  74. package/dist/graph-query.js +62 -0
  75. package/dist/graph-query.js.map +1 -1
  76. package/dist/graph-relations.d.ts +20 -0
  77. package/dist/graph-relations.js +42 -10
  78. package/dist/graph-relations.js.map +1 -1
  79. package/dist/graph-search.d.ts +35 -0
  80. package/dist/graph-search.js +36 -0
  81. package/dist/graph-search.js.map +1 -1
  82. package/dist/graph-snapshot.d.ts +26 -0
  83. package/dist/graph-snapshot.js +30 -1
  84. package/dist/graph-snapshot.js.map +1 -1
  85. package/dist/graph.d.ts +13 -2
  86. package/dist/graph.js +61 -4
  87. package/dist/graph.js.map +1 -1
  88. package/dist/impact.d.ts +50 -0
  89. package/dist/impact.js +62 -2
  90. package/dist/impact.js.map +1 -1
  91. package/dist/index.d.ts +10 -0
  92. package/dist/index.js +10 -0
  93. package/dist/index.js.map +1 -1
  94. package/dist/init.d.ts +12 -0
  95. package/dist/init.js +15 -0
  96. package/dist/init.js.map +1 -1
  97. package/dist/load.d.ts +10 -0
  98. package/dist/load.js +15 -0
  99. package/dist/load.js.map +1 -1
  100. package/dist/main.d.ts +6 -0
  101. package/dist/main.js +93 -5
  102. package/dist/main.js.map +1 -1
  103. package/dist/migrate.d.ts +12 -0
  104. package/dist/migrate.js +17 -0
  105. package/dist/migrate.js.map +1 -1
  106. package/dist/ontology.d.ts +67 -2
  107. package/dist/ontology.js +94 -4
  108. package/dist/ontology.js.map +1 -1
  109. package/dist/process-rules.d.ts +21 -0
  110. package/dist/process-rules.js +100 -0
  111. package/dist/process-rules.js.map +1 -0
  112. package/dist/process.d.ts +32 -0
  113. package/dist/process.js +32 -0
  114. package/dist/process.js.map +1 -1
  115. package/dist/project-structure.d.ts +5 -0
  116. package/dist/project-structure.js +10 -0
  117. package/dist/project-structure.js.map +1 -1
  118. package/dist/registration.d.ts +16 -0
  119. package/dist/registration.js +56 -0
  120. package/dist/registration.js.map +1 -0
  121. package/dist/rules.d.ts +52 -0
  122. package/dist/rules.js +58 -0
  123. package/dist/rules.js.map +1 -1
  124. package/dist/runtime-diagnostics.d.ts +27 -0
  125. package/dist/runtime-diagnostics.js +60 -0
  126. package/dist/runtime-diagnostics.js.map +1 -0
  127. package/dist/snapshots.d.ts +40 -0
  128. package/dist/snapshots.js +62 -0
  129. package/dist/snapshots.js.map +1 -0
  130. package/dist/static-check.d.ts +33 -0
  131. package/dist/static-check.js +37 -1
  132. package/dist/static-check.js.map +1 -1
  133. package/dist/sync.d.ts +11 -0
  134. package/dist/sync.js +66 -9
  135. package/dist/sync.js.map +1 -1
  136. package/dist/upgrade.d.ts +16 -0
  137. package/dist/upgrade.js +21 -0
  138. package/dist/upgrade.js.map +1 -1
  139. package/dist/verify.d.ts +14 -0
  140. package/dist/verify.js +19 -0
  141. package/dist/verify.js.map +1 -1
  142. package/dist/version.js +5 -0
  143. package/dist/version.js.map +1 -1
  144. package/graph-ui/app.js +321 -27
  145. package/graph-ui/approval-flow.js +185 -0
  146. package/graph-ui/approval-parallel.js +110 -0
  147. package/graph-ui/approval-tree.js +17 -0
  148. package/graph-ui/business.css +1011 -0
  149. package/graph-ui/business.js +566 -0
  150. package/graph-ui/flowchart-interaction.js +177 -0
  151. package/graph-ui/flowchart.js +1059 -0
  152. package/graph-ui/graph-approvals.js +92 -0
  153. package/graph-ui/graph-business.js +403 -0
  154. package/graph-ui/graph-model.js +36 -3
  155. package/graph-ui/graph-relations.js +42 -10
  156. package/graph-ui/graph-search.js +36 -0
  157. package/graph-ui/index.html +26 -12
  158. package/graph-ui/model.js +28 -0
  159. package/graph-ui/relations.js +4 -0
  160. package/graph-ui/structure.js +44 -0
  161. package/graph-ui/style.css +12 -0
  162. package/package.json +6 -4
  163. package/templates/app/.dockerignore +2 -0
  164. package/templates/app/.env.example +10 -0
  165. package/templates/app/AGENTS.md +50 -10
  166. package/templates/app/README.md +9 -5
  167. package/templates/app/_gitignore +1 -0
  168. package/templates/app/apps/api/package.json +2 -2
  169. package/templates/app/apps/api/src/main.ts +5 -1
  170. package/templates/app/apps/api/src/worker.ts +3 -0
  171. package/templates/app/apps/web/index.html +1 -0
  172. package/templates/app/apps/web/package.json +7 -3
  173. package/templates/app/apps/web/src/app/app.tsx +122 -12
  174. package/templates/app/apps/web/src/app/styles/global.css +88 -8
  175. package/templates/app/apps/web/src/app/use-session.ts +43 -0
  176. package/templates/app/apps/web/src/app/workspace-layout.tsx +58 -19
  177. package/templates/app/apps/web/src/main.tsx +5 -0
  178. package/templates/app/apps/web/src/modules/approval/components/task-operation-dialog.tsx +61 -0
  179. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +13 -5
  180. package/templates/app/apps/web/src/modules/approval/index.ts +4 -0
  181. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +89 -38
  182. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks.css +18 -0
  183. package/templates/app/apps/web/src/modules/auth/index.ts +4 -0
  184. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  185. package/templates/app/apps/web/src/modules/inventory/index.ts +4 -0
  186. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  187. package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +67 -0
  188. package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  189. package/templates/app/apps/web/src/modules/purchase/components/order-reviewers.tsx +38 -0
  190. package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  191. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  192. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +32 -3
  193. package/templates/app/apps/web/src/modules/purchase/index.ts +5 -0
  194. package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  195. package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +17 -0
  196. package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +156 -0
  197. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +54 -22
  198. package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
  199. package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  200. package/templates/app/apps/web/src/shared/hooks/use-command.ts +13 -0
  201. package/templates/app/apps/web/src/shared/lib/error-message.ts +15 -1
  202. package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
  203. package/templates/app/apps/web/src/shared/ui/approval-member-picker.css +10 -0
  204. package/templates/app/apps/web/src/shared/ui/approval-member-picker.tsx +51 -0
  205. package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  206. package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
  207. package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  208. package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  209. package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
  210. package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  211. package/templates/app/apps/web/src/shared/ui/notice.tsx +7 -0
  212. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +7 -0
  213. package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
  214. package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
  215. package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
  216. package/templates/app/apps/web/vite.config.ts +5 -0
  217. package/templates/app/cage.config.json +23 -0
  218. package/templates/app/db/migrations/0002_draft.sql +12 -0
  219. package/templates/app/db/migrations/0003_draft.sql +8 -0
  220. package/templates/app/db/migrations/0004_draft.sql +27 -0
  221. package/templates/app/deploy/nginx.conf +52 -0
  222. package/templates/app/docs/ai/README.md +28 -2
  223. package/templates/app/docs/ai/approvals.md +260 -0
  224. package/templates/app/docs/ai/architecture.md +26 -0
  225. package/templates/app/docs/ai/commenting.md +203 -0
  226. package/templates/app/docs/ai/diagnostics.md +80 -0
  227. package/templates/app/docs/ai/files.md +93 -0
  228. package/templates/app/docs/ai/intelligence.md +348 -0
  229. package/templates/app/docs/ai/ontology-context.md +59 -4
  230. package/templates/app/docs/ai/primitives.md +34 -1
  231. package/templates/app/docs/ai/project-structure.md +8 -3
  232. package/templates/app/docs/ai/purchase-example.md +35 -7
  233. package/templates/app/docs/ai/recipes.md +10 -2
  234. package/templates/app/docs/ai/routing.md +86 -0
  235. package/templates/app/docs/ai/troubleshooting.md +5 -0
  236. package/templates/app/docs/ai/workflow.md +24 -11
  237. package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
  238. package/templates/app/docs/errors/CAGE-APPR-001.md +13 -9
  239. package/templates/app/docs/errors/CAGE-APPR-002.md +2 -2
  240. package/templates/app/docs/errors/CAGE-APPR-003.md +1 -1
  241. package/templates/app/docs/errors/CAGE-APPR-004.md +4 -4
  242. package/templates/app/docs/errors/CAGE-APPR-005.md +4 -4
  243. package/templates/app/docs/errors/CAGE-APPR-006.md +29 -8
  244. package/templates/app/docs/errors/CAGE-APPR-007.md +9 -7
  245. package/templates/app/docs/errors/CAGE-APPR-010.md +5 -5
  246. package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
  247. package/templates/app/docs/errors/CAGE-AUTH-001.md +1 -1
  248. package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
  249. package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
  250. package/templates/app/docs/errors/CAGE-BUDGET-001.md +1 -1
  251. package/templates/app/docs/errors/CAGE-BUDGET-002.md +1 -1
  252. package/templates/app/docs/errors/CAGE-BUDGET-003.md +1 -1
  253. package/templates/app/docs/errors/CAGE-CMD-002.md +1 -1
  254. package/templates/app/docs/errors/CAGE-CMD-003.md +1 -1
  255. package/templates/app/docs/errors/CAGE-CONN-001.md +3 -3
  256. package/templates/app/docs/errors/CAGE-CONN-002.md +1 -1
  257. package/templates/app/docs/errors/CAGE-CONN-003.md +1 -1
  258. package/templates/app/docs/errors/CAGE-CONN-004.md +1 -1
  259. package/templates/app/docs/errors/CAGE-CONN-005.md +1 -1
  260. package/templates/app/docs/errors/CAGE-CONN-006.md +1 -1
  261. package/templates/app/docs/errors/CAGE-CONN-007.md +6 -6
  262. package/templates/app/docs/errors/CAGE-CONN-008.md +5 -5
  263. package/templates/app/docs/errors/CAGE-CONN-009.md +6 -6
  264. package/templates/app/docs/errors/CAGE-CONN-010.md +6 -6
  265. package/templates/app/docs/errors/CAGE-CONN-011.md +1 -1
  266. package/templates/app/docs/errors/CAGE-CONN-012.md +1 -1
  267. package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
  268. package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
  269. package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
  270. package/templates/app/docs/errors/CAGE-CREATE-001.md +10 -9
  271. package/templates/app/docs/errors/CAGE-DECL-001.md +2 -2
  272. package/templates/app/docs/errors/CAGE-DECL-002.md +7 -6
  273. package/templates/app/docs/errors/CAGE-DECL-003.md +1 -1
  274. package/templates/app/docs/errors/CAGE-DECL-004.md +1 -1
  275. package/templates/app/docs/errors/CAGE-DEP-001.md +2 -2
  276. package/templates/app/docs/errors/CAGE-DEP-002.md +1 -1
  277. package/templates/app/docs/errors/CAGE-DEP-003.md +2 -2
  278. package/templates/app/docs/errors/CAGE-DEP-004.md +1 -1
  279. package/templates/app/docs/errors/CAGE-DEP-005.md +1 -1
  280. package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
  281. package/templates/app/docs/errors/CAGE-DLQ-001.md +2 -2
  282. package/templates/app/docs/errors/CAGE-ENV-001.md +4 -4
  283. package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
  284. package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
  285. package/templates/app/docs/errors/CAGE-EVENT-001.md +1 -1
  286. package/templates/app/docs/errors/CAGE-EVENT-002.md +7 -7
  287. package/templates/app/docs/errors/CAGE-FIELD-001.md +2 -2
  288. package/templates/app/docs/errors/CAGE-FIELD-002.md +1 -1
  289. package/templates/app/docs/errors/CAGE-FIELD-003.md +1 -1
  290. package/templates/app/docs/errors/CAGE-FIELD-004.md +1 -1
  291. package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
  292. package/templates/app/docs/errors/CAGE-GEN-001.md +2 -2
  293. package/templates/app/docs/errors/CAGE-GEN-002.md +1 -1
  294. package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
  295. package/templates/app/docs/errors/CAGE-GRANT-001.md +3 -3
  296. package/templates/app/docs/errors/CAGE-GRANT-002.md +2 -2
  297. package/templates/app/docs/errors/CAGE-GRANT-003.md +7 -6
  298. package/templates/app/docs/errors/CAGE-IMPACT-001.md +2 -2
  299. package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
  300. package/templates/app/docs/errors/CAGE-INIT-001.md +1 -1
  301. package/templates/app/docs/errors/CAGE-INIT-002.md +1 -1
  302. package/templates/app/docs/errors/CAGE-INIT-003.md +2 -2
  303. package/templates/app/docs/errors/CAGE-INIT-004.md +1 -1
  304. package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
  305. package/templates/app/docs/errors/CAGE-JOB-001.md +1 -1
  306. package/templates/app/docs/errors/CAGE-JOB-002.md +1 -1
  307. package/templates/app/docs/errors/CAGE-JOB-003.md +1 -1
  308. package/templates/app/docs/errors/CAGE-LINT-001.md +1 -1
  309. package/templates/app/docs/errors/CAGE-MIG-001.md +1 -1
  310. package/templates/app/docs/errors/CAGE-MIG-002.md +1 -1
  311. package/templates/app/docs/errors/CAGE-MIG-005.md +1 -1
  312. package/templates/app/docs/errors/CAGE-NAME-001.md +1 -1
  313. package/templates/app/docs/errors/CAGE-NAME-002.md +1 -1
  314. package/templates/app/docs/errors/CAGE-NAME-003.md +3 -3
  315. package/templates/app/docs/errors/CAGE-NAME-004.md +1 -1
  316. package/templates/app/docs/errors/CAGE-NAME-005.md +1 -1
  317. package/templates/app/docs/errors/CAGE-NAME-006.md +1 -1
  318. package/templates/app/docs/errors/CAGE-ORG-001.md +7 -6
  319. package/templates/app/docs/errors/CAGE-PAIR-002.md +6 -5
  320. package/templates/app/docs/errors/CAGE-QUERY-001.md +1 -1
  321. package/templates/app/docs/errors/CAGE-QUERY-002.md +2 -2
  322. package/templates/app/docs/errors/CAGE-QUERY-003.md +7 -6
  323. package/templates/app/docs/errors/CAGE-REACT-001.md +3 -3
  324. package/templates/app/docs/errors/CAGE-REACT-002.md +1 -1
  325. package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
  326. package/templates/app/docs/errors/CAGE-READS-001.md +9 -6
  327. package/templates/app/docs/errors/CAGE-REG-001.md +13 -12
  328. package/templates/app/docs/errors/CAGE-REG-002.md +2 -1
  329. package/templates/app/docs/errors/CAGE-REG-003.md +1 -1
  330. package/templates/app/docs/errors/CAGE-REL-001.md +14 -14
  331. package/templates/app/docs/errors/CAGE-ROUTE-001.md +7 -6
  332. package/templates/app/docs/errors/CAGE-SCOPE-001.md +1 -1
  333. package/templates/app/docs/errors/CAGE-SCOPE-002.md +2 -2
  334. package/templates/app/docs/errors/CAGE-SECRET-001.md +2 -2
  335. package/templates/app/docs/errors/CAGE-SECRET-002.md +1 -1
  336. package/templates/app/docs/errors/CAGE-SENS-001.md +5 -5
  337. package/templates/app/docs/errors/CAGE-SQL-001.md +1 -1
  338. package/templates/app/docs/errors/CAGE-SQL-002.md +1 -1
  339. package/templates/app/docs/errors/CAGE-STATE-001.md +3 -3
  340. package/templates/app/docs/errors/CAGE-STATE-002.md +1 -1
  341. package/templates/app/docs/errors/CAGE-STATE-003.md +1 -1
  342. package/templates/app/docs/errors/CAGE-STATE-004.md +1 -1
  343. package/templates/app/docs/errors/CAGE-STATE-005.md +3 -2
  344. package/templates/app/docs/errors/CAGE-STATE-010.md +5 -5
  345. package/templates/app/docs/errors/CAGE-STATE-011.md +5 -5
  346. package/templates/app/docs/errors/CAGE-STRUCT-001.md +1 -1
  347. package/templates/app/docs/errors/CAGE-STRUCT-002.md +1 -1
  348. package/templates/app/docs/errors/CAGE-SYNC-001.md +3 -2
  349. package/templates/app/docs/errors/CAGE-TEST-001.md +1 -1
  350. package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
  351. package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
  352. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +3 -2
  353. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +2 -2
  354. package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
  355. package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
  356. package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
  357. package/templates/app/docs/errors/README.md +52 -2
  358. package/templates/app/package.json +3 -3
  359. package/templates/app/packages/contracts/package.json +1 -1
  360. package/templates/app/packages/contracts/src/aggregates/approval-member/index.ts +70 -0
  361. package/templates/app/packages/contracts/src/aggregates/dept/index.ts +10 -10
  362. package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  363. package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  364. package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +34 -12
  365. package/templates/app/packages/contracts/src/aggregates/role/index.ts +15 -15
  366. package/templates/app/packages/contracts/src/aggregates/user/index.ts +16 -16
  367. package/templates/app/packages/contracts/src/index.ts +16 -1
  368. package/templates/app/packages/contracts/src/queries/index.ts +2 -2
  369. package/templates/app/packages/domain/package.json +5 -4
  370. package/templates/app/packages/domain/src/index.ts +4 -0
  371. package/templates/app/packages/domain/src/integrations/erp.ts +15 -0
  372. package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
  373. package/templates/app/packages/domain/src/modules/inventory/index.ts +1 -0
  374. package/templates/app/packages/domain/src/modules/inventory/inventory.ts +12 -0
  375. package/templates/app/packages/domain/src/modules/purchase/approval-members.ts +54 -0
  376. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +38 -6
  377. package/templates/app/packages/domain/src/modules/purchase/index.ts +2 -0
  378. package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +224 -0
  379. package/templates/app/packages/domain/src/modules/purchase/jobs.ts +5 -0
  380. package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  381. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +125 -4
  382. package/templates/app/packages/domain/src/modules/purchase/queries.ts +5 -0
  383. package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  384. package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
  385. package/templates/blank/.dockerignore +2 -0
  386. package/templates/blank/.env.example +10 -0
  387. package/templates/blank/AGENTS.md +50 -10
  388. package/templates/blank/README.md +4 -1
  389. package/templates/blank/_gitignore +1 -0
  390. package/templates/blank/apps/api/package.json +1 -1
  391. package/templates/blank/apps/api/src/main.ts +4 -1
  392. package/templates/blank/apps/api/src/worker.ts +2 -0
  393. package/templates/blank/apps/web/index.html +1 -0
  394. package/templates/blank/apps/web/package.json +7 -3
  395. package/templates/blank/apps/web/src/app/app.tsx +80 -18
  396. package/templates/blank/apps/web/src/app/styles/global.css +90 -0
  397. package/templates/blank/apps/web/src/app/use-session.ts +43 -0
  398. package/templates/blank/apps/web/src/app/workspace-layout.tsx +30 -5
  399. package/templates/blank/apps/web/src/main.tsx +5 -0
  400. package/templates/blank/apps/web/src/modules/auth/index.ts +4 -0
  401. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +18 -1
  402. package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
  403. package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
  404. package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
  405. package/templates/blank/apps/web/src/modules/workspace/index.ts +4 -0
  406. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +17 -0
  407. package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
  408. package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
  409. package/templates/blank/apps/web/src/shared/ui/brand.tsx +10 -2
  410. package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
  411. package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
  412. package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
  413. package/templates/blank/apps/web/vite.config.ts +5 -0
  414. package/templates/blank/deploy/nginx.conf +52 -0
  415. package/templates/blank/docs/ai/README.md +28 -2
  416. package/templates/blank/docs/ai/approvals.md +260 -0
  417. package/templates/blank/docs/ai/architecture.md +26 -0
  418. package/templates/blank/docs/ai/commenting.md +203 -0
  419. package/templates/blank/docs/ai/diagnostics.md +80 -0
  420. package/templates/blank/docs/ai/files.md +93 -0
  421. package/templates/blank/docs/ai/intelligence.md +348 -0
  422. package/templates/blank/docs/ai/ontology-context.md +59 -4
  423. package/templates/blank/docs/ai/primitives.md +34 -1
  424. package/templates/blank/docs/ai/project-structure.md +8 -3
  425. package/templates/blank/docs/ai/purchase-example.md +35 -7
  426. package/templates/blank/docs/ai/recipes.md +10 -2
  427. package/templates/blank/docs/ai/routing.md +86 -0
  428. package/templates/blank/docs/ai/troubleshooting.md +5 -0
  429. package/templates/blank/docs/ai/workflow.md +24 -11
  430. package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
  431. package/templates/blank/docs/errors/CAGE-APPR-001.md +13 -9
  432. package/templates/blank/docs/errors/CAGE-APPR-002.md +2 -2
  433. package/templates/blank/docs/errors/CAGE-APPR-003.md +1 -1
  434. package/templates/blank/docs/errors/CAGE-APPR-004.md +4 -4
  435. package/templates/blank/docs/errors/CAGE-APPR-005.md +4 -4
  436. package/templates/blank/docs/errors/CAGE-APPR-006.md +29 -8
  437. package/templates/blank/docs/errors/CAGE-APPR-007.md +9 -7
  438. package/templates/blank/docs/errors/CAGE-APPR-010.md +5 -5
  439. package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
  440. package/templates/blank/docs/errors/CAGE-AUTH-001.md +1 -1
  441. package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
  442. package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
  443. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +1 -1
  444. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +1 -1
  445. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +1 -1
  446. package/templates/blank/docs/errors/CAGE-CMD-002.md +1 -1
  447. package/templates/blank/docs/errors/CAGE-CMD-003.md +1 -1
  448. package/templates/blank/docs/errors/CAGE-CONN-001.md +3 -3
  449. package/templates/blank/docs/errors/CAGE-CONN-002.md +1 -1
  450. package/templates/blank/docs/errors/CAGE-CONN-003.md +1 -1
  451. package/templates/blank/docs/errors/CAGE-CONN-004.md +1 -1
  452. package/templates/blank/docs/errors/CAGE-CONN-005.md +1 -1
  453. package/templates/blank/docs/errors/CAGE-CONN-006.md +1 -1
  454. package/templates/blank/docs/errors/CAGE-CONN-007.md +6 -6
  455. package/templates/blank/docs/errors/CAGE-CONN-008.md +5 -5
  456. package/templates/blank/docs/errors/CAGE-CONN-009.md +6 -6
  457. package/templates/blank/docs/errors/CAGE-CONN-010.md +6 -6
  458. package/templates/blank/docs/errors/CAGE-CONN-011.md +1 -1
  459. package/templates/blank/docs/errors/CAGE-CONN-012.md +1 -1
  460. package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
  461. package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
  462. package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
  463. package/templates/blank/docs/errors/CAGE-CREATE-001.md +10 -9
  464. package/templates/blank/docs/errors/CAGE-DECL-001.md +2 -2
  465. package/templates/blank/docs/errors/CAGE-DECL-002.md +7 -6
  466. package/templates/blank/docs/errors/CAGE-DECL-003.md +1 -1
  467. package/templates/blank/docs/errors/CAGE-DECL-004.md +1 -1
  468. package/templates/blank/docs/errors/CAGE-DEP-001.md +2 -2
  469. package/templates/blank/docs/errors/CAGE-DEP-002.md +1 -1
  470. package/templates/blank/docs/errors/CAGE-DEP-003.md +2 -2
  471. package/templates/blank/docs/errors/CAGE-DEP-004.md +1 -1
  472. package/templates/blank/docs/errors/CAGE-DEP-005.md +1 -1
  473. package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
  474. package/templates/blank/docs/errors/CAGE-DLQ-001.md +2 -2
  475. package/templates/blank/docs/errors/CAGE-ENV-001.md +4 -4
  476. package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
  477. package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
  478. package/templates/blank/docs/errors/CAGE-EVENT-001.md +1 -1
  479. package/templates/blank/docs/errors/CAGE-EVENT-002.md +7 -7
  480. package/templates/blank/docs/errors/CAGE-FIELD-001.md +2 -2
  481. package/templates/blank/docs/errors/CAGE-FIELD-002.md +1 -1
  482. package/templates/blank/docs/errors/CAGE-FIELD-003.md +1 -1
  483. package/templates/blank/docs/errors/CAGE-FIELD-004.md +1 -1
  484. package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
  485. package/templates/blank/docs/errors/CAGE-GEN-001.md +2 -2
  486. package/templates/blank/docs/errors/CAGE-GEN-002.md +1 -1
  487. package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
  488. package/templates/blank/docs/errors/CAGE-GRANT-001.md +3 -3
  489. package/templates/blank/docs/errors/CAGE-GRANT-002.md +2 -2
  490. package/templates/blank/docs/errors/CAGE-GRANT-003.md +7 -6
  491. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +2 -2
  492. package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
  493. package/templates/blank/docs/errors/CAGE-INIT-001.md +1 -1
  494. package/templates/blank/docs/errors/CAGE-INIT-002.md +1 -1
  495. package/templates/blank/docs/errors/CAGE-INIT-003.md +2 -2
  496. package/templates/blank/docs/errors/CAGE-INIT-004.md +1 -1
  497. package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
  498. package/templates/blank/docs/errors/CAGE-JOB-001.md +1 -1
  499. package/templates/blank/docs/errors/CAGE-JOB-002.md +1 -1
  500. package/templates/blank/docs/errors/CAGE-JOB-003.md +1 -1
  501. package/templates/blank/docs/errors/CAGE-LINT-001.md +1 -1
  502. package/templates/blank/docs/errors/CAGE-MIG-001.md +1 -1
  503. package/templates/blank/docs/errors/CAGE-MIG-002.md +1 -1
  504. package/templates/blank/docs/errors/CAGE-MIG-005.md +1 -1
  505. package/templates/blank/docs/errors/CAGE-NAME-001.md +1 -1
  506. package/templates/blank/docs/errors/CAGE-NAME-002.md +1 -1
  507. package/templates/blank/docs/errors/CAGE-NAME-003.md +3 -3
  508. package/templates/blank/docs/errors/CAGE-NAME-004.md +1 -1
  509. package/templates/blank/docs/errors/CAGE-NAME-005.md +1 -1
  510. package/templates/blank/docs/errors/CAGE-NAME-006.md +1 -1
  511. package/templates/blank/docs/errors/CAGE-ORG-001.md +7 -6
  512. package/templates/blank/docs/errors/CAGE-PAIR-002.md +6 -5
  513. package/templates/blank/docs/errors/CAGE-QUERY-001.md +1 -1
  514. package/templates/blank/docs/errors/CAGE-QUERY-002.md +2 -2
  515. package/templates/blank/docs/errors/CAGE-QUERY-003.md +7 -6
  516. package/templates/blank/docs/errors/CAGE-REACT-001.md +3 -3
  517. package/templates/blank/docs/errors/CAGE-REACT-002.md +1 -1
  518. package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
  519. package/templates/blank/docs/errors/CAGE-READS-001.md +9 -6
  520. package/templates/blank/docs/errors/CAGE-REG-001.md +13 -12
  521. package/templates/blank/docs/errors/CAGE-REG-002.md +2 -1
  522. package/templates/blank/docs/errors/CAGE-REG-003.md +1 -1
  523. package/templates/blank/docs/errors/CAGE-REL-001.md +14 -14
  524. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +7 -6
  525. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +1 -1
  526. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +2 -2
  527. package/templates/blank/docs/errors/CAGE-SECRET-001.md +2 -2
  528. package/templates/blank/docs/errors/CAGE-SECRET-002.md +1 -1
  529. package/templates/blank/docs/errors/CAGE-SENS-001.md +5 -5
  530. package/templates/blank/docs/errors/CAGE-SQL-001.md +1 -1
  531. package/templates/blank/docs/errors/CAGE-SQL-002.md +1 -1
  532. package/templates/blank/docs/errors/CAGE-STATE-001.md +3 -3
  533. package/templates/blank/docs/errors/CAGE-STATE-002.md +1 -1
  534. package/templates/blank/docs/errors/CAGE-STATE-003.md +1 -1
  535. package/templates/blank/docs/errors/CAGE-STATE-004.md +1 -1
  536. package/templates/blank/docs/errors/CAGE-STATE-005.md +3 -2
  537. package/templates/blank/docs/errors/CAGE-STATE-010.md +5 -5
  538. package/templates/blank/docs/errors/CAGE-STATE-011.md +5 -5
  539. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +1 -1
  540. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +1 -1
  541. package/templates/blank/docs/errors/CAGE-SYNC-001.md +3 -2
  542. package/templates/blank/docs/errors/CAGE-TEST-001.md +1 -1
  543. package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
  544. package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
  545. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +3 -2
  546. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +2 -2
  547. package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
  548. package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
  549. package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
  550. package/templates/blank/docs/errors/README.md +52 -2
  551. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +5 -1
  552. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +3 -0
  553. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +122 -12
  554. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +88 -8
  555. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
  556. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +58 -19
  557. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +5 -0
  558. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/components/task-operation-dialog.tsx +61 -0
  559. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +13 -5
  560. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +4 -0
  561. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +89 -38
  562. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks.css +18 -0
  563. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +4 -0
  564. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  565. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +4 -0
  566. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  567. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +67 -0
  568. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  569. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-reviewers.tsx +38 -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 +32 -3
  573. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +5 -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 +17 -0
  576. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +156 -0
  577. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +54 -22
  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 +13 -0
  581. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +15 -1
  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/approval-member-picker.css +10 -0
  584. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/approval-member-picker.tsx +51 -0
  585. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  586. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
  587. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  588. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  589. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
  590. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  591. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +7 -0
  592. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +7 -0
  593. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
  594. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
  595. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
  596. package/templates/blank/docs/examples/purchase-admin/cage.config.json +23 -0
  597. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/approval-member/index.ts +70 -0
  598. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +10 -10
  599. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  600. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  601. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +34 -12
  602. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +15 -15
  603. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +16 -16
  604. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +16 -1
  605. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +2 -2
  606. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +4 -0
  607. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +15 -0
  608. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
  609. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +1 -0
  610. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +12 -0
  611. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approval-members.ts +54 -0
  612. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +38 -6
  613. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +2 -0
  614. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +224 -0
  615. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +5 -0
  616. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  617. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +125 -4
  618. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +5 -0
  619. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  620. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
  621. package/templates/blank/package.json +3 -3
  622. package/templates/blank/packages/contracts/package.json +1 -1
  623. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +10 -10
  624. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +15 -15
  625. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +16 -16
  626. package/templates/blank/packages/contracts/src/index.ts +1 -1
  627. package/templates/blank/packages/contracts/src/queries/index.ts +1 -1
  628. package/templates/blank/packages/domain/package.json +5 -4
  629. package/templates/blank/packages/domain/src/index.ts +2 -1
@@ -1,22 +1,39 @@
1
- // 根组件恢复会话并选择登录页/应用壳,不放客户业务的表单和数据请求。
2
- import { useEffect, useState } from 'react';
3
- import { loadMe } from '@app/contracts';
1
+ /**
2
+ * 空白应用的路由组合层,连接登录、工作台和成员目录的公开模块入口。
3
+ * 先恢复会话,再按 URL 展示页面;认证失败与网络错误分开处理,保留可回跳的原始地址。
4
+ * 新业务路由在此组合到 Outlet,模块内部实现不直接跨目录互相导入。
5
+ */
6
+ // 页面身份交给 React Router;会话恢复、布局和业务模块在应用层组合。
7
+ import { BrowserRouter, Navigate, Route, Routes, useLocation } from 'react-router-dom';
4
8
  import { LoginPage } from '../modules/auth';
9
+ import { HomePage } from '../modules/workspace';
10
+ import { UsersPage, UserDetailPage } from '../modules/directory';
5
11
  import { Brand } from '../shared/ui/brand';
12
+ import { PageState } from '../shared/ui/page-state';
13
+ import { RequireCapability } from '../shared/ui/require-capability';
14
+ import { loginReturnTo } from '../shared/lib/navigation';
15
+ import { useSession } from './use-session';
6
16
  import { WorkspaceLayout } from './workspace-layout';
7
17
 
18
+ /**
19
+ * 安装 BrowserRouter 作为页面身份来源;生产服务器须为业务深链接提供 SPA 回退。
20
+ */
8
21
  export function App() {
9
- const [session, setSession] = useState<'loading' | 'guest' | 'ready' | 'error'>('loading');
22
+ return (
23
+ <BrowserRouter>
24
+ <AppRoutes />
25
+ </BrowserRouter>
26
+ );
27
+ }
10
28
 
11
- async function restoreSession() {
12
- setSession('loading');
13
- const result = await loadMe();
14
- // 未登录进入表单;服务故障单独展示,避免把连接失败误当作需要重新登录。
15
- setSession(result.ok ? 'ready' : result.code === 'UNAUTHENTICATED' ? 'guest' : 'error');
16
- }
17
- useEffect(() => {
18
- void restoreSession();
19
- }, []);
29
+ /**
30
+ * 依据 useSession 的加载、未认证、就绪和故障状态生成路由。
31
+ * 登录回跳经 loginReturnTo 验证;成员列表和详情要求 User.read,未知路径呈现独立 404 状态。
32
+ * 前端守卫只控制交互,成员的可见范围和字段掩码仍由服务端执行。
33
+ */
34
+ function AppRoutes() {
35
+ const { session, restore, onLogin, onLogout } = useSession();
36
+ const location = useLocation();
20
37
 
21
38
  if (session === 'loading')
22
39
  return (
@@ -31,14 +48,59 @@ export function App() {
31
48
  <Brand />
32
49
  <h1>暂时无法连接工作台</h1>
33
50
  <p role="alert">请检查网络和 API 服务,然后重新尝试。</p>
34
- <button className="primary" onClick={restoreSession}>
51
+ <button className="primary" onClick={restore}>
35
52
  重新连接<span aria-hidden="true">↗</span>
36
53
  </button>
37
54
  </main>
38
55
  );
39
- return session === 'guest' ? (
40
- <LoginPage onLogin={() => setSession('ready')} />
41
- ) : (
42
- <WorkspaceLayout onLogout={() => setSession('guest')} />
56
+ const login = `/login?returnTo=${encodeURIComponent(location.pathname + location.search + location.hash)}`;
57
+ return (
58
+ <Routes>
59
+ <Route
60
+ path="/login"
61
+ element={
62
+ session === 'ready' ? (
63
+ <Navigate to={loginReturnTo(location.search, '/workspace')} replace />
64
+ ) : (
65
+ <LoginPage onLogin={onLogin} />
66
+ )
67
+ }
68
+ />
69
+ <Route
70
+ element={
71
+ session === 'ready' ? <WorkspaceLayout onLogout={onLogout} /> : <Navigate to={login} replace />
72
+ }
73
+ >
74
+ <Route index element={<Navigate to="/workspace" replace />} />
75
+ <Route path="workspace" element={<HomePage />} />
76
+ <Route
77
+ path="directory/users"
78
+ element={
79
+ <RequireCapability capability="User.read" home="/workspace">
80
+ <UsersPage />
81
+ </RequireCapability>
82
+ }
83
+ />
84
+ <Route
85
+ path="directory/users/:id"
86
+ element={
87
+ <RequireCapability capability="User.read" home="/workspace">
88
+ <UserDetailPage />
89
+ </RequireCapability>
90
+ }
91
+ />
92
+ <Route
93
+ path="*"
94
+ element={
95
+ <PageState
96
+ title="页面不存在"
97
+ description="请检查地址,或从工作空间导航进入已有页面。"
98
+ to="/workspace"
99
+ label="返回工作台"
100
+ />
101
+ }
102
+ />
103
+ </Route>
104
+ </Routes>
43
105
  );
44
106
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 空白应用的主题、品牌、登录布局、工作台外壳与成员目录样式,独立于采购模板维护。
3
+ * 颜色和间距供共享 UI 复用;成员详情与空状态只负责呈现真实接口结果或尚未添加模块的状态。
4
+ * 布局样式不授予管理能力,入口显示条件仍由组件与真实授权控制。
5
+ */
1
6
  /* 空白工作台以留白、细线和深绿建立层次;这里不包含演示统计或客户业务样式。 */
2
7
  @import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap');
3
8
 
@@ -514,3 +519,88 @@ button {
514
519
  .session-state .primary {
515
520
  min-width: 200px;
516
521
  }
522
+
523
+ /* 目录复用真实组织数据,独立列表与详情是业务模块的最小导航参考。 */
524
+ .directory-intro {
525
+ display: flex;
526
+ gap: 16px;
527
+ align-items: center;
528
+ margin: 0 0 24px;
529
+ font-size: 12px;
530
+ color: var(--muted);
531
+ }
532
+ .directory-panel {
533
+ border: 1px solid var(--line);
534
+ border-radius: 7px;
535
+ background: #fdfefb;
536
+ overflow: hidden;
537
+ }
538
+ .directory-panel table {
539
+ width: 100%;
540
+ border-collapse: collapse;
541
+ text-align: left;
542
+ }
543
+ .directory-panel th,
544
+ .directory-panel td {
545
+ padding: 18px 24px;
546
+ border-bottom: 1px solid var(--line);
547
+ font-size: 12px;
548
+ }
549
+ .directory-panel th {
550
+ background: #f1f5eb;
551
+ color: var(--muted);
552
+ font-size: 11px;
553
+ font-weight: 500;
554
+ }
555
+ .record-link {
556
+ color: var(--green);
557
+ text-decoration: underline;
558
+ text-decoration-color: #c6d5b5;
559
+ text-underline-offset: 4px;
560
+ }
561
+ .record-link:hover {
562
+ text-decoration-color: var(--green);
563
+ }
564
+ .directory-pagination {
565
+ display: flex;
566
+ justify-content: space-between;
567
+ align-items: center;
568
+ padding: 20px 24px;
569
+ color: var(--muted);
570
+ font-size: 11px;
571
+ }
572
+ .directory-pagination button {
573
+ padding: 8px 12px;
574
+ margin-left: 8px;
575
+ background: #f1f5eb;
576
+ color: var(--green);
577
+ border: 1px solid var(--line);
578
+ border-radius: 4px;
579
+ }
580
+ .directory-empty {
581
+ text-align: center;
582
+ padding: 48px;
583
+ color: var(--muted);
584
+ font-size: 13px;
585
+ }
586
+ .record-facts {
587
+ display: grid;
588
+ grid-template-columns: repeat(2, minmax(0, 1fr));
589
+ margin: 0;
590
+ padding: 8px 24px;
591
+ gap: 0 36px;
592
+ }
593
+ .record-facts > div {
594
+ padding: 24px 0;
595
+ border-bottom: 1px solid var(--line);
596
+ }
597
+ .record-facts dt {
598
+ color: var(--muted);
599
+ font-size: 11px;
600
+ margin-bottom: 12px;
601
+ }
602
+ .record-facts dd {
603
+ margin: 0;
604
+ font-size: 14px;
605
+ overflow-wrap: anywhere;
606
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * 应用会话生命周期:首次加载 /me,并把 SDK 的账号退出或失效通知同步到路由状态。
3
+ * 与 URL 路由分离,网络故障不会被误判成未登录;查询缓存不能跨账号继续使用。
4
+ */
5
+ // 应用会话与 URL 导航分别管理:401 才进入登录,网络故障保留原地址并允许重试。
6
+ import { useCallback, useEffect, useState } from 'react';
7
+ import { useQueryClient } from '@tanstack/react-query';
8
+ import { client, loadMe } from '@app/contracts';
9
+
10
+ /**
11
+ * 在 QueryClientProvider 内使用。挂载时恢复用户,卸载时解除 SDK 订阅。
12
+ * 返回 session:loading 为恢复中,guest 为未认证,ready 为已加载身份,error 为其他恢复失败。
13
+ * restore 可重试恢复;onLogin/onLogout 由已完成认证动作的页面调用,只更新应用状态。
14
+ * 账号失效时发起取消查询并清空缓存;这里不负责服务端退出操作,也不保证取消已提交的业务命令。
15
+ */
16
+ export function useSession() {
17
+ const [session, setSession] = useState<'loading' | 'guest' | 'ready' | 'error'>('loading');
18
+ const cache = useQueryClient();
19
+ /**
20
+ * 每次恢复先显示 loading,再按 loadMe 的明确结果分类;只有 UNAUTHENTICATED 进入 guest。
21
+ */
22
+ const restore = useCallback(async () => {
23
+ setSession('loading');
24
+ const result = await loadMe();
25
+ setSession(result.ok ? 'ready' : result.code === 'UNAUTHENTICATED' ? 'guest' : 'error');
26
+ }, []);
27
+
28
+ useEffect(() => {
29
+ const unsubscribe = client.subscribe((_snapshot, reason) => {
30
+ if (reason === 'loaded') return;
31
+ // 先取消在途查询,再清除上一账号的缓存;路由守卫保留 URL 并决定登录回跳。
32
+ void cache.cancelQueries();
33
+ cache.clear();
34
+ setSession('guest');
35
+ });
36
+ void restore();
37
+ return () => {
38
+ unsubscribe();
39
+ };
40
+ }, [cache, restore]);
41
+
42
+ return { session, restore, onLogin: () => setSession('ready'), onLogout: () => setSession('guest') };
43
+ }
@@ -1,11 +1,19 @@
1
+ /**
2
+ * 已登录空白应用的公共外壳,装配品牌、导航、账号信息、退出登录和子页面 Outlet。
3
+ * 成员目录和系统管理入口依据 User.read 能力显示;该显示判断不代表拥有全部管理操作。
4
+ */
1
5
  // 应用壳负责导航和账号状态;具体页面通过业务模块的公开入口组合。
2
6
  import { useState } from 'react';
7
+ import { NavLink, Outlet, useLocation } from 'react-router-dom';
3
8
  import { useQueryClient } from '@tanstack/react-query';
4
9
  import { client, currentUser, useCan } from '@app/contracts';
5
10
  import { errorMessages } from '../shared/lib/error-message';
6
11
  import { Brand } from '../shared/ui/brand';
7
- import { HomePage } from '../modules/workspace';
8
12
 
13
+ /**
14
+ * 从路由计算当前位置标题,读取当前账号与能力,承载各业务模块页面。
15
+ * onLogout 由 app 提供,退出请求成功并清空缓存后调用;失败在当前页面显示原因。
16
+ */
9
17
  export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
10
18
  // 能力只决定界面入口是否展示;系统管理接口还会再次校验授权。
11
19
  const canManage = useCan('User.read');
@@ -13,7 +21,19 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
13
21
  const [error, setError] = useState('');
14
22
  const user = currentUser();
15
23
  const cache = useQueryClient();
24
+ const location = useLocation();
25
+ const page = location.pathname.startsWith('/directory/users/')
26
+ ? '成员详情'
27
+ : location.pathname === '/directory/users'
28
+ ? '成员目录'
29
+ : location.pathname === '/workspace'
30
+ ? '工作台'
31
+ : '页面';
16
32
 
33
+ /**
34
+ * 等待 SDK 结束服务端会话,成功才清除查询缓存并通知 app。
35
+ * 失败不伪造已退出状态;按钮在结果返回前保持忙碌。
36
+ */
17
37
  async function logout() {
18
38
  setBusy(true);
19
39
  const result = await client.logout();
@@ -29,9 +49,14 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
29
49
  <aside className="sidebar">
30
50
  <Brand />
31
51
  <span className="sidebar-label">工作空间</span>
32
- <a className="nav-item active" href="/" aria-current="page">
52
+ <NavLink className={({ isActive }) => `nav-item${isActive ? ' active' : ''}`} to="/workspace">
33
53
  <span aria-hidden="true">◫</span>工作台<span className="nav-arrow">↗</span>
34
- </a>
54
+ </NavLink>
55
+ {canManage && (
56
+ <NavLink className={({ isActive }) => `nav-item${isActive ? ' active' : ''}`} to="/directory/users">
57
+ <span aria-hidden="true">♧</span>成员目录<span className="nav-arrow">↗</span>
58
+ </NavLink>
59
+ )}
35
60
  {canManage && (
36
61
  <a className="nav-item" href="/admin/">
37
62
  <span aria-hidden="true">⚙</span>系统管理<span className="nav-arrow">↗</span>
@@ -46,7 +71,7 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
46
71
  <header className="topbar">
47
72
  <span>
48
73
  工作空间<span className="breadcrumb-divider">/</span>
49
- <strong>工作台</strong>
74
+ <strong>{page}</strong>
50
75
  </span>
51
76
  <div className="account">
52
77
  <span className="avatar">{user?.name.slice(0, 1)}</span>
@@ -62,7 +87,7 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
62
87
  {error}
63
88
  </p>
64
89
  )}
65
- <HomePage />
90
+ <Outlet />
66
91
  </main>
67
92
  </div>
68
93
  </div>
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 空白业务应用的浏览器启动入口,创建共享 QueryClient 并挂载 app 路由。
3
+ * 新增业务页面使用同一 Provider 内的生成查询 hooks;此处只装配前端,不注册领域或连接数据库。
4
+ * 全局样式由入口加载,会话失效与账号切换时的查询清理由 useSession 负责。
5
+ */
1
6
  // 浏览器入口只负责挂载和全局 Provider。QueryClient 让新增模块可直接使用生成查询 hooks。
2
7
  import { createRoot } from 'react-dom/client';
3
8
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -1 +1,5 @@
1
+ /**
2
+ * auth 模块的公开导出边界,向 app 提供登录页面。
3
+ * 其他模块通过这个入口组合页面,不依赖内部页面文件路径;具体读取与交互留在实现文件。
4
+ */
1
5
  export { LoginPage } from './pages/login-page';
@@ -1,13 +1,27 @@
1
+ /**
2
+ * 空白应用的登录表单,使用客户端完成认证并由 app 决定成功后的导航。
3
+ * SDK 先认证再读取当前用户和能力,两阶段都成功才通知 app;身份读取失败保留在登录页展示。
4
+ * 账号密码仅用于本次提交,不在本组件持久化或输出日志。
5
+ */
1
6
  // 认证模块拥有登录表单;登录后的导航由 app 组合层处理。
2
7
  import { useState, type FormEvent } from 'react';
3
8
  import { client } from '@app/contracts';
4
9
  import { errorMessages } from '../../../shared/lib/error-message';
5
10
  import { Brand } from '../../../shared/ui/brand';
6
11
 
12
+ /**
13
+ * 维护本地忙碌与错误状态,使用统一错误文案;成功调用 onLogin 更新应用会话状态。
14
+ * 页面不直接消费未验证的 returnTo,也不会把网络错误当成登录成功。
15
+ */
7
16
  export function LoginPage({ onLogin }: { onLogin: () => void }) {
8
17
  const [busy, setBusy] = useState(false);
9
18
  const [error, setError] = useState('');
10
19
 
20
+ /**
21
+ * 读取表单中的账号密码并等待 client.login;SDK 完成会话协议与用户能力同步。
22
+ * 返回失败结果时保留页面并提示原因,成功后回跳由 app 路由处理。
23
+ * NOT_FOUND 来自认证后读取当前身份的 GET 结果,单独提示服务配置问题,不误报为账号密码错误。
24
+ */
11
25
  async function submit(event: FormEvent<HTMLFormElement>) {
12
26
  event.preventDefault();
13
27
  const form = new FormData(event.currentTarget);
@@ -17,7 +31,10 @@ export function LoginPage({ onLogin }: { onLogin: () => void }) {
17
31
  const result = await client.login(String(form.get('username')), String(form.get('password')));
18
32
  setBusy(false);
19
33
  if (result.ok) onLogin();
20
- else setError(errorMessages[result.code]);
34
+ else if (result.code === 'NOT_FOUND') {
35
+ // login 的返回类型包含 loadMe 的读取错误;先处理该分支,剩余代码仍由 CommonError 映射穷尽检查。
36
+ setError('无法加载当前登录信息,请检查 API 配置或联系管理员。');
37
+ } else setError(errorMessages[result.code]);
21
38
  }
22
39
 
23
40
  return (
@@ -0,0 +1,7 @@
1
+ /**
2
+ * directory 模块的公开导出边界,向 app 提供成员列表及独立详情页。
3
+ * 其他模块通过这个入口组合页面,不依赖内部页面文件路径;具体读取与交互留在实现文件。
4
+ */
5
+ // 空白模板利用已有组织模型演示列表/详情路由,不注册额外客户业务或演示数据。
6
+ export { UsersPage } from './pages/users-page';
7
+ export { UserDetailPage } from './pages/user-detail-page';
@@ -0,0 +1,78 @@
1
+ /**
2
+ * 成员详情路由,从地址栏独立校验和加载成员,支持直接访问与刷新。
3
+ * 姓名、联系方式等均来自安全契约结果,敏感字段是否可见由后端决定。
4
+ */
5
+ import { Link, useParams } from 'react-router-dom';
6
+ import { UserSchema, useUser } from '@app/contracts';
7
+ import { PageState, QueryFailure } from '../../../shared/ui/page-state';
8
+
9
+ /** ID 来自地址栏,详情不依赖“先打开列表”的内存对象,也不自行放宽读侧权限。 */
10
+ /**
11
+ * 校验 URL 中的成员 id,非法时显示地址错误与返回目录入口;通过后才挂载读取组件。
12
+ */
13
+ export function UserDetailPage() {
14
+ const { id } = useParams();
15
+ const parsed = UserSchema.shape.id.safeParse(id);
16
+ if (!parsed.success)
17
+ return <PageState title="成员地址无效" description="请从成员目录选择有效记录。" to="/directory/users" />;
18
+ return <UserDetail id={parsed.data} />;
19
+ }
20
+
21
+ /**
22
+ * 对合法 id 调用 useUser,分别呈现加载、权限/范围/网络错误及真实成员信息。
23
+ * 电话邮箱为空时显示未填写;该展示不能恢复被服务端掩码或裁剪的原始字段。
24
+ */
25
+ function UserDetail({ id }: { id: string }) {
26
+ const query = useUser(id);
27
+ if (query.isPending)
28
+ return (
29
+ <p className="muted" role="status">
30
+ 正在读取成员详情…
31
+ </p>
32
+ );
33
+ if (query.isError)
34
+ return <QueryFailure error={query.error} to="/directory/users" retry={() => void query.refetch()} />;
35
+ const user = query.data;
36
+ return (
37
+ <>
38
+ <div className="page-heading">
39
+ <div>
40
+ <p className="eyebrow">成员详情</p>
41
+ <h1>{user.name}</h1>
42
+ <p className="muted">联系方式按当前账号的权限展示。</p>
43
+ </div>
44
+ <Link className="route-link" to="/directory/users">
45
+ ← 返回成员目录
46
+ </Link>
47
+ </div>
48
+ <section className="directory-panel">
49
+ <dl className="record-facts">
50
+ <div>
51
+ <dt>账号</dt>
52
+ <dd>{user.username}</dd>
53
+ </div>
54
+ <div>
55
+ <dt>状态</dt>
56
+ <dd>{user.status === 'active' ? '使用中' : '已停用'}</dd>
57
+ </div>
58
+ <div>
59
+ <dt>电话</dt>
60
+ <dd>{user.phone ?? '未填写'}</dd>
61
+ </div>
62
+ <div>
63
+ <dt>邮箱</dt>
64
+ <dd>{user.email ?? '未填写'}</dd>
65
+ </div>
66
+ <div>
67
+ <dt>成员 ID</dt>
68
+ <dd>{user.id}</dd>
69
+ </div>
70
+ <div>
71
+ <dt>加入时间</dt>
72
+ <dd>{new Date(user.createdAt).toLocaleString('zh-CN')}</dd>
73
+ </div>
74
+ </dl>
75
+ </section>
76
+ </>
77
+ );
78
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * 组织成员的只读目录,使用生成的 useUserList 读取当前账号可访问的安全投影。
3
+ * 分页存入 URL,姓名排序、每页二十条;不会直接访问组织基表或承担账号维护。
4
+ */
5
+ import { Link, useSearchParams } from 'react-router-dom';
6
+ import { useUserList } from '@app/contracts';
7
+ import { QueryFailure } from '../../../shared/ui/page-state';
8
+
9
+ /** 列表来自真实安全接口;分页写入 URL,使刷新、分享和前进后退保留当前页。 */
10
+ /**
11
+ * 从 page 查询参数恢复页码,非法或非正整数按第一页处理。
12
+ * 加载、查询失败与空列表分别展示;列表 total 是当前读取范围的结果,详情链接使用成员 ID。
13
+ */
14
+ export function UsersPage() {
15
+ const [search, setSearch] = useSearchParams();
16
+ const requested = Number(search.get('page') ?? 1);
17
+ const page = Number.isSafeInteger(requested) && requested > 0 ? requested : 1;
18
+ const query = useUserList({ page, pageSize: 20, sort: 'name' });
19
+ /**
20
+ * 更新页码并保留其他查询参数,第一页移除 page,让浏览器历史承担前进后退。
21
+ */
22
+ function go(next: number) {
23
+ const params = new URLSearchParams(search);
24
+ next === 1 ? params.delete('page') : params.set('page', String(next));
25
+ setSearch(params);
26
+ }
27
+ if (query.isPending)
28
+ return (
29
+ <p className="muted" role="status">
30
+ 正在读取成员目录…
31
+ </p>
32
+ );
33
+ if (query.isError)
34
+ return (
35
+ <QueryFailure
36
+ error={query.error}
37
+ to="/workspace"
38
+ label="返回工作台"
39
+ retry={() => void query.refetch()}
40
+ />
41
+ );
42
+ return (
43
+ <>
44
+ <div className="page-heading">
45
+ <div>
46
+ <p className="eyebrow">团队与协作</p>
47
+ <h1>成员目录</h1>
48
+ <p className="muted">仅显示你有权查看的成员;账号维护请进入系统管理。</p>
49
+ </div>
50
+ </div>
51
+ <section className="directory-panel">
52
+ <table>
53
+ <thead>
54
+ <tr>
55
+ <th>成员</th>
56
+ <th>账号</th>
57
+ <th>状态</th>
58
+ <th>查看</th>
59
+ </tr>
60
+ </thead>
61
+ <tbody>
62
+ {query.data.items.map((user) => (
63
+ <tr key={user.id}>
64
+ <td>{user.name}</td>
65
+ <td>{user.username}</td>
66
+ <td>{user.status === 'active' ? '使用中' : '已停用'}</td>
67
+ <td>
68
+ <Link className="record-link" to={`/directory/users/${encodeURIComponent(user.id)}`}>
69
+ 成员详情 ↗
70
+ </Link>
71
+ </td>
72
+ </tr>
73
+ ))}
74
+ </tbody>
75
+ </table>
76
+ {!query.data.items.length && <p className="directory-empty">当前范围内没有成员。</p>}
77
+ <footer className="directory-pagination">
78
+ <span>
79
+ 共 {query.data.total} 人 · 第 {page} 页
80
+ </span>
81
+ <div>
82
+ <button disabled={page === 1} onClick={() => go(page - 1)}>
83
+ 上一页
84
+ </button>
85
+ <button disabled={page * 20 >= query.data.total} onClick={() => go(page + 1)}>
86
+ 下一页
87
+ </button>
88
+ </div>
89
+ </footer>
90
+ </section>
91
+ </>
92
+ );
93
+ }
@@ -1 +1,5 @@
1
+ /**
2
+ * workspace 模块的公开导出边界,向 app 提供空白工作台首页。
3
+ * 其他模块通过这个入口组合页面,不依赖内部页面文件路径;具体读取与交互留在实现文件。
4
+ */
1
5
  export { HomePage } from './pages/home-page';
@@ -1,6 +1,15 @@
1
+ /**
2
+ * 空白业务项目的工作台首页,解释尚未添加业务模块并提供真实成员目录和管理入口。
3
+ * 不注册采购演示、不制造统计;客户业务应建立相邻模块,再经 app 接入导航。
4
+ */
1
5
  // 空白工作台模块:新增业务时建立相邻模块,由 app 导航接入,不在本页堆全部业务。
2
6
  import { useCan } from '@app/contracts';
7
+ import { Link } from 'react-router-dom';
3
8
 
9
+ /**
10
+ * 根据 User.read 的界面能力展示组织相关入口,其余区域显示业务空状态。
11
+ * 拥有读取能力不等于获得全部管理权限;系统管理仍按具体操作检查能力。
12
+ */
4
13
  export function HomePage() {
5
14
  const canManage = useCan('User.read');
6
15
  return (
@@ -13,6 +22,14 @@ export function HomePage() {
13
22
  </div>
14
23
  <span className="project-tag">空白业务项目</span>
15
24
  </div>
25
+ {canManage && (
26
+ <p className="directory-intro">
27
+ <Link className="record-link" to="/directory/users">
28
+ 打开成员目录 ↗
29
+ </Link>
30
+ <span>查看真实组织成员,也可作为新增业务列表与详情页的参考。</span>
31
+ </p>
32
+ )}
16
33
  <section className="empty-state" aria-labelledby="empty-title">
17
34
  <div className="empty-illustration" aria-hidden="true">
18
35
  <div className="sheet sheet-back" />
@@ -1,6 +1,15 @@
1
+ /**
2
+ * 空白应用通用错误码的中文展示表,由登录页和公共外壳共享。
3
+ * 保持与 CommonError 类型覆盖一致;错误文案只供提示,控制流应仍判断客户端 ok/code。
4
+ * 取消和超时由客户端请求生命周期产生,不代表服务端一定没有完成操作,提示用户先确认当前状态。
5
+ */
1
6
  import type { CommonError } from '@app/contracts';
2
7
 
3
8
  // 通用错误提示不依赖具体业务,登录页和应用壳复用它。
9
+ /**
10
+ * 完整映射认证、授权、输入、限流、服务异常、网络、取消和超时错误;新增业务领域错误由其模块单独说明。
11
+ * Record 保留穷尽检查,SDK 增加通用错误码时必须补充文案,不能用空提示或静默默认值掩盖缺项。
12
+ */
4
13
  export const errorMessages: Record<CommonError, string> = {
5
14
  UNAUTHENTICATED: '账号或密码不正确,请重新输入。',
6
15
  FORBIDDEN: '当前账号无法执行此操作,请联系管理员。',
@@ -8,4 +17,6 @@ export const errorMessages: Record<CommonError, string> = {
8
17
  RATE_LIMITED: '操作过于频繁,请稍后重试。',
9
18
  INTERNAL: '服务暂时无法处理请求,请稍后重试。',
10
19
  NETWORK: '无法连接服务,请检查网络和 API 是否已启动。',
20
+ CANCELLED: '请求已取消,请确认当前页面状态后重试。',
21
+ TIMEOUT: '请求超时,请检查网络并确认操作结果后重试。',
11
22
  };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 登录回跳的应用边界:只接受本应用的业务路径,阻止外站及认证/API/静态资源路径回跳。
3
+ * 由路由组合层调用,纯解析 URL 字符串,不发起导航或网络请求。
4
+ */
5
+ /** 登录回跳只接受本应用页面;固定基址只用于解析,不会发起网络请求。 */
6
+ /**
7
+ * 提取 search 中的 returnTo,使用固定解析基准检查同源路径并排除保留前缀。
8
+ * @param search 登录页查询字符串,可含 URL 编码的 returnTo。
9
+ * @param fallback 缺失、格式不合法或越界时返回的可信业务首页。
10
+ * @returns 可回跳路径,保留其查询参数与 hash;不返回外站 URL。
11
+ */
12
+ export function loginReturnTo(search: string, fallback: string): string {
13
+ const requested = new URLSearchParams(search).get('returnTo');
14
+ const origin = 'https://cage.local';
15
+ if (!requested?.startsWith('/') || !URL.canParse(requested, origin)) return fallback;
16
+ const url = new URL(requested, origin);
17
+ // 保留查询条件和锚点;阻止外站跳转、登录循环及把服务端入口当成 React 页面。
18
+ if (url.origin !== origin || /^\/(login|admin|api|auth|hooks|assets)(\/|$)/.test(url.pathname))
19
+ return fallback;
20
+ return url.pathname + url.search + url.hash;
21
+ }