@yss123/cage-cli 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -3
- package/bin/cage.js +5 -0
- package/bin/create-cage-app.js +5 -0
- package/dist/analyze.d.ts +16 -0
- package/dist/analyze.js +20 -2
- package/dist/analyze.js.map +1 -1
- package/dist/baseline.d.ts +8 -0
- package/dist/baseline.js +13 -0
- package/dist/baseline.js.map +1 -1
- package/dist/bootstrap.d.ts +20 -0
- package/dist/bootstrap.js +75 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/budget.d.ts +7 -0
- package/dist/budget.js +49 -5
- package/dist/budget.js.map +1 -1
- package/dist/capabilities.d.ts +38 -0
- package/dist/capabilities.js +133 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/config.d.ts +33 -4
- package/dist/config.js +22 -1
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +86 -0
- package/dist/context.js +235 -0
- package/dist/context.js.map +1 -0
- package/dist/create-prompt.d.ts +12 -0
- package/dist/create-prompt.js +62 -0
- package/dist/create-prompt.js.map +1 -0
- package/dist/create.d.ts +38 -1
- package/dist/create.js +52 -13
- package/dist/create.js.map +1 -1
- package/dist/derive.d.ts +23 -0
- package/dist/derive.js +40 -0
- package/dist/derive.js.map +1 -1
- package/dist/dev.d.ts +6 -0
- package/dist/dev.js +23 -51
- package/dist/dev.js.map +1 -1
- package/dist/doctor.d.ts +98 -0
- package/dist/doctor.js +93 -0
- package/dist/doctor.js.map +1 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +11 -0
- package/dist/env.js.map +1 -1
- package/dist/findings.d.ts +27 -0
- package/dist/findings.js +20 -0
- package/dist/findings.js.map +1 -1
- package/dist/gen/contracts.d.ts +28 -0
- package/dist/gen/contracts.js +81 -20
- package/dist/gen/contracts.js.map +1 -1
- package/dist/gen/index.d.ts +26 -0
- package/dist/gen/index.js +112 -4
- package/dist/gen/index.js.map +1 -1
- package/dist/gen/zod-code.d.ts +43 -1
- package/dist/gen/zod-code.js +180 -16
- package/dist/gen/zod-code.js.map +1 -1
- package/dist/graph-approvals.d.ts +60 -0
- package/dist/graph-approvals.js +80 -0
- package/dist/graph-approvals.js.map +1 -0
- package/dist/graph-business.d.ts +135 -0
- package/dist/graph-business.js +404 -0
- package/dist/graph-business.js.map +1 -0
- package/dist/graph-command.d.ts +28 -0
- package/dist/graph-command.js +88 -0
- package/dist/graph-command.js.map +1 -0
- package/dist/graph-model.d.ts +65 -0
- package/dist/graph-model.js +134 -0
- package/dist/graph-model.js.map +1 -0
- package/dist/graph-presentation.d.ts +27 -0
- package/dist/graph-presentation.js +34 -0
- package/dist/graph-presentation.js.map +1 -0
- package/dist/graph-query.d.ts +266 -0
- package/dist/graph-query.js +304 -0
- package/dist/graph-query.js.map +1 -0
- package/dist/graph-relations.d.ts +34 -0
- package/dist/graph-relations.js +172 -0
- package/dist/graph-relations.js.map +1 -0
- package/dist/graph-search.d.ts +56 -0
- package/dist/graph-search.js +99 -0
- package/dist/graph-search.js.map +1 -0
- package/dist/graph-snapshot.d.ts +28 -4
- package/dist/graph-snapshot.js +32 -20
- package/dist/graph-snapshot.js.map +1 -1
- package/dist/graph.d.ts +13 -2
- package/dist/graph.js +78 -5
- package/dist/graph.js.map +1 -1
- package/dist/impact.d.ts +56 -0
- package/dist/impact.js +90 -18
- package/dist/impact.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +18 -0
- package/dist/init.js +146 -0
- package/dist/init.js.map +1 -0
- package/dist/load.d.ts +10 -0
- package/dist/load.js +15 -0
- package/dist/load.js.map +1 -1
- package/dist/main.d.ts +6 -0
- package/dist/main.js +170 -37
- package/dist/main.js.map +1 -1
- package/dist/migrate.d.ts +15 -6
- package/dist/migrate.js +31 -53
- package/dist/migrate.js.map +1 -1
- package/dist/ontology.d.ts +69 -2
- package/dist/ontology.js +101 -4
- package/dist/ontology.js.map +1 -1
- package/dist/process-rules.d.ts +21 -0
- package/dist/process-rules.js +100 -0
- package/dist/process-rules.js.map +1 -0
- package/dist/process.d.ts +32 -0
- package/dist/process.js +32 -0
- package/dist/process.js.map +1 -1
- package/dist/project-structure.d.ts +13 -0
- package/dist/project-structure.js +104 -0
- package/dist/project-structure.js.map +1 -0
- package/dist/registration.d.ts +16 -0
- package/dist/registration.js +56 -0
- package/dist/registration.js.map +1 -0
- package/dist/rules.d.ts +52 -0
- package/dist/rules.js +58 -0
- package/dist/rules.js.map +1 -1
- package/dist/runtime-diagnostics.d.ts +27 -0
- package/dist/runtime-diagnostics.js +60 -0
- package/dist/runtime-diagnostics.js.map +1 -0
- package/dist/snapshots.d.ts +40 -0
- package/dist/snapshots.js +62 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/static-check.d.ts +33 -0
- package/dist/static-check.js +38 -5
- package/dist/static-check.js.map +1 -1
- package/dist/sync.d.ts +11 -0
- package/dist/sync.js +139 -10
- package/dist/sync.js.map +1 -1
- package/dist/upgrade.d.ts +16 -0
- package/dist/upgrade.js +21 -0
- package/dist/upgrade.js.map +1 -1
- package/dist/verify.d.ts +14 -0
- package/dist/verify.js +19 -0
- package/dist/verify.js.map +1 -1
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -1
- package/graph-ui/app.js +367 -35
- package/graph-ui/approval-flow.js +165 -0
- package/graph-ui/business.css +985 -0
- package/graph-ui/business.js +549 -0
- package/graph-ui/flowchart-interaction.js +177 -0
- package/graph-ui/flowchart.js +1059 -0
- package/graph-ui/graph-approvals.js +79 -0
- package/graph-ui/graph-business.js +403 -0
- package/graph-ui/graph-model.js +133 -0
- package/graph-ui/graph-relations.js +171 -0
- package/graph-ui/graph-search.js +98 -0
- package/graph-ui/index.html +26 -12
- package/graph-ui/model.js +47 -77
- package/graph-ui/relations.js +6 -125
- package/graph-ui/structure.js +48 -1
- package/graph-ui/style.css +33 -0
- package/package.json +10 -8
- package/templates/app/.dockerignore +2 -0
- package/templates/app/.env.example +68 -14
- package/templates/app/AGENTS.md +135 -12
- package/templates/app/Dockerfile +2 -0
- package/templates/app/README.md +49 -16
- package/templates/app/_gitignore +9 -0
- package/templates/app/apps/api/package.json +2 -2
- package/templates/app/apps/api/src/main.ts +5 -1
- package/templates/app/apps/api/src/worker.ts +3 -0
- package/templates/app/apps/web/index.html +1 -0
- package/templates/app/apps/web/package.json +7 -3
- package/templates/app/apps/web/src/app/app.tsx +128 -0
- package/templates/app/apps/web/src/{style.css → app/styles/global.css} +88 -8
- package/templates/app/apps/web/src/app/use-session.ts +43 -0
- package/templates/app/apps/web/src/app/workspace-layout.tsx +109 -0
- package/templates/app/apps/web/src/main.tsx +9 -543
- package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +31 -0
- package/templates/app/apps/web/src/modules/approval/index.ts +6 -0
- package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +73 -0
- package/templates/app/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +71 -0
- package/templates/app/apps/web/src/modules/inventory/index.ts +5 -0
- package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +102 -0
- package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
- package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +82 -0
- package/templates/app/apps/web/src/modules/purchase/index.ts +7 -0
- package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +240 -0
- package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
- package/templates/app/apps/web/src/shared/hooks/use-command.ts +42 -0
- package/templates/app/apps/web/src/shared/lib/error-message.ts +24 -0
- package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
- package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
- package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
- package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
- package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
- package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
- package/templates/app/apps/web/src/shared/ui/notice.tsx +20 -0
- package/templates/app/apps/web/src/shared/ui/page-heading.tsx +35 -0
- package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/app/apps/web/vite.config.ts +8 -0
- package/templates/app/cage.config.json +10 -1
- package/templates/app/db/migrations/0002_draft.sql +12 -0
- package/templates/app/db/migrations/0003_draft.sql +8 -0
- package/templates/app/deploy/nginx.conf +52 -0
- package/templates/app/docs/ai/README.md +98 -0
- package/templates/app/docs/ai/architecture.md +148 -0
- package/templates/app/docs/ai/commenting.md +203 -0
- package/templates/app/docs/ai/diagnostics.md +80 -0
- package/templates/app/docs/ai/files.md +93 -0
- package/templates/app/docs/ai/intelligence.md +348 -0
- package/templates/app/docs/ai/ontology-context.md +172 -0
- package/templates/app/docs/ai/primitives.md +282 -0
- package/templates/app/docs/ai/project-structure.md +128 -0
- package/templates/app/docs/ai/purchase-example.md +111 -0
- package/templates/app/docs/ai/recipes.md +89 -0
- package/templates/app/docs/ai/relations.md +160 -0
- package/templates/app/docs/ai/routing.md +86 -0
- package/templates/app/docs/ai/transfers.md +92 -0
- package/templates/app/docs/ai/troubleshooting.md +65 -0
- package/templates/app/docs/ai/workflow.md +152 -0
- package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
- package/templates/app/docs/errors/CAGE-APPR-001.md +48 -0
- package/templates/app/docs/errors/CAGE-APPR-002.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-003.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-004.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-005.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-006.md +53 -0
- package/templates/app/docs/errors/CAGE-APPR-007.md +50 -0
- package/templates/app/docs/errors/CAGE-APPR-010.md +48 -0
- package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
- package/templates/app/docs/errors/CAGE-AUTH-001.md +47 -0
- package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
- package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
- package/templates/app/docs/errors/CAGE-BUDGET-001.md +47 -0
- package/templates/app/docs/errors/CAGE-BUDGET-002.md +47 -0
- package/templates/app/docs/errors/CAGE-BUDGET-003.md +47 -0
- package/templates/app/docs/errors/CAGE-CMD-002.md +47 -0
- package/templates/app/docs/errors/CAGE-CMD-003.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-001.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-002.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-003.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-004.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-005.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-006.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-007.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-008.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-009.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-010.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-011.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-012.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
- package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
- package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
- package/templates/app/docs/errors/CAGE-CREATE-001.md +53 -0
- package/templates/app/docs/errors/CAGE-DECL-001.md +48 -0
- package/templates/app/docs/errors/CAGE-DECL-002.md +48 -0
- package/templates/app/docs/errors/CAGE-DECL-003.md +47 -0
- package/templates/app/docs/errors/CAGE-DECL-004.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-001.md +48 -0
- package/templates/app/docs/errors/CAGE-DEP-002.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-003.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-004.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-005.md +47 -0
- package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
- package/templates/app/docs/errors/CAGE-DLQ-001.md +48 -0
- package/templates/app/docs/errors/CAGE-ENV-001.md +52 -0
- package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
- package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
- package/templates/app/docs/errors/CAGE-EVENT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-EVENT-002.md +50 -0
- package/templates/app/docs/errors/CAGE-FIELD-001.md +47 -0
- package/templates/app/docs/errors/CAGE-FIELD-002.md +47 -0
- package/templates/app/docs/errors/CAGE-FIELD-003.md +47 -0
- package/templates/app/docs/errors/CAGE-FIELD-004.md +47 -0
- package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
- package/templates/app/docs/errors/CAGE-GEN-001.md +48 -0
- package/templates/app/docs/errors/CAGE-GEN-002.md +47 -0
- package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
- package/templates/app/docs/errors/CAGE-GRANT-001.md +49 -0
- package/templates/app/docs/errors/CAGE-GRANT-002.md +48 -0
- package/templates/app/docs/errors/CAGE-GRANT-003.md +48 -0
- package/templates/app/docs/errors/CAGE-IMPACT-001.md +48 -0
- package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
- package/templates/app/docs/errors/CAGE-INIT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-INIT-002.md +49 -0
- package/templates/app/docs/errors/CAGE-INIT-003.md +48 -0
- package/templates/app/docs/errors/CAGE-INIT-004.md +48 -0
- package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
- package/templates/app/docs/errors/CAGE-JOB-001.md +47 -0
- package/templates/app/docs/errors/CAGE-JOB-002.md +47 -0
- package/templates/app/docs/errors/CAGE-JOB-003.md +47 -0
- package/templates/app/docs/errors/CAGE-LINT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-MIG-001.md +47 -0
- package/templates/app/docs/errors/CAGE-MIG-002.md +47 -0
- package/templates/app/docs/errors/CAGE-MIG-003.md +5 -0
- package/templates/app/docs/errors/CAGE-MIG-004.md +5 -0
- package/templates/app/docs/errors/CAGE-MIG-005.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-001.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-002.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-003.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-004.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-005.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-006.md +47 -0
- package/templates/app/docs/errors/CAGE-ORG-001.md +50 -0
- package/templates/app/docs/errors/CAGE-PAIR-002.md +51 -0
- package/templates/app/docs/errors/CAGE-QUERY-001.md +47 -0
- package/templates/app/docs/errors/CAGE-QUERY-002.md +47 -0
- package/templates/app/docs/errors/CAGE-QUERY-003.md +50 -0
- package/templates/app/docs/errors/CAGE-REACT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-REACT-002.md +47 -0
- package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
- package/templates/app/docs/errors/CAGE-READS-001.md +50 -0
- package/templates/app/docs/errors/CAGE-REG-001.md +54 -0
- package/templates/app/docs/errors/CAGE-REG-002.md +49 -0
- package/templates/app/docs/errors/CAGE-REG-003.md +47 -0
- package/templates/app/docs/errors/CAGE-REL-001.md +64 -0
- package/templates/app/docs/errors/CAGE-ROUTE-001.md +48 -0
- package/templates/app/docs/errors/CAGE-SCOPE-001.md +47 -0
- package/templates/app/docs/errors/CAGE-SCOPE-002.md +47 -0
- package/templates/app/docs/errors/CAGE-SECRET-001.md +48 -0
- package/templates/app/docs/errors/CAGE-SECRET-002.md +47 -0
- package/templates/app/docs/errors/CAGE-SENS-001.md +48 -0
- package/templates/app/docs/errors/CAGE-SQL-001.md +47 -0
- package/templates/app/docs/errors/CAGE-SQL-002.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-001.md +49 -0
- package/templates/app/docs/errors/CAGE-STATE-002.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-003.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-004.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-005.md +49 -0
- package/templates/app/docs/errors/CAGE-STATE-010.md +48 -0
- package/templates/app/docs/errors/CAGE-STATE-011.md +48 -0
- package/templates/app/docs/errors/CAGE-STRUCT-001.md +51 -0
- package/templates/app/docs/errors/CAGE-STRUCT-002.md +51 -0
- package/templates/app/docs/errors/CAGE-SYNC-001.md +49 -0
- package/templates/app/docs/errors/CAGE-TEST-001.md +47 -0
- package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
- package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
- package/templates/app/docs/errors/CAGE-UNSAFE-001.md +49 -0
- package/templates/app/docs/errors/CAGE-UPGRADE-001.md +48 -0
- package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
- package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
- package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
- package/templates/app/docs/errors/README.md +357 -0
- package/templates/app/docs/errors/runtime.md +50 -0
- package/templates/app/package.json +4 -7
- package/templates/app/packages/contracts/package.json +1 -1
- package/templates/app/packages/contracts/src/{dept.ts → aggregates/dept/index.ts} +11 -11
- package/templates/app/packages/contracts/src/{inventory.ts → aggregates/inventory/index.ts} +6 -6
- package/templates/app/packages/contracts/src/{inventory-lock.ts → aggregates/inventory-lock/index.ts} +5 -5
- package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +86 -0
- package/templates/app/packages/contracts/src/{role.ts → aggregates/role/index.ts} +16 -16
- package/templates/app/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/app/packages/contracts/src/index.ts +20 -14
- package/templates/app/packages/contracts/src/{queries.ts → queries/index.ts} +2 -2
- package/templates/app/packages/domain/package.json +5 -4
- package/templates/app/packages/domain/src/index.ts +8 -7
- package/templates/app/packages/domain/src/{erp.ts → integrations/erp.ts} +16 -1
- package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
- package/templates/app/packages/domain/src/modules/inventory/index.ts +3 -0
- package/templates/app/packages/domain/src/{inventory.ts → modules/inventory/inventory.ts} +12 -0
- package/templates/app/packages/domain/src/modules/purchase/approvals.ts +39 -0
- package/templates/app/packages/domain/src/modules/purchase/index.ts +7 -0
- package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
- package/templates/app/packages/domain/src/{jobs.ts → modules/purchase/jobs.ts} +5 -0
- package/templates/app/packages/domain/src/{purchase-order.test.ts → modules/purchase/purchase-order.test.ts} +11 -2
- package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +192 -0
- package/templates/app/packages/domain/src/{queries.ts → modules/purchase/queries.ts} +5 -0
- package/templates/app/packages/domain/src/{reactions.ts → workflows/purchase-inventory.ts} +8 -2
- package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
- package/templates/blank/.dockerignore +12 -0
- package/templates/blank/.env.example +71 -0
- package/templates/blank/.github/workflows/cage.yml +44 -0
- package/templates/blank/AGENTS.md +136 -0
- package/templates/blank/Dockerfile +25 -0
- package/templates/blank/README.md +40 -0
- package/templates/blank/_gitignore +9 -0
- package/templates/blank/apps/api/package.json +15 -0
- package/templates/blank/apps/api/src/main.ts +14 -0
- package/templates/blank/apps/api/src/worker.ts +10 -0
- package/templates/blank/apps/api/tsconfig.json +5 -0
- package/templates/blank/apps/web/index.html +14 -0
- package/templates/blank/apps/web/package.json +26 -0
- package/templates/blank/apps/web/src/app/app.tsx +106 -0
- package/templates/blank/apps/web/src/app/styles/global.css +606 -0
- package/templates/blank/apps/web/src/app/use-session.ts +43 -0
- package/templates/blank/apps/web/src/app/workspace-layout.tsx +95 -0
- package/templates/blank/apps/web/src/main.tsx +18 -0
- package/templates/blank/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +104 -0
- package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
- package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
- package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
- package/templates/blank/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +62 -0
- package/templates/blank/apps/web/src/shared/lib/error-message.ts +22 -0
- package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/blank/apps/web/src/shared/ui/brand.tsx +19 -0
- package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/blank/apps/web/tsconfig.json +11 -0
- package/templates/blank/apps/web/vite.config.ts +24 -0
- package/templates/blank/cage.config.json +14 -0
- package/templates/blank/db/migrations/0001_init.sql +63 -0
- package/templates/blank/deploy/nginx.conf +52 -0
- package/templates/blank/docs/ai/README.md +98 -0
- package/templates/blank/docs/ai/architecture.md +148 -0
- package/templates/blank/docs/ai/commenting.md +203 -0
- package/templates/blank/docs/ai/diagnostics.md +80 -0
- package/templates/blank/docs/ai/files.md +93 -0
- package/templates/blank/docs/ai/intelligence.md +348 -0
- package/templates/blank/docs/ai/ontology-context.md +172 -0
- package/templates/blank/docs/ai/primitives.md +282 -0
- package/templates/blank/docs/ai/project-structure.md +128 -0
- package/templates/blank/docs/ai/purchase-example.md +111 -0
- package/templates/blank/docs/ai/recipes.md +89 -0
- package/templates/blank/docs/ai/relations.md +160 -0
- package/templates/blank/docs/ai/routing.md +86 -0
- package/templates/blank/docs/ai/transfers.md +92 -0
- package/templates/blank/docs/ai/troubleshooting.md +65 -0
- package/templates/blank/docs/ai/workflow.md +152 -0
- package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
- package/templates/blank/docs/errors/CAGE-APPR-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-APPR-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-006.md +53 -0
- package/templates/blank/docs/errors/CAGE-APPR-007.md +50 -0
- package/templates/blank/docs/errors/CAGE-APPR-010.md +48 -0
- package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-AUTH-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
- package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-CMD-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-CMD-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-006.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-007.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-008.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-009.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-010.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-011.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-012.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
- package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
- package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
- package/templates/blank/docs/errors/CAGE-CREATE-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-DECL-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-DECL-002.md +48 -0
- package/templates/blank/docs/errors/CAGE-DECL-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-DECL-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-DEP-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-DLQ-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-ENV-001.md +52 -0
- package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-EVENT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-EVENT-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-FIELD-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-FIELD-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-FIELD-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-FIELD-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
- package/templates/blank/docs/errors/CAGE-GEN-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-GEN-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
- package/templates/blank/docs/errors/CAGE-GRANT-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-GRANT-002.md +48 -0
- package/templates/blank/docs/errors/CAGE-GRANT-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-IMPACT-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
- package/templates/blank/docs/errors/CAGE-INIT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-INIT-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-INIT-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-INIT-004.md +48 -0
- package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
- package/templates/blank/docs/errors/CAGE-JOB-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-JOB-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-JOB-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-LINT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-MIG-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-MIG-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-MIG-003.md +5 -0
- package/templates/blank/docs/errors/CAGE-MIG-004.md +5 -0
- package/templates/blank/docs/errors/CAGE-MIG-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-006.md +47 -0
- package/templates/blank/docs/errors/CAGE-ORG-001.md +50 -0
- package/templates/blank/docs/errors/CAGE-PAIR-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-QUERY-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-QUERY-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-QUERY-003.md +50 -0
- package/templates/blank/docs/errors/CAGE-REACT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-REACT-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
- package/templates/blank/docs/errors/CAGE-READS-001.md +50 -0
- package/templates/blank/docs/errors/CAGE-REG-001.md +54 -0
- package/templates/blank/docs/errors/CAGE-REG-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-REG-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-REL-001.md +64 -0
- package/templates/blank/docs/errors/CAGE-ROUTE-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-SCOPE-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-SCOPE-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-SECRET-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-SECRET-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-SENS-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-SQL-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-SQL-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-STATE-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-005.md +49 -0
- package/templates/blank/docs/errors/CAGE-STATE-010.md +48 -0
- package/templates/blank/docs/errors/CAGE-STATE-011.md +48 -0
- package/templates/blank/docs/errors/CAGE-STRUCT-001.md +51 -0
- package/templates/blank/docs/errors/CAGE-STRUCT-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-SYNC-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-TEST-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
- package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
- package/templates/blank/docs/errors/README.md +357 -0
- package/templates/blank/docs/errors/runtime.md +50 -0
- package/templates/blank/docs/examples/purchase-admin/README.md +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +14 -0
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +17 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +128 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +743 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +109 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +18 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +31 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +6 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +73 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +71 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +102 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +82 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +7 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +240 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +42 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +24 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +20 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +35 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/blank/docs/examples/purchase-admin/cage.config.json +123 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +74 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +57 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +86 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +85 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +87 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +17 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +10 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +51 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +3 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +55 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +39 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +7 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +18 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +146 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +192 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +15 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +30 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
- package/templates/blank/package.json +22 -0
- package/templates/blank/packages/contracts/package.json +16 -0
- package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +74 -0
- package/templates/blank/packages/contracts/src/aggregates/role/index.ts +85 -0
- package/templates/blank/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/blank/packages/contracts/src/index.ts +55 -0
- package/templates/blank/packages/contracts/src/queries/index.ts +13 -0
- package/templates/blank/packages/contracts/tsconfig.json +5 -0
- package/templates/blank/packages/domain/package.json +24 -0
- package/templates/blank/packages/domain/src/index.ts +5 -0
- package/templates/blank/packages/domain/tsconfig.json +5 -0
- package/templates/blank/pnpm-workspace.yaml +10 -0
- package/templates/blank/renovate.json +5 -0
- package/templates/blank/tsconfig.base.json +8 -0
- package/dist/database.d.ts +0 -5
- package/dist/database.js +0 -70
- package/dist/database.js.map +0 -1
- package/managed/errors/CAGE-APPR-001.md +0 -32
- package/managed/errors/CAGE-APPR-002.md +0 -32
- package/managed/errors/CAGE-APPR-003.md +0 -32
- package/managed/errors/CAGE-APPR-004.md +0 -32
- package/managed/errors/CAGE-APPR-005.md +0 -32
- package/managed/errors/CAGE-APPR-006.md +0 -32
- package/managed/errors/CAGE-APPR-007.md +0 -32
- package/managed/errors/CAGE-APPR-010.md +0 -32
- package/managed/errors/CAGE-AUTH-001.md +0 -32
- package/managed/errors/CAGE-BUDGET-001.md +0 -32
- package/managed/errors/CAGE-BUDGET-002.md +0 -32
- package/managed/errors/CAGE-BUDGET-003.md +0 -32
- package/managed/errors/CAGE-CMD-002.md +0 -32
- package/managed/errors/CAGE-CMD-003.md +0 -34
- package/managed/errors/CAGE-CONN-001.md +0 -32
- package/managed/errors/CAGE-CONN-002.md +0 -32
- package/managed/errors/CAGE-CONN-003.md +0 -32
- package/managed/errors/CAGE-CONN-004.md +0 -32
- package/managed/errors/CAGE-CONN-005.md +0 -32
- package/managed/errors/CAGE-CONN-006.md +0 -32
- package/managed/errors/CAGE-CONN-007.md +0 -32
- package/managed/errors/CAGE-CONN-008.md +0 -32
- package/managed/errors/CAGE-CONN-009.md +0 -32
- package/managed/errors/CAGE-CONN-010.md +0 -32
- package/managed/errors/CAGE-CONN-011.md +0 -32
- package/managed/errors/CAGE-CONN-012.md +0 -32
- package/managed/errors/CAGE-CREATE-001.md +0 -32
- package/managed/errors/CAGE-DECL-001.md +0 -34
- package/managed/errors/CAGE-DECL-002.md +0 -34
- package/managed/errors/CAGE-DECL-003.md +0 -34
- package/managed/errors/CAGE-DECL-004.md +0 -34
- package/managed/errors/CAGE-DEP-001.md +0 -34
- package/managed/errors/CAGE-DEP-002.md +0 -34
- package/managed/errors/CAGE-DEP-003.md +0 -34
- package/managed/errors/CAGE-DEP-004.md +0 -34
- package/managed/errors/CAGE-DEP-005.md +0 -34
- package/managed/errors/CAGE-DLQ-001.md +0 -32
- package/managed/errors/CAGE-ENV-001.md +0 -32
- package/managed/errors/CAGE-EVENT-001.md +0 -32
- package/managed/errors/CAGE-EVENT-002.md +0 -32
- package/managed/errors/CAGE-FIELD-001.md +0 -32
- package/managed/errors/CAGE-FIELD-002.md +0 -32
- package/managed/errors/CAGE-FIELD-003.md +0 -32
- package/managed/errors/CAGE-FIELD-004.md +0 -32
- package/managed/errors/CAGE-GEN-001.md +0 -33
- package/managed/errors/CAGE-GEN-002.md +0 -33
- package/managed/errors/CAGE-GRANT-001.md +0 -32
- package/managed/errors/CAGE-GRANT-002.md +0 -32
- package/managed/errors/CAGE-GRANT-003.md +0 -32
- package/managed/errors/CAGE-IMPACT-001.md +0 -32
- package/managed/errors/CAGE-JOB-001.md +0 -32
- package/managed/errors/CAGE-JOB-002.md +0 -32
- package/managed/errors/CAGE-JOB-003.md +0 -32
- package/managed/errors/CAGE-LINT-001.md +0 -32
- package/managed/errors/CAGE-MIG-001.md +0 -32
- package/managed/errors/CAGE-MIG-002.md +0 -32
- package/managed/errors/CAGE-MIG-003.md +0 -32
- package/managed/errors/CAGE-MIG-004.md +0 -32
- package/managed/errors/CAGE-MIG-005.md +0 -32
- package/managed/errors/CAGE-NAME-001.md +0 -32
- package/managed/errors/CAGE-NAME-002.md +0 -32
- package/managed/errors/CAGE-NAME-003.md +0 -32
- package/managed/errors/CAGE-NAME-004.md +0 -32
- package/managed/errors/CAGE-NAME-005.md +0 -32
- package/managed/errors/CAGE-NAME-006.md +0 -32
- package/managed/errors/CAGE-ORG-001.md +0 -32
- package/managed/errors/CAGE-PAIR-002.md +0 -33
- package/managed/errors/CAGE-QUERY-001.md +0 -32
- package/managed/errors/CAGE-QUERY-002.md +0 -32
- package/managed/errors/CAGE-QUERY-003.md +0 -32
- package/managed/errors/CAGE-REACT-001.md +0 -32
- package/managed/errors/CAGE-REACT-002.md +0 -32
- package/managed/errors/CAGE-READS-001.md +0 -32
- package/managed/errors/CAGE-REG-001.md +0 -32
- package/managed/errors/CAGE-REG-002.md +0 -32
- package/managed/errors/CAGE-REG-003.md +0 -32
- package/managed/errors/CAGE-ROUTE-001.md +0 -32
- package/managed/errors/CAGE-SCOPE-001.md +0 -32
- package/managed/errors/CAGE-SCOPE-002.md +0 -32
- package/managed/errors/CAGE-SECRET-001.md +0 -32
- package/managed/errors/CAGE-SECRET-002.md +0 -32
- package/managed/errors/CAGE-SENS-001.md +0 -32
- package/managed/errors/CAGE-SQL-001.md +0 -32
- package/managed/errors/CAGE-SQL-002.md +0 -32
- package/managed/errors/CAGE-STATE-001.md +0 -32
- package/managed/errors/CAGE-STATE-002.md +0 -32
- package/managed/errors/CAGE-STATE-003.md +0 -32
- package/managed/errors/CAGE-STATE-004.md +0 -32
- package/managed/errors/CAGE-STATE-005.md +0 -32
- package/managed/errors/CAGE-STATE-010.md +0 -32
- package/managed/errors/CAGE-STATE-011.md +0 -32
- package/managed/errors/CAGE-SYNC-001.md +0 -35
- package/managed/errors/CAGE-TEST-001.md +0 -33
- package/managed/errors/CAGE-UNSAFE-001.md +0 -32
- package/managed/errors/CAGE-UPGRADE-001.md +0 -32
- package/managed/errors/README.md +0 -99
- package/templates/app/compose.yaml +0 -39
- package/templates/app/packages/contracts/src/purchase-order.ts +0 -72
- package/templates/app/packages/contracts/src/user.ts +0 -89
- package/templates/app/packages/domain/src/approvals.ts +0 -18
- package/templates/app/packages/domain/src/purchase-order.ts +0 -122
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 已登录空白应用的公共外壳,装配品牌、导航、账号信息、退出登录和子页面 Outlet。
|
|
3
|
+
* 成员目录和系统管理入口依据 User.read 能力显示;该显示判断不代表拥有全部管理操作。
|
|
4
|
+
*/
|
|
5
|
+
// 应用壳负责导航和账号状态;具体页面通过业务模块的公开入口组合。
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
import { NavLink, Outlet, useLocation } from 'react-router-dom';
|
|
8
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
9
|
+
import { client, currentUser, useCan } from '@app/contracts';
|
|
10
|
+
import { errorMessages } from '../shared/lib/error-message';
|
|
11
|
+
import { Brand } from '../shared/ui/brand';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 从路由计算当前位置标题,读取当前账号与能力,承载各业务模块页面。
|
|
15
|
+
* onLogout 由 app 提供,退出请求成功并清空缓存后调用;失败在当前页面显示原因。
|
|
16
|
+
*/
|
|
17
|
+
export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
|
|
18
|
+
// 能力只决定界面入口是否展示;系统管理接口还会再次校验授权。
|
|
19
|
+
const canManage = useCan('User.read');
|
|
20
|
+
const [busy, setBusy] = useState(false);
|
|
21
|
+
const [error, setError] = useState('');
|
|
22
|
+
const user = currentUser();
|
|
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
|
+
: '页面';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 等待 SDK 结束服务端会话,成功才清除查询缓存并通知 app。
|
|
35
|
+
* 失败不伪造已退出状态;按钮在结果返回前保持忙碌。
|
|
36
|
+
*/
|
|
37
|
+
async function logout() {
|
|
38
|
+
setBusy(true);
|
|
39
|
+
const result = await client.logout();
|
|
40
|
+
setBusy(false);
|
|
41
|
+
if (result.ok) {
|
|
42
|
+
cache.clear();
|
|
43
|
+
onLogout();
|
|
44
|
+
} else setError(errorMessages[result.code]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="workspace">
|
|
49
|
+
<aside className="sidebar">
|
|
50
|
+
<Brand />
|
|
51
|
+
<span className="sidebar-label">工作空间</span>
|
|
52
|
+
<NavLink className={({ isActive }) => `nav-item${isActive ? ' active' : ''}`} to="/workspace">
|
|
53
|
+
<span aria-hidden="true">◫</span>工作台<span className="nav-arrow">↗</span>
|
|
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
|
+
)}
|
|
60
|
+
{canManage && (
|
|
61
|
+
<a className="nav-item" href="/admin/">
|
|
62
|
+
<span aria-hidden="true">⚙</span>系统管理<span className="nav-arrow">↗</span>
|
|
63
|
+
</a>
|
|
64
|
+
)}
|
|
65
|
+
<div className="sidebar-note">
|
|
66
|
+
<span className="status-dot" />
|
|
67
|
+
从一个好起点出发
|
|
68
|
+
</div>
|
|
69
|
+
</aside>
|
|
70
|
+
<div className="workspace-body">
|
|
71
|
+
<header className="topbar">
|
|
72
|
+
<span>
|
|
73
|
+
工作空间<span className="breadcrumb-divider">/</span>
|
|
74
|
+
<strong>{page}</strong>
|
|
75
|
+
</span>
|
|
76
|
+
<div className="account">
|
|
77
|
+
<span className="avatar">{user?.name.slice(0, 1)}</span>
|
|
78
|
+
<span>{user?.name}</span>
|
|
79
|
+
<button className="text-button" onClick={logout} disabled={busy}>
|
|
80
|
+
{busy ? '正在退出…' : '退出登录'}
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
</header>
|
|
84
|
+
<main className="workspace-content">
|
|
85
|
+
{error && (
|
|
86
|
+
<p className="error" role="alert">
|
|
87
|
+
{error}
|
|
88
|
+
</p>
|
|
89
|
+
)}
|
|
90
|
+
<Outlet />
|
|
91
|
+
</main>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 空白业务应用的浏览器启动入口,创建共享 QueryClient 并挂载 app 路由。
|
|
3
|
+
* 新增业务页面使用同一 Provider 内的生成查询 hooks;此处只装配前端,不注册领域或连接数据库。
|
|
4
|
+
* 全局样式由入口加载,会话失效与账号切换时的查询清理由 useSession 负责。
|
|
5
|
+
*/
|
|
6
|
+
// 浏览器入口只负责挂载和全局 Provider。QueryClient 让新增模块可直接使用生成查询 hooks。
|
|
7
|
+
import { createRoot } from 'react-dom/client';
|
|
8
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
9
|
+
import { App } from './app/app';
|
|
10
|
+
import './app/styles/global.css';
|
|
11
|
+
|
|
12
|
+
const queryClient = new QueryClient();
|
|
13
|
+
|
|
14
|
+
createRoot(document.getElementById('root')!).render(
|
|
15
|
+
<QueryClientProvider client={queryClient}>
|
|
16
|
+
<App />
|
|
17
|
+
</QueryClientProvider>,
|
|
18
|
+
);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 空白应用的登录表单,使用客户端完成认证并由 app 决定成功后的导航。
|
|
3
|
+
* SDK 先认证再读取当前用户和能力,两阶段都成功才通知 app;身份读取失败保留在登录页展示。
|
|
4
|
+
* 账号密码仅用于本次提交,不在本组件持久化或输出日志。
|
|
5
|
+
*/
|
|
6
|
+
// 认证模块拥有登录表单;登录后的导航由 app 组合层处理。
|
|
7
|
+
import { useState, type FormEvent } from 'react';
|
|
8
|
+
import { client } from '@app/contracts';
|
|
9
|
+
import { errorMessages } from '../../../shared/lib/error-message';
|
|
10
|
+
import { Brand } from '../../../shared/ui/brand';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 维护本地忙碌与错误状态,使用统一错误文案;成功调用 onLogin 更新应用会话状态。
|
|
14
|
+
* 页面不直接消费未验证的 returnTo,也不会把网络错误当成登录成功。
|
|
15
|
+
*/
|
|
16
|
+
export function LoginPage({ onLogin }: { onLogin: () => void }) {
|
|
17
|
+
const [busy, setBusy] = useState(false);
|
|
18
|
+
const [error, setError] = useState('');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 读取表单中的账号密码并等待 client.login;SDK 完成会话协议与用户能力同步。
|
|
22
|
+
* 返回失败结果时保留页面并提示原因,成功后回跳由 app 路由处理。
|
|
23
|
+
* NOT_FOUND 来自认证后读取当前身份的 GET 结果,单独提示服务配置问题,不误报为账号密码错误。
|
|
24
|
+
*/
|
|
25
|
+
async function submit(event: FormEvent<HTMLFormElement>) {
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
const form = new FormData(event.currentTarget);
|
|
28
|
+
setBusy(true);
|
|
29
|
+
setError('');
|
|
30
|
+
// SDK 自动处理会话 Cookie、CSRF 与幂等键;成功后同步当前用户和能力列表。
|
|
31
|
+
const result = await client.login(String(form.get('username')), String(form.get('password')));
|
|
32
|
+
setBusy(false);
|
|
33
|
+
if (result.ok) onLogin();
|
|
34
|
+
else if (result.code === 'NOT_FOUND') {
|
|
35
|
+
// login 的返回类型包含 loadMe 的读取错误;先处理该分支,剩余代码仍由 CommonError 映射穷尽检查。
|
|
36
|
+
setError('无法加载当前登录信息,请检查 API 配置或联系管理员。');
|
|
37
|
+
} else setError(errorMessages[result.code]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<main className="login-layout">
|
|
42
|
+
<section className="login-story">
|
|
43
|
+
<Brand />
|
|
44
|
+
<div className="story-copy">
|
|
45
|
+
<p className="eyebrow">为你的业务,留出空间</p>
|
|
46
|
+
<h1>
|
|
47
|
+
从这里,
|
|
48
|
+
<br />
|
|
49
|
+
开始自己的业务<span>。</span>
|
|
50
|
+
</h1>
|
|
51
|
+
<p className="story-description">
|
|
52
|
+
基础已经就绪。让每一个流程,
|
|
53
|
+
<br />
|
|
54
|
+
按你的业务方式运转。
|
|
55
|
+
</p>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="story-foot">
|
|
58
|
+
<span className="status-dot" />
|
|
59
|
+
业务工作台<span className="edition">CAGE / WORKSPACE</span>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
<section className="login-panel" aria-labelledby="login-title">
|
|
63
|
+
<div className="login-form-wrap">
|
|
64
|
+
<span className="section-number">01 / 欢迎回来</span>
|
|
65
|
+
<h2 id="login-title">登录工作台</h2>
|
|
66
|
+
<p className="muted">使用管理员为你配置的账号继续。</p>
|
|
67
|
+
<form onSubmit={submit} className="login-form">
|
|
68
|
+
<label htmlFor="username">账号</label>
|
|
69
|
+
<input
|
|
70
|
+
id="username"
|
|
71
|
+
name="username"
|
|
72
|
+
autoComplete="username"
|
|
73
|
+
placeholder="请输入账号"
|
|
74
|
+
required
|
|
75
|
+
autoFocus
|
|
76
|
+
disabled={busy}
|
|
77
|
+
/>
|
|
78
|
+
<label htmlFor="password">密码</label>
|
|
79
|
+
<input
|
|
80
|
+
id="password"
|
|
81
|
+
name="password"
|
|
82
|
+
type="password"
|
|
83
|
+
autoComplete="current-password"
|
|
84
|
+
placeholder="请输入密码"
|
|
85
|
+
required
|
|
86
|
+
disabled={busy}
|
|
87
|
+
/>
|
|
88
|
+
{error && (
|
|
89
|
+
<p className="error" role="alert">
|
|
90
|
+
{error}
|
|
91
|
+
</p>
|
|
92
|
+
)}
|
|
93
|
+
<button className="primary" disabled={busy}>
|
|
94
|
+
{busy ? '正在登录…' : '进入工作台'}
|
|
95
|
+
<span aria-hidden="true">↗</span>
|
|
96
|
+
</button>
|
|
97
|
+
</form>
|
|
98
|
+
<p className="login-note">首次使用的管理员账号,请查看 API 启动终端。</p>
|
|
99
|
+
</div>
|
|
100
|
+
<span className="panel-foot">一个属于你的业务起点</span>
|
|
101
|
+
</section>
|
|
102
|
+
</main>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 空白业务项目的工作台首页,解释尚未添加业务模块并提供真实成员目录和管理入口。
|
|
3
|
+
* 不注册采购演示、不制造统计;客户业务应建立相邻模块,再经 app 接入导航。
|
|
4
|
+
*/
|
|
5
|
+
// 空白工作台模块:新增业务时建立相邻模块,由 app 导航接入,不在本页堆全部业务。
|
|
6
|
+
import { useCan } from '@app/contracts';
|
|
7
|
+
import { Link } from 'react-router-dom';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 根据 User.read 的界面能力展示组织相关入口,其余区域显示业务空状态。
|
|
11
|
+
* 拥有读取能力不等于获得全部管理权限;系统管理仍按具体操作检查能力。
|
|
12
|
+
*/
|
|
13
|
+
export function HomePage() {
|
|
14
|
+
const canManage = useCan('User.read');
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
<div className="page-heading">
|
|
18
|
+
<div>
|
|
19
|
+
<p className="eyebrow">你的工作空间</p>
|
|
20
|
+
<h1>工作台</h1>
|
|
21
|
+
<p className="muted">业务从这里开始,逐步长成你需要的样子。</p>
|
|
22
|
+
</div>
|
|
23
|
+
<span className="project-tag">空白业务项目</span>
|
|
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
|
+
)}
|
|
33
|
+
<section className="empty-state" aria-labelledby="empty-title">
|
|
34
|
+
<div className="empty-illustration" aria-hidden="true">
|
|
35
|
+
<div className="sheet sheet-back" />
|
|
36
|
+
<div className="sheet sheet-front">
|
|
37
|
+
<span />
|
|
38
|
+
<span />
|
|
39
|
+
<span />
|
|
40
|
+
<b>+</b>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<p className="eyebrow">准备好,开始新的业务</p>
|
|
44
|
+
<h2 id="empty-title">这里还没有业务模块</h2>
|
|
45
|
+
<p>
|
|
46
|
+
添加你的第一个业务对象和页面后,
|
|
47
|
+
<br />
|
|
48
|
+
这里就会成为团队日常工作的地方。
|
|
49
|
+
</p>
|
|
50
|
+
{canManage && (
|
|
51
|
+
<a className="primary manage-link" href="/admin/">
|
|
52
|
+
配置用户与权限<span aria-hidden="true">↗</span>
|
|
53
|
+
</a>
|
|
54
|
+
)}
|
|
55
|
+
</section>
|
|
56
|
+
<footer className="workspace-footer">
|
|
57
|
+
<span>Cage · 让业务有序发生</span>
|
|
58
|
+
<span>属于你的业务,由你定义</span>
|
|
59
|
+
</footer>
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 空白应用通用错误码的中文展示表,由登录页和公共外壳共享。
|
|
3
|
+
* 保持与 CommonError 类型覆盖一致;错误文案只供提示,控制流应仍判断客户端 ok/code。
|
|
4
|
+
* 取消和超时由客户端请求生命周期产生,不代表服务端一定没有完成操作,提示用户先确认当前状态。
|
|
5
|
+
*/
|
|
6
|
+
import type { CommonError } from '@app/contracts';
|
|
7
|
+
|
|
8
|
+
// 通用错误提示不依赖具体业务,登录页和应用壳复用它。
|
|
9
|
+
/**
|
|
10
|
+
* 完整映射认证、授权、输入、限流、服务异常、网络、取消和超时错误;新增业务领域错误由其模块单独说明。
|
|
11
|
+
* Record 保留穷尽检查,SDK 增加通用错误码时必须补充文案,不能用空提示或静默默认值掩盖缺项。
|
|
12
|
+
*/
|
|
13
|
+
export const errorMessages: Record<CommonError, string> = {
|
|
14
|
+
UNAUTHENTICATED: '账号或密码不正确,请重新输入。',
|
|
15
|
+
FORBIDDEN: '当前账号无法执行此操作,请联系管理员。',
|
|
16
|
+
INVALID_INPUT: '请检查输入的账号和密码。',
|
|
17
|
+
RATE_LIMITED: '操作过于频繁,请稍后重试。',
|
|
18
|
+
INTERNAL: '服务暂时无法处理请求,请稍后重试。',
|
|
19
|
+
NETWORK: '无法连接服务,请检查网络和 API 是否已启动。',
|
|
20
|
+
CANCELLED: '请求已取消,请确认当前页面状态后重试。',
|
|
21
|
+
TIMEOUT: '请求超时,请检查网络并确认操作结果后重试。',
|
|
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
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 登录页与工作台复用的品牌组件,只负责显示品牌及首页链接。
|
|
3
|
+
* 依赖 Router 的 Link 导航,不读取会话、不决定用户权限,也不导入具体业务模块。
|
|
4
|
+
*/
|
|
5
|
+
// 登录与工作台共用的品牌组件;只呈现,不读取模块或会话。
|
|
6
|
+
import { Link } from 'react-router-dom';
|
|
7
|
+
/**
|
|
8
|
+
* 渲染可访问名称完整的首页链接;未登录时目标页面仍由 app 的会话守卫处理。
|
|
9
|
+
*/
|
|
10
|
+
export function Brand() {
|
|
11
|
+
return (
|
|
12
|
+
<Link className="brand" to="/workspace" aria-label="Cage 工作台首页">
|
|
13
|
+
<span className="brand-mark">C</span>
|
|
14
|
+
<span>
|
|
15
|
+
Cage<span className="brand-dot">.</span>
|
|
16
|
+
</span>
|
|
17
|
+
</Link>
|
|
18
|
+
);
|
|
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
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 供列表、详情和路由守卫复用的页面级状态组件。
|
|
3
|
+
* 将服务端可确认的错误与可恢复操作对应,保留返回链接;不泄露范围外记录是否真实存在。
|
|
4
|
+
*/
|
|
5
|
+
import type { ReactNode } from 'react';
|
|
6
|
+
import { Link } from 'react-router-dom';
|
|
7
|
+
import { CageQueryError } from '@app/contracts';
|
|
8
|
+
import './page-state.css';
|
|
9
|
+
|
|
10
|
+
/** 页面级状态保留导航入口,详情直达失败时也能回到列表,而不是出现空白页。 */
|
|
11
|
+
/**
|
|
12
|
+
* 渲染标题、说明、返回链接和可选附加操作。
|
|
13
|
+
* props.title/description 为调用方提供的当前状态;to 是业务返回地址,label 缺省为返回列表。
|
|
14
|
+
* children 可放重试按钮;组件只呈现内容,不自行读取数据或推断错误。
|
|
15
|
+
*/
|
|
16
|
+
export function PageState({
|
|
17
|
+
title,
|
|
18
|
+
description,
|
|
19
|
+
to,
|
|
20
|
+
label = '返回列表',
|
|
21
|
+
children,
|
|
22
|
+
}: {
|
|
23
|
+
title: string;
|
|
24
|
+
description: string;
|
|
25
|
+
to: string;
|
|
26
|
+
label?: string;
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
}) {
|
|
29
|
+
return (
|
|
30
|
+
<section className="route-state" aria-labelledby="route-state-title">
|
|
31
|
+
<span className="route-state-mark" aria-hidden="true">
|
|
32
|
+
↗
|
|
33
|
+
</span>
|
|
34
|
+
<h1 id="route-state-title">{title}</h1>
|
|
35
|
+
<p>{description}</p>
|
|
36
|
+
<Link className="route-link" to={to}>
|
|
37
|
+
{label}
|
|
38
|
+
</Link>
|
|
39
|
+
{children}
|
|
40
|
+
</section>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 按服务端错误区分权限、范围/不存在和服务故障;不从 URL 推断记录是否存在。 */
|
|
45
|
+
/**
|
|
46
|
+
* 将查询异常映射为页面状态。CageQueryError 的 FORBIDDEN 与 NOT_FOUND 不展示重试按钮,其他错误允许调用 retry。
|
|
47
|
+
* props.error 为实际查询异常;to/label 决定退出路径,retry 由页面绑定 refetch。
|
|
48
|
+
* NOT_FOUND 同时涵盖记录不存在与不在可访问范围,不能据此向用户确认数据库中有无此记录。
|
|
49
|
+
*/
|
|
50
|
+
export function QueryFailure({
|
|
51
|
+
error,
|
|
52
|
+
to,
|
|
53
|
+
label,
|
|
54
|
+
retry,
|
|
55
|
+
}: {
|
|
56
|
+
error: Error;
|
|
57
|
+
to: string;
|
|
58
|
+
label?: string;
|
|
59
|
+
retry: () => void;
|
|
60
|
+
}) {
|
|
61
|
+
const code = error instanceof CageQueryError ? error.result.code : undefined;
|
|
62
|
+
const title = code === 'FORBIDDEN' ? '暂无访问权限' : code === 'NOT_FOUND' ? '记录不可用' : '暂时无法读取';
|
|
63
|
+
const description =
|
|
64
|
+
code === 'FORBIDDEN'
|
|
65
|
+
? '当前账号没有访问此页面所需的权限,请联系管理员。'
|
|
66
|
+
: code === 'NOT_FOUND'
|
|
67
|
+
? '记录不存在,或不在你当前可访问的数据范围内。'
|
|
68
|
+
: code === 'UNAUTHENTICATED'
|
|
69
|
+
? '登录已过期,请重新登录后继续。'
|
|
70
|
+
: '请检查网络或稍后重新尝试。';
|
|
71
|
+
return (
|
|
72
|
+
<PageState title={title} description={description} to={to} label={label}>
|
|
73
|
+
{code !== 'FORBIDDEN' && code !== 'NOT_FOUND' && <button onClick={retry}>重新读取</button>}
|
|
74
|
+
</PageState>
|
|
75
|
+
);
|
|
76
|
+
}
|