@yss123/cage-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (607) 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/baseline.d.ts +8 -0
  8. package/dist/baseline.js +13 -0
  9. package/dist/baseline.js.map +1 -1
  10. package/dist/bootstrap.d.ts +20 -0
  11. package/dist/bootstrap.js +75 -0
  12. package/dist/bootstrap.js.map +1 -0
  13. package/dist/budget.d.ts +7 -0
  14. package/dist/budget.js +49 -5
  15. package/dist/budget.js.map +1 -1
  16. package/dist/capabilities.d.ts +38 -0
  17. package/dist/capabilities.js +133 -0
  18. package/dist/capabilities.js.map +1 -0
  19. package/dist/config.d.ts +31 -2
  20. package/dist/config.js +22 -0
  21. package/dist/config.js.map +1 -1
  22. package/dist/context.d.ts +14 -0
  23. package/dist/context.js +35 -2
  24. package/dist/context.js.map +1 -1
  25. package/dist/create-prompt.d.ts +7 -0
  26. package/dist/create-prompt.js +12 -0
  27. package/dist/create-prompt.js.map +1 -1
  28. package/dist/create.d.ts +21 -1
  29. package/dist/create.js +23 -1
  30. package/dist/create.js.map +1 -1
  31. package/dist/derive.d.ts +23 -0
  32. package/dist/derive.js +40 -0
  33. package/dist/derive.js.map +1 -1
  34. package/dist/dev.d.ts +6 -0
  35. package/dist/dev.js +11 -0
  36. package/dist/dev.js.map +1 -1
  37. package/dist/doctor.d.ts +98 -0
  38. package/dist/doctor.js +93 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/env.d.ts +6 -0
  41. package/dist/env.js +11 -0
  42. package/dist/env.js.map +1 -1
  43. package/dist/findings.d.ts +27 -0
  44. package/dist/findings.js +20 -0
  45. package/dist/findings.js.map +1 -1
  46. package/dist/gen/contracts.d.ts +28 -0
  47. package/dist/gen/contracts.js +52 -12
  48. package/dist/gen/contracts.js.map +1 -1
  49. package/dist/gen/index.d.ts +26 -0
  50. package/dist/gen/index.js +69 -1
  51. package/dist/gen/index.js.map +1 -1
  52. package/dist/gen/zod-code.d.ts +42 -0
  53. package/dist/gen/zod-code.js +178 -16
  54. package/dist/gen/zod-code.js.map +1 -1
  55. package/dist/graph-approvals.d.ts +60 -0
  56. package/dist/graph-approvals.js +80 -0
  57. package/dist/graph-approvals.js.map +1 -0
  58. package/dist/graph-business.d.ts +135 -0
  59. package/dist/graph-business.js +404 -0
  60. package/dist/graph-business.js.map +1 -0
  61. package/dist/graph-command.d.ts +17 -0
  62. package/dist/graph-command.js +21 -0
  63. package/dist/graph-command.js.map +1 -1
  64. package/dist/graph-model.d.ts +44 -0
  65. package/dist/graph-model.js +36 -3
  66. package/dist/graph-model.js.map +1 -1
  67. package/dist/graph-presentation.d.ts +16 -0
  68. package/dist/graph-presentation.js +10 -1
  69. package/dist/graph-presentation.js.map +1 -1
  70. package/dist/graph-query.d.ts +95 -0
  71. package/dist/graph-query.js +62 -0
  72. package/dist/graph-query.js.map +1 -1
  73. package/dist/graph-relations.d.ts +20 -0
  74. package/dist/graph-relations.js +34 -4
  75. package/dist/graph-relations.js.map +1 -1
  76. package/dist/graph-search.d.ts +35 -0
  77. package/dist/graph-search.js +36 -0
  78. package/dist/graph-search.js.map +1 -1
  79. package/dist/graph-snapshot.d.ts +26 -0
  80. package/dist/graph-snapshot.js +30 -1
  81. package/dist/graph-snapshot.js.map +1 -1
  82. package/dist/graph.d.ts +13 -2
  83. package/dist/graph.js +59 -4
  84. package/dist/graph.js.map +1 -1
  85. package/dist/impact.d.ts +50 -0
  86. package/dist/impact.js +62 -2
  87. package/dist/impact.js.map +1 -1
  88. package/dist/index.d.ts +10 -0
  89. package/dist/index.js +10 -0
  90. package/dist/index.js.map +1 -1
  91. package/dist/init.d.ts +12 -0
  92. package/dist/init.js +15 -0
  93. package/dist/init.js.map +1 -1
  94. package/dist/load.d.ts +10 -0
  95. package/dist/load.js +15 -0
  96. package/dist/load.js.map +1 -1
  97. package/dist/main.d.ts +6 -0
  98. package/dist/main.js +93 -5
  99. package/dist/main.js.map +1 -1
  100. package/dist/migrate.d.ts +12 -0
  101. package/dist/migrate.js +17 -0
  102. package/dist/migrate.js.map +1 -1
  103. package/dist/ontology.d.ts +67 -2
  104. package/dist/ontology.js +89 -2
  105. package/dist/ontology.js.map +1 -1
  106. package/dist/process-rules.d.ts +21 -0
  107. package/dist/process-rules.js +100 -0
  108. package/dist/process-rules.js.map +1 -0
  109. package/dist/process.d.ts +32 -0
  110. package/dist/process.js +32 -0
  111. package/dist/process.js.map +1 -1
  112. package/dist/project-structure.d.ts +5 -0
  113. package/dist/project-structure.js +10 -0
  114. package/dist/project-structure.js.map +1 -1
  115. package/dist/registration.d.ts +16 -0
  116. package/dist/registration.js +56 -0
  117. package/dist/registration.js.map +1 -0
  118. package/dist/rules.d.ts +52 -0
  119. package/dist/rules.js +58 -0
  120. package/dist/rules.js.map +1 -1
  121. package/dist/runtime-diagnostics.d.ts +27 -0
  122. package/dist/runtime-diagnostics.js +60 -0
  123. package/dist/runtime-diagnostics.js.map +1 -0
  124. package/dist/snapshots.d.ts +40 -0
  125. package/dist/snapshots.js +62 -0
  126. package/dist/snapshots.js.map +1 -0
  127. package/dist/static-check.d.ts +33 -0
  128. package/dist/static-check.js +37 -1
  129. package/dist/static-check.js.map +1 -1
  130. package/dist/sync.d.ts +11 -0
  131. package/dist/sync.js +65 -8
  132. package/dist/sync.js.map +1 -1
  133. package/dist/upgrade.d.ts +16 -0
  134. package/dist/upgrade.js +21 -0
  135. package/dist/upgrade.js.map +1 -1
  136. package/dist/verify.d.ts +14 -0
  137. package/dist/verify.js +19 -0
  138. package/dist/verify.js.map +1 -1
  139. package/dist/version.js +5 -0
  140. package/dist/version.js.map +1 -1
  141. package/graph-ui/app.js +321 -27
  142. package/graph-ui/approval-flow.js +165 -0
  143. package/graph-ui/business.css +985 -0
  144. package/graph-ui/business.js +549 -0
  145. package/graph-ui/flowchart-interaction.js +177 -0
  146. package/graph-ui/flowchart.js +1059 -0
  147. package/graph-ui/graph-approvals.js +79 -0
  148. package/graph-ui/graph-business.js +403 -0
  149. package/graph-ui/graph-model.js +36 -3
  150. package/graph-ui/graph-relations.js +34 -4
  151. package/graph-ui/graph-search.js +36 -0
  152. package/graph-ui/index.html +26 -12
  153. package/graph-ui/model.js +28 -0
  154. package/graph-ui/relations.js +4 -0
  155. package/graph-ui/structure.js +44 -0
  156. package/graph-ui/style.css +12 -0
  157. package/package.json +6 -4
  158. package/templates/app/.dockerignore +2 -0
  159. package/templates/app/.env.example +10 -0
  160. package/templates/app/AGENTS.md +49 -9
  161. package/templates/app/README.md +4 -1
  162. package/templates/app/_gitignore +1 -0
  163. package/templates/app/apps/api/package.json +2 -2
  164. package/templates/app/apps/api/src/main.ts +5 -1
  165. package/templates/app/apps/api/src/worker.ts +3 -0
  166. package/templates/app/apps/web/index.html +1 -0
  167. package/templates/app/apps/web/package.json +7 -3
  168. package/templates/app/apps/web/src/app/app.tsx +122 -12
  169. package/templates/app/apps/web/src/app/styles/global.css +88 -8
  170. package/templates/app/apps/web/src/app/use-session.ts +43 -0
  171. package/templates/app/apps/web/src/app/workspace-layout.tsx +58 -19
  172. package/templates/app/apps/web/src/main.tsx +5 -0
  173. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +11 -0
  174. package/templates/app/apps/web/src/modules/approval/index.ts +4 -0
  175. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +20 -1
  176. package/templates/app/apps/web/src/modules/auth/index.ts +4 -0
  177. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  178. package/templates/app/apps/web/src/modules/inventory/index.ts +4 -0
  179. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  180. package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
  181. package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  182. package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  183. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  184. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +25 -3
  185. package/templates/app/apps/web/src/modules/purchase/index.ts +5 -0
  186. package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  187. package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
  188. package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
  189. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +52 -22
  190. package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
  191. package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  192. package/templates/app/apps/web/src/shared/hooks/use-command.ts +13 -0
  193. package/templates/app/apps/web/src/shared/lib/error-message.ts +9 -0
  194. package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
  195. package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  196. package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
  197. package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  198. package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  199. package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
  200. package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  201. package/templates/app/apps/web/src/shared/ui/notice.tsx +7 -0
  202. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +7 -0
  203. package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
  204. package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
  205. package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
  206. package/templates/app/apps/web/vite.config.ts +5 -0
  207. package/templates/app/cage.config.json +9 -0
  208. package/templates/app/db/migrations/0002_draft.sql +12 -0
  209. package/templates/app/db/migrations/0003_draft.sql +8 -0
  210. package/templates/app/deploy/nginx.conf +52 -0
  211. package/templates/app/docs/ai/README.md +21 -0
  212. package/templates/app/docs/ai/architecture.md +26 -0
  213. package/templates/app/docs/ai/commenting.md +203 -0
  214. package/templates/app/docs/ai/diagnostics.md +80 -0
  215. package/templates/app/docs/ai/files.md +93 -0
  216. package/templates/app/docs/ai/intelligence.md +348 -0
  217. package/templates/app/docs/ai/ontology-context.md +59 -4
  218. package/templates/app/docs/ai/primitives.md +33 -0
  219. package/templates/app/docs/ai/project-structure.md +8 -3
  220. package/templates/app/docs/ai/purchase-example.md +16 -2
  221. package/templates/app/docs/ai/recipes.md +9 -1
  222. package/templates/app/docs/ai/routing.md +86 -0
  223. package/templates/app/docs/ai/troubleshooting.md +5 -0
  224. package/templates/app/docs/ai/workflow.md +24 -11
  225. package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
  226. package/templates/app/docs/errors/CAGE-APPR-001.md +7 -6
  227. package/templates/app/docs/errors/CAGE-APPR-002.md +2 -2
  228. package/templates/app/docs/errors/CAGE-APPR-003.md +1 -1
  229. package/templates/app/docs/errors/CAGE-APPR-004.md +4 -4
  230. package/templates/app/docs/errors/CAGE-APPR-005.md +1 -1
  231. package/templates/app/docs/errors/CAGE-APPR-006.md +12 -6
  232. package/templates/app/docs/errors/CAGE-APPR-007.md +3 -3
  233. package/templates/app/docs/errors/CAGE-APPR-010.md +5 -5
  234. package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
  235. package/templates/app/docs/errors/CAGE-AUTH-001.md +1 -1
  236. package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
  237. package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
  238. package/templates/app/docs/errors/CAGE-BUDGET-001.md +1 -1
  239. package/templates/app/docs/errors/CAGE-BUDGET-002.md +1 -1
  240. package/templates/app/docs/errors/CAGE-BUDGET-003.md +1 -1
  241. package/templates/app/docs/errors/CAGE-CMD-002.md +1 -1
  242. package/templates/app/docs/errors/CAGE-CMD-003.md +1 -1
  243. package/templates/app/docs/errors/CAGE-CONN-001.md +3 -3
  244. package/templates/app/docs/errors/CAGE-CONN-002.md +1 -1
  245. package/templates/app/docs/errors/CAGE-CONN-003.md +1 -1
  246. package/templates/app/docs/errors/CAGE-CONN-004.md +1 -1
  247. package/templates/app/docs/errors/CAGE-CONN-005.md +1 -1
  248. package/templates/app/docs/errors/CAGE-CONN-006.md +1 -1
  249. package/templates/app/docs/errors/CAGE-CONN-007.md +6 -6
  250. package/templates/app/docs/errors/CAGE-CONN-008.md +5 -5
  251. package/templates/app/docs/errors/CAGE-CONN-009.md +6 -6
  252. package/templates/app/docs/errors/CAGE-CONN-010.md +6 -6
  253. package/templates/app/docs/errors/CAGE-CONN-011.md +1 -1
  254. package/templates/app/docs/errors/CAGE-CONN-012.md +1 -1
  255. package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
  256. package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
  257. package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
  258. package/templates/app/docs/errors/CAGE-CREATE-001.md +10 -9
  259. package/templates/app/docs/errors/CAGE-DECL-001.md +2 -2
  260. package/templates/app/docs/errors/CAGE-DECL-002.md +7 -6
  261. package/templates/app/docs/errors/CAGE-DECL-003.md +1 -1
  262. package/templates/app/docs/errors/CAGE-DECL-004.md +1 -1
  263. package/templates/app/docs/errors/CAGE-DEP-001.md +2 -2
  264. package/templates/app/docs/errors/CAGE-DEP-002.md +1 -1
  265. package/templates/app/docs/errors/CAGE-DEP-003.md +2 -2
  266. package/templates/app/docs/errors/CAGE-DEP-004.md +1 -1
  267. package/templates/app/docs/errors/CAGE-DEP-005.md +1 -1
  268. package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
  269. package/templates/app/docs/errors/CAGE-DLQ-001.md +2 -2
  270. package/templates/app/docs/errors/CAGE-ENV-001.md +4 -4
  271. package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
  272. package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
  273. package/templates/app/docs/errors/CAGE-EVENT-001.md +1 -1
  274. package/templates/app/docs/errors/CAGE-EVENT-002.md +7 -7
  275. package/templates/app/docs/errors/CAGE-FIELD-001.md +2 -2
  276. package/templates/app/docs/errors/CAGE-FIELD-002.md +1 -1
  277. package/templates/app/docs/errors/CAGE-FIELD-003.md +1 -1
  278. package/templates/app/docs/errors/CAGE-FIELD-004.md +1 -1
  279. package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
  280. package/templates/app/docs/errors/CAGE-GEN-001.md +2 -2
  281. package/templates/app/docs/errors/CAGE-GEN-002.md +1 -1
  282. package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
  283. package/templates/app/docs/errors/CAGE-GRANT-001.md +3 -3
  284. package/templates/app/docs/errors/CAGE-GRANT-002.md +2 -2
  285. package/templates/app/docs/errors/CAGE-GRANT-003.md +7 -6
  286. package/templates/app/docs/errors/CAGE-IMPACT-001.md +2 -2
  287. package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
  288. package/templates/app/docs/errors/CAGE-INIT-001.md +1 -1
  289. package/templates/app/docs/errors/CAGE-INIT-002.md +1 -1
  290. package/templates/app/docs/errors/CAGE-INIT-003.md +2 -2
  291. package/templates/app/docs/errors/CAGE-INIT-004.md +1 -1
  292. package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
  293. package/templates/app/docs/errors/CAGE-JOB-001.md +1 -1
  294. package/templates/app/docs/errors/CAGE-JOB-002.md +1 -1
  295. package/templates/app/docs/errors/CAGE-JOB-003.md +1 -1
  296. package/templates/app/docs/errors/CAGE-LINT-001.md +1 -1
  297. package/templates/app/docs/errors/CAGE-MIG-001.md +1 -1
  298. package/templates/app/docs/errors/CAGE-MIG-002.md +1 -1
  299. package/templates/app/docs/errors/CAGE-MIG-005.md +1 -1
  300. package/templates/app/docs/errors/CAGE-NAME-001.md +1 -1
  301. package/templates/app/docs/errors/CAGE-NAME-002.md +1 -1
  302. package/templates/app/docs/errors/CAGE-NAME-003.md +3 -3
  303. package/templates/app/docs/errors/CAGE-NAME-004.md +1 -1
  304. package/templates/app/docs/errors/CAGE-NAME-005.md +1 -1
  305. package/templates/app/docs/errors/CAGE-NAME-006.md +1 -1
  306. package/templates/app/docs/errors/CAGE-ORG-001.md +7 -6
  307. package/templates/app/docs/errors/CAGE-PAIR-002.md +6 -5
  308. package/templates/app/docs/errors/CAGE-QUERY-001.md +1 -1
  309. package/templates/app/docs/errors/CAGE-QUERY-002.md +2 -2
  310. package/templates/app/docs/errors/CAGE-QUERY-003.md +7 -6
  311. package/templates/app/docs/errors/CAGE-REACT-001.md +3 -3
  312. package/templates/app/docs/errors/CAGE-REACT-002.md +1 -1
  313. package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
  314. package/templates/app/docs/errors/CAGE-READS-001.md +9 -6
  315. package/templates/app/docs/errors/CAGE-REG-001.md +13 -12
  316. package/templates/app/docs/errors/CAGE-REG-002.md +2 -1
  317. package/templates/app/docs/errors/CAGE-REG-003.md +1 -1
  318. package/templates/app/docs/errors/CAGE-REL-001.md +14 -14
  319. package/templates/app/docs/errors/CAGE-ROUTE-001.md +7 -6
  320. package/templates/app/docs/errors/CAGE-SCOPE-001.md +1 -1
  321. package/templates/app/docs/errors/CAGE-SCOPE-002.md +2 -2
  322. package/templates/app/docs/errors/CAGE-SECRET-001.md +2 -2
  323. package/templates/app/docs/errors/CAGE-SECRET-002.md +1 -1
  324. package/templates/app/docs/errors/CAGE-SENS-001.md +5 -5
  325. package/templates/app/docs/errors/CAGE-SQL-001.md +1 -1
  326. package/templates/app/docs/errors/CAGE-SQL-002.md +1 -1
  327. package/templates/app/docs/errors/CAGE-STATE-001.md +3 -3
  328. package/templates/app/docs/errors/CAGE-STATE-002.md +1 -1
  329. package/templates/app/docs/errors/CAGE-STATE-003.md +1 -1
  330. package/templates/app/docs/errors/CAGE-STATE-004.md +1 -1
  331. package/templates/app/docs/errors/CAGE-STATE-005.md +3 -2
  332. package/templates/app/docs/errors/CAGE-STATE-010.md +5 -5
  333. package/templates/app/docs/errors/CAGE-STATE-011.md +5 -5
  334. package/templates/app/docs/errors/CAGE-STRUCT-001.md +1 -1
  335. package/templates/app/docs/errors/CAGE-STRUCT-002.md +1 -1
  336. package/templates/app/docs/errors/CAGE-SYNC-001.md +3 -2
  337. package/templates/app/docs/errors/CAGE-TEST-001.md +1 -1
  338. package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
  339. package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
  340. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +3 -2
  341. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +2 -2
  342. package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
  343. package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
  344. package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
  345. package/templates/app/docs/errors/README.md +50 -0
  346. package/templates/app/package.json +3 -3
  347. package/templates/app/packages/contracts/package.json +1 -1
  348. package/templates/app/packages/contracts/src/aggregates/dept/index.ts +10 -10
  349. package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  350. package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  351. package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +26 -12
  352. package/templates/app/packages/contracts/src/aggregates/role/index.ts +15 -15
  353. package/templates/app/packages/contracts/src/aggregates/user/index.ts +16 -16
  354. package/templates/app/packages/contracts/src/index.ts +7 -1
  355. package/templates/app/packages/contracts/src/queries/index.ts +2 -2
  356. package/templates/app/packages/domain/package.json +5 -4
  357. package/templates/app/packages/domain/src/index.ts +4 -0
  358. package/templates/app/packages/domain/src/integrations/erp.ts +15 -0
  359. package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
  360. package/templates/app/packages/domain/src/modules/inventory/index.ts +1 -0
  361. package/templates/app/packages/domain/src/modules/inventory/inventory.ts +12 -0
  362. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +22 -1
  363. package/templates/app/packages/domain/src/modules/purchase/index.ts +1 -0
  364. package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
  365. package/templates/app/packages/domain/src/modules/purchase/jobs.ts +5 -0
  366. package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  367. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +70 -0
  368. package/templates/app/packages/domain/src/modules/purchase/queries.ts +5 -0
  369. package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  370. package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
  371. package/templates/blank/.dockerignore +2 -0
  372. package/templates/blank/.env.example +10 -0
  373. package/templates/blank/AGENTS.md +49 -9
  374. package/templates/blank/README.md +4 -1
  375. package/templates/blank/_gitignore +1 -0
  376. package/templates/blank/apps/api/package.json +1 -1
  377. package/templates/blank/apps/api/src/main.ts +4 -1
  378. package/templates/blank/apps/api/src/worker.ts +2 -0
  379. package/templates/blank/apps/web/index.html +1 -0
  380. package/templates/blank/apps/web/package.json +7 -3
  381. package/templates/blank/apps/web/src/app/app.tsx +80 -18
  382. package/templates/blank/apps/web/src/app/styles/global.css +90 -0
  383. package/templates/blank/apps/web/src/app/use-session.ts +43 -0
  384. package/templates/blank/apps/web/src/app/workspace-layout.tsx +30 -5
  385. package/templates/blank/apps/web/src/main.tsx +5 -0
  386. package/templates/blank/apps/web/src/modules/auth/index.ts +4 -0
  387. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +18 -1
  388. package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
  389. package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
  390. package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
  391. package/templates/blank/apps/web/src/modules/workspace/index.ts +4 -0
  392. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +17 -0
  393. package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
  394. package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
  395. package/templates/blank/apps/web/src/shared/ui/brand.tsx +10 -2
  396. package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
  397. package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
  398. package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
  399. package/templates/blank/apps/web/vite.config.ts +5 -0
  400. package/templates/blank/deploy/nginx.conf +52 -0
  401. package/templates/blank/docs/ai/README.md +21 -0
  402. package/templates/blank/docs/ai/architecture.md +26 -0
  403. package/templates/blank/docs/ai/commenting.md +203 -0
  404. package/templates/blank/docs/ai/diagnostics.md +80 -0
  405. package/templates/blank/docs/ai/files.md +93 -0
  406. package/templates/blank/docs/ai/intelligence.md +348 -0
  407. package/templates/blank/docs/ai/ontology-context.md +59 -4
  408. package/templates/blank/docs/ai/primitives.md +33 -0
  409. package/templates/blank/docs/ai/project-structure.md +8 -3
  410. package/templates/blank/docs/ai/purchase-example.md +16 -2
  411. package/templates/blank/docs/ai/recipes.md +9 -1
  412. package/templates/blank/docs/ai/routing.md +86 -0
  413. package/templates/blank/docs/ai/troubleshooting.md +5 -0
  414. package/templates/blank/docs/ai/workflow.md +24 -11
  415. package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
  416. package/templates/blank/docs/errors/CAGE-APPR-001.md +7 -6
  417. package/templates/blank/docs/errors/CAGE-APPR-002.md +2 -2
  418. package/templates/blank/docs/errors/CAGE-APPR-003.md +1 -1
  419. package/templates/blank/docs/errors/CAGE-APPR-004.md +4 -4
  420. package/templates/blank/docs/errors/CAGE-APPR-005.md +1 -1
  421. package/templates/blank/docs/errors/CAGE-APPR-006.md +12 -6
  422. package/templates/blank/docs/errors/CAGE-APPR-007.md +3 -3
  423. package/templates/blank/docs/errors/CAGE-APPR-010.md +5 -5
  424. package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
  425. package/templates/blank/docs/errors/CAGE-AUTH-001.md +1 -1
  426. package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
  427. package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
  428. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +1 -1
  429. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +1 -1
  430. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +1 -1
  431. package/templates/blank/docs/errors/CAGE-CMD-002.md +1 -1
  432. package/templates/blank/docs/errors/CAGE-CMD-003.md +1 -1
  433. package/templates/blank/docs/errors/CAGE-CONN-001.md +3 -3
  434. package/templates/blank/docs/errors/CAGE-CONN-002.md +1 -1
  435. package/templates/blank/docs/errors/CAGE-CONN-003.md +1 -1
  436. package/templates/blank/docs/errors/CAGE-CONN-004.md +1 -1
  437. package/templates/blank/docs/errors/CAGE-CONN-005.md +1 -1
  438. package/templates/blank/docs/errors/CAGE-CONN-006.md +1 -1
  439. package/templates/blank/docs/errors/CAGE-CONN-007.md +6 -6
  440. package/templates/blank/docs/errors/CAGE-CONN-008.md +5 -5
  441. package/templates/blank/docs/errors/CAGE-CONN-009.md +6 -6
  442. package/templates/blank/docs/errors/CAGE-CONN-010.md +6 -6
  443. package/templates/blank/docs/errors/CAGE-CONN-011.md +1 -1
  444. package/templates/blank/docs/errors/CAGE-CONN-012.md +1 -1
  445. package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
  446. package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
  447. package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
  448. package/templates/blank/docs/errors/CAGE-CREATE-001.md +10 -9
  449. package/templates/blank/docs/errors/CAGE-DECL-001.md +2 -2
  450. package/templates/blank/docs/errors/CAGE-DECL-002.md +7 -6
  451. package/templates/blank/docs/errors/CAGE-DECL-003.md +1 -1
  452. package/templates/blank/docs/errors/CAGE-DECL-004.md +1 -1
  453. package/templates/blank/docs/errors/CAGE-DEP-001.md +2 -2
  454. package/templates/blank/docs/errors/CAGE-DEP-002.md +1 -1
  455. package/templates/blank/docs/errors/CAGE-DEP-003.md +2 -2
  456. package/templates/blank/docs/errors/CAGE-DEP-004.md +1 -1
  457. package/templates/blank/docs/errors/CAGE-DEP-005.md +1 -1
  458. package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
  459. package/templates/blank/docs/errors/CAGE-DLQ-001.md +2 -2
  460. package/templates/blank/docs/errors/CAGE-ENV-001.md +4 -4
  461. package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
  462. package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
  463. package/templates/blank/docs/errors/CAGE-EVENT-001.md +1 -1
  464. package/templates/blank/docs/errors/CAGE-EVENT-002.md +7 -7
  465. package/templates/blank/docs/errors/CAGE-FIELD-001.md +2 -2
  466. package/templates/blank/docs/errors/CAGE-FIELD-002.md +1 -1
  467. package/templates/blank/docs/errors/CAGE-FIELD-003.md +1 -1
  468. package/templates/blank/docs/errors/CAGE-FIELD-004.md +1 -1
  469. package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
  470. package/templates/blank/docs/errors/CAGE-GEN-001.md +2 -2
  471. package/templates/blank/docs/errors/CAGE-GEN-002.md +1 -1
  472. package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
  473. package/templates/blank/docs/errors/CAGE-GRANT-001.md +3 -3
  474. package/templates/blank/docs/errors/CAGE-GRANT-002.md +2 -2
  475. package/templates/blank/docs/errors/CAGE-GRANT-003.md +7 -6
  476. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +2 -2
  477. package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
  478. package/templates/blank/docs/errors/CAGE-INIT-001.md +1 -1
  479. package/templates/blank/docs/errors/CAGE-INIT-002.md +1 -1
  480. package/templates/blank/docs/errors/CAGE-INIT-003.md +2 -2
  481. package/templates/blank/docs/errors/CAGE-INIT-004.md +1 -1
  482. package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
  483. package/templates/blank/docs/errors/CAGE-JOB-001.md +1 -1
  484. package/templates/blank/docs/errors/CAGE-JOB-002.md +1 -1
  485. package/templates/blank/docs/errors/CAGE-JOB-003.md +1 -1
  486. package/templates/blank/docs/errors/CAGE-LINT-001.md +1 -1
  487. package/templates/blank/docs/errors/CAGE-MIG-001.md +1 -1
  488. package/templates/blank/docs/errors/CAGE-MIG-002.md +1 -1
  489. package/templates/blank/docs/errors/CAGE-MIG-005.md +1 -1
  490. package/templates/blank/docs/errors/CAGE-NAME-001.md +1 -1
  491. package/templates/blank/docs/errors/CAGE-NAME-002.md +1 -1
  492. package/templates/blank/docs/errors/CAGE-NAME-003.md +3 -3
  493. package/templates/blank/docs/errors/CAGE-NAME-004.md +1 -1
  494. package/templates/blank/docs/errors/CAGE-NAME-005.md +1 -1
  495. package/templates/blank/docs/errors/CAGE-NAME-006.md +1 -1
  496. package/templates/blank/docs/errors/CAGE-ORG-001.md +7 -6
  497. package/templates/blank/docs/errors/CAGE-PAIR-002.md +6 -5
  498. package/templates/blank/docs/errors/CAGE-QUERY-001.md +1 -1
  499. package/templates/blank/docs/errors/CAGE-QUERY-002.md +2 -2
  500. package/templates/blank/docs/errors/CAGE-QUERY-003.md +7 -6
  501. package/templates/blank/docs/errors/CAGE-REACT-001.md +3 -3
  502. package/templates/blank/docs/errors/CAGE-REACT-002.md +1 -1
  503. package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
  504. package/templates/blank/docs/errors/CAGE-READS-001.md +9 -6
  505. package/templates/blank/docs/errors/CAGE-REG-001.md +13 -12
  506. package/templates/blank/docs/errors/CAGE-REG-002.md +2 -1
  507. package/templates/blank/docs/errors/CAGE-REG-003.md +1 -1
  508. package/templates/blank/docs/errors/CAGE-REL-001.md +14 -14
  509. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +7 -6
  510. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +1 -1
  511. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +2 -2
  512. package/templates/blank/docs/errors/CAGE-SECRET-001.md +2 -2
  513. package/templates/blank/docs/errors/CAGE-SECRET-002.md +1 -1
  514. package/templates/blank/docs/errors/CAGE-SENS-001.md +5 -5
  515. package/templates/blank/docs/errors/CAGE-SQL-001.md +1 -1
  516. package/templates/blank/docs/errors/CAGE-SQL-002.md +1 -1
  517. package/templates/blank/docs/errors/CAGE-STATE-001.md +3 -3
  518. package/templates/blank/docs/errors/CAGE-STATE-002.md +1 -1
  519. package/templates/blank/docs/errors/CAGE-STATE-003.md +1 -1
  520. package/templates/blank/docs/errors/CAGE-STATE-004.md +1 -1
  521. package/templates/blank/docs/errors/CAGE-STATE-005.md +3 -2
  522. package/templates/blank/docs/errors/CAGE-STATE-010.md +5 -5
  523. package/templates/blank/docs/errors/CAGE-STATE-011.md +5 -5
  524. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +1 -1
  525. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +1 -1
  526. package/templates/blank/docs/errors/CAGE-SYNC-001.md +3 -2
  527. package/templates/blank/docs/errors/CAGE-TEST-001.md +1 -1
  528. package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
  529. package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
  530. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +3 -2
  531. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +2 -2
  532. package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
  533. package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
  534. package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
  535. package/templates/blank/docs/errors/README.md +50 -0
  536. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +5 -1
  537. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +3 -0
  538. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +122 -12
  539. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +88 -8
  540. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
  541. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +58 -19
  542. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +5 -0
  543. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +11 -0
  544. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +4 -0
  545. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +20 -1
  546. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +4 -0
  547. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  548. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +4 -0
  549. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  550. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
  551. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  552. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  553. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  554. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +25 -3
  555. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +5 -0
  556. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  557. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
  558. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
  559. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +52 -22
  560. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
  561. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  562. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +13 -0
  563. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +9 -0
  564. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
  565. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  566. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
  567. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  568. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  569. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
  570. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  571. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +7 -0
  572. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +7 -0
  573. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
  574. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
  575. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
  576. package/templates/blank/docs/examples/purchase-admin/cage.config.json +9 -0
  577. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +10 -10
  578. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  579. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  580. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +26 -12
  581. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +15 -15
  582. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +16 -16
  583. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +7 -1
  584. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +2 -2
  585. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +4 -0
  586. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +15 -0
  587. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
  588. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +1 -0
  589. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +12 -0
  590. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +22 -1
  591. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +1 -0
  592. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
  593. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +5 -0
  594. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  595. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +70 -0
  596. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +5 -0
  597. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  598. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
  599. package/templates/blank/package.json +3 -3
  600. package/templates/blank/packages/contracts/package.json +1 -1
  601. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +10 -10
  602. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +15 -15
  603. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +16 -16
  604. package/templates/blank/packages/contracts/src/index.ts +1 -1
  605. package/templates/blank/packages/contracts/src/queries/index.ts +1 -1
  606. package/templates/blank/packages/domain/package.json +5 -4
  607. package/templates/blank/packages/domain/src/index.ts +2 -1
@@ -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
+ }
@@ -1,11 +1,19 @@
1
+ /**
2
+ * 登录页与工作台复用的品牌组件,只负责显示品牌及首页链接。
3
+ * 依赖 Router 的 Link 导航,不读取会话、不决定用户权限,也不导入具体业务模块。
4
+ */
1
5
  // 登录与工作台共用的品牌组件;只呈现,不读取模块或会话。
6
+ import { Link } from 'react-router-dom';
7
+ /**
8
+ * 渲染可访问名称完整的首页链接;未登录时目标页面仍由 app 的会话守卫处理。
9
+ */
2
10
  export function Brand() {
3
11
  return (
4
- <a className="brand" href="/" aria-label="Cage 工作台首页">
12
+ <Link className="brand" to="/workspace" aria-label="Cage 工作台首页">
5
13
  <span className="brand-mark">C</span>
6
14
  <span>
7
15
  Cage<span className="brand-dot">.</span>
8
16
  </span>
9
- </a>
17
+ </Link>
10
18
  );
11
19
  }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 共享页面状态卡与返回链接的样式,采购和空白模板均由同步流程取得同一版本。
3
+ * 颜色变量由应用主题提供;这里只排版标题、说明和操作,具体错误分类由 PageState/QueryFailure 决定。
4
+ */
5
+ /* 与两套工作台共享的纸面状态卡;状态清楚可读,链接保持可聚焦和可复制。 */
6
+ .route-state {
7
+ margin: 32px 0;
8
+ padding: 68px 36px;
9
+ border: 1px solid var(--line);
10
+ border-radius: 7px;
11
+ background: #fdfefb;
12
+ text-align: center;
13
+ }
14
+ .route-state-mark {
15
+ display: block;
16
+ margin-bottom: 20px;
17
+ color: #7d9866;
18
+ font:
19
+ italic 42px Georgia,
20
+ serif;
21
+ }
22
+ .route-state h1 {
23
+ font-size: 26px;
24
+ letter-spacing: -0.5px;
25
+ }
26
+ .route-state p {
27
+ margin: 16px 0 26px;
28
+ color: var(--muted);
29
+ font-size: 13px;
30
+ line-height: 1.9;
31
+ }
32
+ .route-link {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ padding: 10px 16px;
36
+ border: 1px solid var(--line);
37
+ border-radius: 4px;
38
+ background: #f1f5eb;
39
+ color: var(--green);
40
+ font-size: 12px;
41
+ }
42
+ .route-link:hover {
43
+ background: #e4ecd9;
44
+ }
45
+ .route-state > button {
46
+ margin-left: 12px;
47
+ }