@yss123/cage-cli 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +40 -2
- package/bin/cage.js +6 -0
- package/bin/create-cage-app.js +6 -0
- package/dist/analyze.d.ts +18 -0
- package/dist/analyze.js +28 -0
- package/dist/analyze.js.map +1 -0
- package/dist/baseline.d.ts +5 -0
- package/dist/baseline.js +50 -0
- package/dist/baseline.js.map +1 -0
- package/dist/budget.d.ts +7 -0
- package/dist/budget.js +52 -0
- package/dist/budget.js.map +1 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +72 -0
- package/dist/context.js +202 -0
- package/dist/context.js.map +1 -0
- package/dist/create-prompt.d.ts +5 -0
- package/dist/create-prompt.js +50 -0
- package/dist/create-prompt.js.map +1 -0
- package/dist/create.d.ts +18 -0
- package/dist/create.js +64 -0
- package/dist/create.js.map +1 -0
- package/dist/derive.d.ts +14 -0
- package/dist/derive.js +163 -0
- package/dist/derive.js.map +1 -0
- package/dist/dev.d.ts +2 -0
- package/dist/dev.js +116 -0
- package/dist/dev.js.map +1 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +15 -0
- package/dist/env.js.map +1 -0
- package/dist/findings.d.ts +11 -0
- package/dist/findings.js +13 -0
- package/dist/findings.js.map +1 -0
- package/dist/gen/contracts.d.ts +6 -0
- package/dist/gen/contracts.js +188 -0
- package/dist/gen/contracts.js.map +1 -0
- package/dist/gen/index.d.ts +19 -0
- package/dist/gen/index.js +177 -0
- package/dist/gen/index.js.map +1 -0
- package/dist/gen/zod-code.d.ts +7 -0
- package/dist/gen/zod-code.js +163 -0
- package/dist/gen/zod-code.js.map +1 -0
- package/dist/graph-command.d.ts +11 -0
- package/dist/graph-command.js +67 -0
- package/dist/graph-command.js.map +1 -0
- package/dist/graph-model.d.ts +21 -0
- package/dist/graph-model.js +101 -0
- package/dist/graph-model.js.map +1 -0
- package/dist/graph-presentation.d.ts +11 -0
- package/dist/graph-presentation.js +25 -0
- package/dist/graph-presentation.js.map +1 -0
- package/dist/graph-query.d.ts +171 -0
- package/dist/graph-query.js +242 -0
- package/dist/graph-query.js.map +1 -0
- package/dist/graph-relations.d.ts +14 -0
- package/dist/graph-relations.js +142 -0
- package/dist/graph-relations.js.map +1 -0
- package/dist/graph-search.d.ts +21 -0
- package/dist/graph-search.js +63 -0
- package/dist/graph-search.js.map +1 -0
- package/dist/graph-snapshot.d.ts +11 -0
- package/dist/graph-snapshot.js +29 -0
- package/dist/graph-snapshot.js.map +1 -0
- package/dist/graph.d.ts +11 -0
- package/dist/graph.js +105 -0
- package/dist/graph.js.map +1 -0
- package/dist/impact.d.ts +34 -0
- package/dist/impact.js +235 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +6 -0
- package/dist/init.js +131 -0
- package/dist/init.js.map +1 -0
- package/dist/load.d.ts +6 -0
- package/dist/load.js +17 -0
- package/dist/load.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +221 -0
- package/dist/main.js.map +1 -0
- package/dist/migrate.d.ts +4 -0
- package/dist/migrate.js +30 -0
- package/dist/migrate.js.map +1 -0
- package/dist/ontology.d.ts +43 -0
- package/dist/ontology.js +280 -0
- package/dist/ontology.js.map +1 -0
- package/dist/process.d.ts +6 -0
- package/dist/process.js +39 -0
- package/dist/process.js.map +1 -0
- package/dist/project-structure.d.ts +8 -0
- package/dist/project-structure.js +94 -0
- package/dist/project-structure.js.map +1 -0
- package/dist/rules.d.ts +23 -0
- package/dist/rules.js +251 -0
- package/dist/rules.js.map +1 -0
- package/dist/static-check.d.ts +23 -0
- package/dist/static-check.js +222 -0
- package/dist/static-check.js.map +1 -0
- package/dist/sync.d.ts +5 -0
- package/dist/sync.js +118 -0
- package/dist/sync.js.map +1 -0
- package/dist/upgrade.d.ts +10 -0
- package/dist/upgrade.js +81 -0
- package/dist/upgrade.js.map +1 -0
- package/dist/verify.d.ts +7 -0
- package/dist/verify.js +88 -0
- package/dist/verify.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/graph-ui/app.js +1103 -0
- package/graph-ui/graph-model.js +100 -0
- package/graph-ui/graph-relations.js +141 -0
- package/graph-ui/graph-search.js +62 -0
- package/graph-ui/index.html +197 -0
- package/graph-ui/model.js +83 -0
- package/graph-ui/relations.js +2 -0
- package/graph-ui/structure.js +77 -0
- package/graph-ui/style.css +1719 -0
- package/package.json +60 -3
- package/templates/app/.dockerignore +10 -0
- package/templates/app/.env.example +61 -0
- package/templates/app/.github/workflows/cage.yml +44 -0
- package/templates/app/AGENTS.md +96 -0
- package/templates/app/Dockerfile +25 -0
- package/templates/app/README.md +88 -0
- package/templates/app/_gitignore +8 -0
- package/templates/app/apps/api/package.json +16 -0
- package/templates/app/apps/api/src/main.ts +10 -0
- package/templates/app/apps/api/src/worker.ts +14 -0
- package/templates/app/apps/api/tsconfig.json +5 -0
- package/templates/app/apps/web/index.html +13 -0
- package/templates/app/apps/web/package.json +22 -0
- package/templates/app/apps/web/src/app/app.tsx +18 -0
- package/templates/app/apps/web/src/app/styles/global.css +663 -0
- package/templates/app/apps/web/src/app/workspace-layout.tsx +70 -0
- package/templates/app/apps/web/src/main.tsx +13 -0
- package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +20 -0
- package/templates/app/apps/web/src/modules/approval/index.ts +2 -0
- package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +54 -0
- package/templates/app/apps/web/src/modules/auth/index.ts +1 -0
- package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +59 -0
- package/templates/app/apps/web/src/modules/inventory/index.ts +1 -0
- package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +74 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +60 -0
- package/templates/app/apps/web/src/modules/purchase/index.ts +2 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +210 -0
- package/templates/app/apps/web/src/shared/hooks/use-command.ts +29 -0
- package/templates/app/apps/web/src/shared/lib/error-message.ts +15 -0
- package/templates/app/apps/web/src/shared/ui/notice.tsx +13 -0
- package/templates/app/apps/web/src/shared/ui/page-heading.tsx +28 -0
- package/templates/app/apps/web/tsconfig.json +11 -0
- package/templates/app/apps/web/vite.config.ts +19 -0
- package/templates/app/cage.config.json +114 -0
- package/templates/app/db/migrations/0001_init.sql +112 -0
- package/templates/app/docs/ai/README.md +77 -0
- package/templates/app/docs/ai/architecture.md +122 -0
- package/templates/app/docs/ai/ontology-context.md +117 -0
- package/templates/app/docs/ai/primitives.md +249 -0
- package/templates/app/docs/ai/project-structure.md +123 -0
- package/templates/app/docs/ai/purchase-example.md +97 -0
- package/templates/app/docs/ai/recipes.md +81 -0
- package/templates/app/docs/ai/relations.md +160 -0
- package/templates/app/docs/ai/transfers.md +92 -0
- package/templates/app/docs/ai/troubleshooting.md +60 -0
- package/templates/app/docs/ai/workflow.md +139 -0
- package/templates/app/docs/errors/CAGE-APPR-001.md +47 -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 +47 -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-AUTH-001.md +47 -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-CREATE-001.md +52 -0
- package/templates/app/docs/errors/CAGE-DECL-001.md +48 -0
- package/templates/app/docs/errors/CAGE-DECL-002.md +47 -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-DLQ-001.md +48 -0
- package/templates/app/docs/errors/CAGE-ENV-001.md +52 -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-GEN-001.md +48 -0
- package/templates/app/docs/errors/CAGE-GEN-002.md +47 -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 +47 -0
- package/templates/app/docs/errors/CAGE-IMPACT-001.md +48 -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-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 +49 -0
- package/templates/app/docs/errors/CAGE-PAIR-002.md +50 -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 +49 -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-READS-001.md +47 -0
- package/templates/app/docs/errors/CAGE-REG-001.md +53 -0
- package/templates/app/docs/errors/CAGE-REG-002.md +48 -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 +47 -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 +48 -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 +48 -0
- package/templates/app/docs/errors/CAGE-TEST-001.md +47 -0
- package/templates/app/docs/errors/CAGE-UNSAFE-001.md +48 -0
- package/templates/app/docs/errors/CAGE-UPGRADE-001.md +48 -0
- package/templates/app/docs/errors/README.md +307 -0
- package/templates/app/docs/errors/runtime.md +50 -0
- package/templates/app/package.json +22 -0
- package/templates/app/packages/contracts/package.json +16 -0
- package/templates/app/packages/contracts/src/aggregates/dept/index.ts +74 -0
- package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +57 -0
- package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
- package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +72 -0
- package/templates/app/packages/contracts/src/aggregates/role/index.ts +85 -0
- package/templates/app/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/app/packages/contracts/src/index.ts +81 -0
- package/templates/app/packages/contracts/src/queries/index.ts +17 -0
- package/templates/app/packages/contracts/tsconfig.json +5 -0
- package/templates/app/packages/domain/package.json +23 -0
- package/templates/app/packages/domain/src/index.ts +6 -0
- package/templates/app/packages/domain/src/integrations/erp.ts +36 -0
- package/templates/app/packages/domain/src/modules/inventory/index.ts +2 -0
- package/templates/app/packages/domain/src/modules/inventory/inventory.ts +43 -0
- package/templates/app/packages/domain/src/modules/purchase/approvals.ts +18 -0
- package/templates/app/packages/domain/src/modules/purchase/index.ts +6 -0
- package/templates/app/packages/domain/src/modules/purchase/jobs.ts +13 -0
- package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +137 -0
- package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +122 -0
- package/templates/app/packages/domain/src/modules/purchase/queries.ts +10 -0
- package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +24 -0
- package/templates/app/packages/domain/tsconfig.json +5 -0
- package/templates/app/pnpm-workspace.yaml +10 -0
- package/templates/app/renovate.json +5 -0
- package/templates/app/tsconfig.base.json +8 -0
- package/templates/blank/.dockerignore +10 -0
- package/templates/blank/.env.example +61 -0
- package/templates/blank/.github/workflows/cage.yml +44 -0
- package/templates/blank/AGENTS.md +96 -0
- package/templates/blank/Dockerfile +25 -0
- package/templates/blank/README.md +37 -0
- package/templates/blank/_gitignore +8 -0
- package/templates/blank/apps/api/package.json +15 -0
- package/templates/blank/apps/api/src/main.ts +11 -0
- package/templates/blank/apps/api/src/worker.ts +8 -0
- package/templates/blank/apps/api/tsconfig.json +5 -0
- package/templates/blank/apps/web/index.html +13 -0
- package/templates/blank/apps/web/package.json +22 -0
- package/templates/blank/apps/web/src/app/app.tsx +44 -0
- package/templates/blank/apps/web/src/app/styles/global.css +516 -0
- package/templates/blank/apps/web/src/app/workspace-layout.tsx +70 -0
- package/templates/blank/apps/web/src/main.tsx +13 -0
- package/templates/blank/apps/web/src/modules/auth/index.ts +1 -0
- package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +87 -0
- package/templates/blank/apps/web/src/modules/workspace/index.ts +1 -0
- package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +45 -0
- package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
- package/templates/blank/apps/web/src/shared/ui/brand.tsx +11 -0
- package/templates/blank/apps/web/tsconfig.json +11 -0
- package/templates/blank/apps/web/vite.config.ts +19 -0
- package/templates/blank/cage.config.json +14 -0
- package/templates/blank/db/migrations/0001_init.sql +63 -0
- package/templates/blank/docs/ai/README.md +77 -0
- package/templates/blank/docs/ai/architecture.md +122 -0
- package/templates/blank/docs/ai/ontology-context.md +117 -0
- package/templates/blank/docs/ai/primitives.md +249 -0
- package/templates/blank/docs/ai/project-structure.md +123 -0
- package/templates/blank/docs/ai/purchase-example.md +97 -0
- package/templates/blank/docs/ai/recipes.md +81 -0
- package/templates/blank/docs/ai/relations.md +160 -0
- package/templates/blank/docs/ai/transfers.md +92 -0
- package/templates/blank/docs/ai/troubleshooting.md +60 -0
- package/templates/blank/docs/ai/workflow.md +139 -0
- package/templates/blank/docs/errors/CAGE-APPR-001.md +47 -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 +47 -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-AUTH-001.md +47 -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-CREATE-001.md +52 -0
- package/templates/blank/docs/errors/CAGE-DECL-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-DECL-002.md +47 -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-DLQ-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-ENV-001.md +52 -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-GEN-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-GEN-002.md +47 -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 +47 -0
- package/templates/blank/docs/errors/CAGE-IMPACT-001.md +48 -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-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 +49 -0
- package/templates/blank/docs/errors/CAGE-PAIR-002.md +50 -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 +49 -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-READS-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-REG-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-REG-002.md +48 -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 +47 -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 +48 -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 +48 -0
- package/templates/blank/docs/errors/CAGE-TEST-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +48 -0
- package/templates/blank/docs/errors/README.md +307 -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 +10 -0
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +14 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +18 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +663 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +70 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +13 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +2 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +54 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +1 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +59 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +1 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +74 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +60 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +2 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +210 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +29 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +15 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +13 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +28 -0
- package/templates/blank/docs/examples/purchase-admin/cage.config.json +114 -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 +72 -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 +81 -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 +6 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +36 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +2 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +43 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +18 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +6 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +13 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +137 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +122 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +10 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +24 -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 +23 -0
- package/templates/blank/packages/domain/src/index.ts +4 -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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// 空白工作台模块:新增业务时建立相邻模块,由 app 导航接入,不在本页堆全部业务。
|
|
2
|
+
import { useCan } from '@app/contracts';
|
|
3
|
+
|
|
4
|
+
export function HomePage() {
|
|
5
|
+
const canManage = useCan('User.read');
|
|
6
|
+
return (
|
|
7
|
+
<>
|
|
8
|
+
<div className="page-heading">
|
|
9
|
+
<div>
|
|
10
|
+
<p className="eyebrow">你的工作空间</p>
|
|
11
|
+
<h1>工作台</h1>
|
|
12
|
+
<p className="muted">业务从这里开始,逐步长成你需要的样子。</p>
|
|
13
|
+
</div>
|
|
14
|
+
<span className="project-tag">空白业务项目</span>
|
|
15
|
+
</div>
|
|
16
|
+
<section className="empty-state" aria-labelledby="empty-title">
|
|
17
|
+
<div className="empty-illustration" aria-hidden="true">
|
|
18
|
+
<div className="sheet sheet-back" />
|
|
19
|
+
<div className="sheet sheet-front">
|
|
20
|
+
<span />
|
|
21
|
+
<span />
|
|
22
|
+
<span />
|
|
23
|
+
<b>+</b>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<p className="eyebrow">准备好,开始新的业务</p>
|
|
27
|
+
<h2 id="empty-title">这里还没有业务模块</h2>
|
|
28
|
+
<p>
|
|
29
|
+
添加你的第一个业务对象和页面后,
|
|
30
|
+
<br />
|
|
31
|
+
这里就会成为团队日常工作的地方。
|
|
32
|
+
</p>
|
|
33
|
+
{canManage && (
|
|
34
|
+
<a className="primary manage-link" href="/admin/">
|
|
35
|
+
配置用户与权限<span aria-hidden="true">↗</span>
|
|
36
|
+
</a>
|
|
37
|
+
)}
|
|
38
|
+
</section>
|
|
39
|
+
<footer className="workspace-footer">
|
|
40
|
+
<span>Cage · 让业务有序发生</span>
|
|
41
|
+
<span>属于你的业务,由你定义</span>
|
|
42
|
+
</footer>
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CommonError } from '@app/contracts';
|
|
2
|
+
|
|
3
|
+
// 通用错误提示不依赖具体业务,登录页和应用壳复用它。
|
|
4
|
+
export const errorMessages: Record<CommonError, string> = {
|
|
5
|
+
UNAUTHENTICATED: '账号或密码不正确,请重新输入。',
|
|
6
|
+
FORBIDDEN: '当前账号无法执行此操作,请联系管理员。',
|
|
7
|
+
INVALID_INPUT: '请检查输入的账号和密码。',
|
|
8
|
+
RATE_LIMITED: '操作过于频繁,请稍后重试。',
|
|
9
|
+
INTERNAL: '服务暂时无法处理请求,请稍后重试。',
|
|
10
|
+
NETWORK: '无法连接服务,请检查网络和 API 是否已启动。',
|
|
11
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
// 浏览器请求保持同源,让 cookie 会话和 CSRF 验证与生产环境使用同一种方式。
|
|
4
|
+
// Windows 的 Docker/Hyper-V 可能保留 5173,允许从项目 .env 显式选择可用端口。
|
|
5
|
+
const api = `http://127.0.0.1:${process.env.PORT ?? '3000'}`;
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
// 本地 --framework-path 会把 SDK 链接到另一个 node_modules。
|
|
8
|
+
// hooks 与页面必须共用同一个 React/Query 实例,否则构建成功也会在登录后白屏。
|
|
9
|
+
resolve: { dedupe: ['react', 'react-dom', '@tanstack/react-query'] },
|
|
10
|
+
server: {
|
|
11
|
+
port: Number(process.env.CAGE_WEB_PORT ?? 5173),
|
|
12
|
+
strictPort: true,
|
|
13
|
+
proxy: {
|
|
14
|
+
'/api': api,
|
|
15
|
+
'/auth': api,
|
|
16
|
+
'/admin': api,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domain": "packages/domain/src/index.ts",
|
|
3
|
+
"contracts": "packages/contracts/src",
|
|
4
|
+
"structure": "modular",
|
|
5
|
+
"typecheck": ["packages/domain", "packages/contracts", "apps/api", "apps/web"],
|
|
6
|
+
"graph": {
|
|
7
|
+
"title": "业务应用图谱",
|
|
8
|
+
"labels": {
|
|
9
|
+
"aggregate:Dept": "部门",
|
|
10
|
+
"aggregate:User": "用户",
|
|
11
|
+
"aggregate:Role": "角色"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- 迁移草稿:由 cage gen 生成,人审后提交;已发布的迁移不要修改
|
|
2
|
+
-- 破坏性变更按「先扩展再收缩」分多次发布
|
|
3
|
+
|
|
4
|
+
-- 新表:来自聚合 Dept
|
|
5
|
+
CREATE TABLE IF NOT EXISTS "sys"."dept" (
|
|
6
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
"tenant_id" uuid NOT NULL,
|
|
8
|
+
"name" text NOT NULL,
|
|
9
|
+
"code" text,
|
|
10
|
+
"parent_id" uuid REFERENCES "sys"."dept"(id),
|
|
11
|
+
"ancestors" text NOT NULL,
|
|
12
|
+
"leader_id" uuid,
|
|
13
|
+
"status" text NOT NULL,
|
|
14
|
+
"version" integer NOT NULL DEFAULT 1,
|
|
15
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
16
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
17
|
+
CONSTRAINT "dept_status_check" CHECK (status IN ('active', 'archived'))
|
|
18
|
+
);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS "dept_status_idx" ON "sys"."dept" ("tenant_id", "status");
|
|
20
|
+
CREATE INDEX IF NOT EXISTS "dept_parent_id_idx" ON "sys"."dept" ("parent_id");
|
|
21
|
+
|
|
22
|
+
-- 新表:来自聚合 Role
|
|
23
|
+
CREATE TABLE IF NOT EXISTS "sys"."role" (
|
|
24
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
25
|
+
"tenant_id" uuid NOT NULL,
|
|
26
|
+
"code" text NOT NULL,
|
|
27
|
+
"name" text NOT NULL,
|
|
28
|
+
"capabilities" jsonb NOT NULL,
|
|
29
|
+
"scopes" jsonb NOT NULL,
|
|
30
|
+
"status" text NOT NULL,
|
|
31
|
+
"version" integer NOT NULL DEFAULT 1,
|
|
32
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
33
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
34
|
+
CONSTRAINT "role_status_check" CHECK (status IN ('active', 'archived'))
|
|
35
|
+
);
|
|
36
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "role_code_uq" ON "sys"."role" (tenant_id, "code");
|
|
37
|
+
CREATE INDEX IF NOT EXISTS "role_status_idx" ON "sys"."role" ("tenant_id", "status");
|
|
38
|
+
|
|
39
|
+
-- 新表:来自聚合 User
|
|
40
|
+
CREATE TABLE IF NOT EXISTS "sys"."user" (
|
|
41
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
42
|
+
"tenant_id" uuid NOT NULL,
|
|
43
|
+
"username" text NOT NULL,
|
|
44
|
+
"name" text NOT NULL,
|
|
45
|
+
"dept_id" uuid NOT NULL REFERENCES "sys"."dept"(id),
|
|
46
|
+
"role_ids" jsonb NOT NULL,
|
|
47
|
+
"phone" text,
|
|
48
|
+
"email" text,
|
|
49
|
+
"sso_subject" text,
|
|
50
|
+
"password_hash" text,
|
|
51
|
+
"status" text NOT NULL,
|
|
52
|
+
"version" integer NOT NULL DEFAULT 1,
|
|
53
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
54
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
55
|
+
CONSTRAINT "user_status_check" CHECK (status IN ('active', 'disabled'))
|
|
56
|
+
);
|
|
57
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "user_username_uq" ON "sys"."user" (tenant_id, "username");
|
|
58
|
+
CREATE INDEX IF NOT EXISTS "user_tenant_dept_id_idx" ON "sys"."user" ("tenant_id", "dept_id");
|
|
59
|
+
CREATE INDEX IF NOT EXISTS "user_status_idx" ON "sys"."user" ("tenant_id", "status");
|
|
60
|
+
|
|
61
|
+
/* cage:schema
|
|
62
|
+
{"version":1,"tables":[{"schema":"sys","name":"dept","aggregate":"Dept","columns":[{"name":"id","type":"uuid","notNull":true},{"name":"tenant_id","type":"uuid","notNull":true},{"name":"name","type":"text","notNull":true},{"name":"code","type":"text","notNull":false},{"name":"parent_id","type":"uuid","notNull":false,"references":"sys.dept"},{"name":"ancestors","type":"text","notNull":true},{"name":"leader_id","type":"uuid","notNull":false},{"name":"status","type":"text","notNull":true},{"name":"version","type":"integer","notNull":true},{"name":"created_at","type":"timestamptz","notNull":true},{"name":"updated_at","type":"timestamptz","notNull":true}],"statusValues":["active","archived"],"indexes":[{"name":"dept_status_idx","columns":["tenant_id","status"]},{"name":"dept_parent_id_idx","columns":["parent_id"]}]},{"schema":"sys","name":"role","aggregate":"Role","columns":[{"name":"id","type":"uuid","notNull":true},{"name":"tenant_id","type":"uuid","notNull":true},{"name":"code","type":"text","notNull":true,"unique":true},{"name":"name","type":"text","notNull":true},{"name":"capabilities","type":"jsonb","notNull":true},{"name":"scopes","type":"jsonb","notNull":true},{"name":"status","type":"text","notNull":true},{"name":"version","type":"integer","notNull":true},{"name":"created_at","type":"timestamptz","notNull":true},{"name":"updated_at","type":"timestamptz","notNull":true}],"statusValues":["active","archived"],"indexes":[{"name":"role_status_idx","columns":["tenant_id","status"]}]},{"schema":"sys","name":"user","aggregate":"User","columns":[{"name":"id","type":"uuid","notNull":true},{"name":"tenant_id","type":"uuid","notNull":true},{"name":"username","type":"text","notNull":true,"unique":true},{"name":"name","type":"text","notNull":true},{"name":"dept_id","type":"uuid","notNull":true,"references":"sys.dept"},{"name":"role_ids","type":"jsonb","notNull":true},{"name":"phone","type":"text","notNull":false},{"name":"email","type":"text","notNull":false},{"name":"sso_subject","type":"text","notNull":false},{"name":"password_hash","type":"text","notNull":false},{"name":"status","type":"text","notNull":true},{"name":"version","type":"integer","notNull":true},{"name":"created_at","type":"timestamptz","notNull":true},{"name":"updated_at","type":"timestamptz","notNull":true}],"statusValues":["active","disabled"],"indexes":[{"name":"user_tenant_dept_id_idx","columns":["tenant_id","dept_id"]},{"name":"user_status_idx","columns":["tenant_id","status"]}]}]}
|
|
63
|
+
*/
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 业务开发指南(给 Codex 等编程工具)
|
|
2
|
+
|
|
3
|
+
这是 `create-cage-app` 产物自带的业务开发资料。目标是让 Codex 等编程工具只读当前项目,就能增加业务对象、操作、审批、报表和页面。先读根目录 `AGENTS.md`,再按任务定位本页资料;无需另行克隆 Cage 框架仓库。
|
|
4
|
+
|
|
5
|
+
## 先认识当前应用
|
|
6
|
+
|
|
7
|
+
| 目录 | 开发业务时放什么 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `packages/domain/src/modules/<业务>` | 按业务集中聚合、命令、事件、审批、查询与任务;跨模块反应放 workflows,外部协议放 integrations |
|
|
10
|
+
| `packages/contracts/src/aggregates`、`queries` | 按聚合目录生成 API 与类型;通过根 @app/contracts 使用,通过 gen 更新 |
|
|
11
|
+
| `apps/api/src` | API 与 worker 的薄启动入口;普通业务不在这里写路由 |
|
|
12
|
+
| `apps/web/src/app`、`modules`、`shared` | 应用组合 / 业务页面与交互 / 无具体业务归属的共用代码 |
|
|
13
|
+
| `db/migrations` | 生成后审查的迁移;更新已有数据库中的表 |
|
|
14
|
+
| `.env` / `.env.example` | 本机配置 / 不含真实凭证的配置说明 |
|
|
15
|
+
| `docs/ai`、`docs/errors` | 业务开发方法与错误排查 |
|
|
16
|
+
|
|
17
|
+
下文路径均相对**应用根目录**,即生成项目的 `package.json` 所在目录。框架包使用 `@yss123/cage-*`,作为依赖安装;当前项目不应复制或重新实现这些包。框架维护者在源码仓库读本页时,应用根目录为 `examples/purchase-admin`。
|
|
18
|
+
|
|
19
|
+
创建时可选 `blank`(空白业务项目)或 `purchase`(采购示例项目)。空白项目只有组织基础模型,新增客户业务写入根目录的 `packages/domain/src`;采购参考源码放在 `docs/examples/purchase-admin`,不参与注册、编译或建表。阅读本指南中的采购路径时,空白项目在该参考目录下查找,采购项目直接在应用根目录查找。先读本项目 AGENTS.md 的模板说明,不能把参考代码误当成已运行的业务。
|
|
20
|
+
|
|
21
|
+
## 推荐阅读顺序
|
|
22
|
+
|
|
23
|
+
| 顺序 | 资料 | 读完应能回答 |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| 1 | [架构与执行模型](architecture.md) | 聚合是什么?为什么写入必须走命令?数据库由谁连接? |
|
|
26
|
+
| 2 | [工程目录与代码组织](project-structure.md) | 新业务放哪里?页面如何拆分?哪些依赖会被门禁阻止? |
|
|
27
|
+
| 3 | [原语与最小业务](primitives.md) | 如何新增字段、CRUD 命令、读依赖、事件和查询? |
|
|
28
|
+
| 开发前 | [本体查询与 AI 上下文](ontology-context.md) | 按需求查哪些代码?为什么关联?候选、证据与子图边界怎么判断? |
|
|
29
|
+
| 按需 | [对象关系](relations.md) | 如何在 fields 中声明一对一、一对多、多对多,修改关联并分页读取? |
|
|
30
|
+
| 4 | [标准采购范例导读](purchase-example.md) | 一次提交如何进入审批、锁库存、推 ERP、释放资源? |
|
|
31
|
+
| 5 | [开发步骤](workflow.md) | 改哪个文件?运行哪些命令?检查结果在哪里? |
|
|
32
|
+
| 6 | [业务任务配方](recipes.md) | 如何从采购演示换成自己的业务?常见需求如何交给 AI? |
|
|
33
|
+
| 7 | [业务页导入导出](transfers.md) | 如何提交任务、准备 CSV、查询状态、下载和展示报告? |
|
|
34
|
+
| 8 | [排错方法](troubleshooting.md)、[错误码册](../errors/README.md) | 如何区分配置、权限、业务失败和异步死信? |
|
|
35
|
+
|
|
36
|
+
第一次先读架构、目录规范和原语,再沿范例读代码。接到业务需求后先运行 `pnpm exec cage context "需求关键词"`,确认候选入口,再按源码位置阅读对应实现。
|
|
37
|
+
|
|
38
|
+
## 按任务找入口
|
|
39
|
+
|
|
40
|
+
| 用户需求 | 优先修改 | 需要一起考虑 |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| 增加业务对象、字段 | `packages/domain/src/modules/<业务>` | 模块公开入口、范围字段、不变量、契约、迁移、角色授权、图谱中文名 |
|
|
43
|
+
| 增加对象关联 | `fields` 的 ref / hasMany / manyToMany;见[关系指南](relations.md) | 归属命令、双侧权限与范围、目标分页、迁移;纯关联不手写中间表聚合 |
|
|
44
|
+
| 增加操作按钮 | 领域命令 + `apps/web/src/modules/<业务>` | 状态迁移、调用身份、错误展示、提交幂等键 |
|
|
45
|
+
| 增加报表 | 所属领域模块 `queries.ts` | `reads`、`safe.*`、参数化、调用人 read 权限 |
|
|
46
|
+
| 修改审批顺序/条件/选人 | 所属领域模块 `approvals.ts` | `routable`、角色/负责人数据、结论命令约束 |
|
|
47
|
+
| 取消后释放占用 | `workflows/<相关业务>.ts` + 领域事件/命令 | 所有离开持有状态的路径、同事务/异步选择 |
|
|
48
|
+
| 接 ERP 或其他系统 | `integrations/<系统名>.ts` | schema、密钥名、白名单、幂等、回调验签、重试 |
|
|
49
|
+
| 业务页导入/导出 | 业务前端调用已有接口 | 任务状态、worker、权限、导入目标命令;不固定到系统管理页 |
|
|
50
|
+
| 新业务没出现在图或 API | domain 统一入口 | 顶层 `export const`、导出名唯一、入口 re-export |
|
|
51
|
+
| 框架无法表达业务 | 先核对公开导出与范例 | 说明能力缺口;不要编造 API 或把业务分支塞进内核 |
|
|
52
|
+
|
|
53
|
+
## 三份协作材料各管什么
|
|
54
|
+
|
|
55
|
+
- **AGENTS.md** 是工作入口:必守边界、目录、顺序和验证要求。`<!-- cage:begin ... -->` 到 `<!-- cage:end -->` 为框架托管区,`cage sync` 更新它;项目自己的规则放在外面。
|
|
56
|
+
- **标准范例** 是可运行证据:采购模板包含完整运行链路,空白模板保留离线参考源码。按需学习其中模式,客户业务仍写在本项目自己的 domain 和页面中。
|
|
57
|
+
- **错误码册** 是诊断索引:按真实错误码查位置、触发原因、修复步骤和正反例;不要靠放开权限或关闭门禁“修好”报错。
|
|
58
|
+
|
|
59
|
+
`docs/ai` 与 `docs/errors` 已放入分发模板,创建项目时一起复制,可离线阅读。框架仓库中的标准范例使用根目录的规范文档,资料位置由应用 AGENTS.md 指明。
|
|
60
|
+
|
|
61
|
+
## 当前实现边界
|
|
62
|
+
|
|
63
|
+
以下区分可避免 agent 把方案中的愿景写成不存在的功能。
|
|
64
|
+
|
|
65
|
+
| 已有能力 | 使用边界 |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| 真实 PostgreSQL 连接、分账号、表结构迁移 | 连接已有数据库;`init` 不建库;不会自动识别并接管任意历史表 |
|
|
68
|
+
| 聚合/命令、能力与范围、掩码、审计、outbox、worker | handler 不做数据库/网络 IO;生产角色不会自动拿到新能力 |
|
|
69
|
+
| fields 中的 ref / hasMany / manyToMany | hasMany 为只读反查;manyToMany 自动中间表并随主对象事务写入,公开读取独立分页;双向集合不会自动互为镜像 |
|
|
70
|
+
| 本体抽取、中文检索/节点/路径/AI 上下文、图规则、图谱、生成、影响分析与门禁 | 上下文注明证据、源码和覆盖边界;名称与测试匹配是候选线索,不能证明任意 JS 正确;跳过用例仍需补足 |
|
|
71
|
+
| 代码审批路由与适配接口 | 顺序步骤、条件步骤、步骤内任一/全部审批;没有通用可视化流程设计器、任意 JS 选人、转签/加签 API |
|
|
72
|
+
| 连接器 fake、出站、入站验签、同步记录 | fake 不等于真实 ERP 联调,也不等于完整请求录制/回放平台 |
|
|
73
|
+
| 异步 CSV 导入/导出接口与客户端任务查询 | 界面由业务项目决定;导出结果不是可直接回导的命令输入模板 |
|
|
74
|
+
| 组织模型、系统管理界面 | 暂无移动部门(改上级)的完整支持、菜单配置页 |
|
|
75
|
+
| 库存锁采购范例 | 演示资源生命周期;不是仓库级并发库存扣减、退货或 ERP 撤销补偿系统 |
|
|
76
|
+
|
|
77
|
+
文档与实现冲突时,以当前代码和检查结果为依据,指出冲突并修正文档;不要默默扩展公开 API。规划、代码存在、构建通过、真实联调通过是不同状态,交付时分别说明。
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# 架构与执行模型
|
|
2
|
+
|
|
3
|
+
[返回学习入口](README.md) · [下一篇:原语](primitives.md)
|
|
4
|
+
|
|
5
|
+
## 业务声明是一份可执行规格
|
|
6
|
+
|
|
7
|
+
Cage 把业务字段、状态、写操作、读依赖和跨对象关系写成 TypeScript 声明。声明函数返回描述对象,本身不连接数据库;API 和 worker 启动时从 domain 入口构建注册表,CLI 则结合 TypeScript 源码位置抽取本体图。
|
|
8
|
+
|
|
9
|
+
同一份声明产生以下结果:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
domain/index.ts 导出的声明
|
|
13
|
+
├─ 注册表 → 能力目录 → HTTP 路由 → 内核与读侧
|
|
14
|
+
├─ 本体图 → 图规则 / 中文图谱 / 影响分析 / 派生测试
|
|
15
|
+
└─ 生成器 → 前端 contracts / 状态图 / SQL / 迁移草稿
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
因此新增业务操作应先写领域命令,不再为该操作手写路由、权限拦截器、审计 SQL 和前端请求封装。新增声明还必须从 domain 入口导出;仅创建文件不会被自动注册。
|
|
19
|
+
|
|
20
|
+
## 聚合、命令、事件分别是什么
|
|
21
|
+
|
|
22
|
+
用“采购单”举例:
|
|
23
|
+
|
|
24
|
+
| 概念 | 例子 | 它负责的事 |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| 聚合 aggregate | `PurchaseOrder` | 把金额、明细、部门、状态和不变量放在同一业务边界内 |
|
|
27
|
+
| 命令 command | `PurchaseOrder.submit` | 请求把草稿提交审批;执行时可拒绝,不是直接改字段 |
|
|
28
|
+
| 事件 event | `OrderSubmitted` | 表示提交已经成功发生,供审批等后续处理消费 |
|
|
29
|
+
| 反应 reaction | `lockOnApprove` | 收到已批准事件后调用库存锁命令 |
|
|
30
|
+
| 约束 constraint | `sod.notSameAs('createdBy')` | 执行前判断当前主体是否能进行这个业务动作 |
|
|
31
|
+
| 不变量 invariant | 金额必须大于零 | 执行后的对象在任何允许状态下都必须满足的条件 |
|
|
32
|
+
|
|
33
|
+
聚合通常对应 `core.purchase_order` 一张业务主表。系统列包括 `id / version / status / createdAt / updatedAt`,数据库还维护租户列;业务不要重复定义它们。`createdBy` 是业务字段,声明为 `ref('User')` 后内核会在新建时填入当前用户,并可作为本人范围与职责分离依据。
|
|
34
|
+
|
|
35
|
+
一个采购单可以有明细列表,也可以引用库存等其他聚合。跨聚合写入要调用对方的命令,通过反应表达关系,不能拿到对方数据库表直接更新。
|
|
36
|
+
|
|
37
|
+
对象关联统一写在 fields:ref 为本表外键,hasMany 依据目标外键反查,manyToMany 自动生成中间表。多对多链接属于来源对象的命令事务,但不授权修改目标内容;公开关联通过两侧安全视图分页读取。完整模式见[对象关系](relations.md)。
|
|
38
|
+
|
|
39
|
+
## 一次写入的完整路径
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
浏览器 contracts → HTTP 会话与 CSRF → Kernel.execute
|
|
43
|
+
→ 校验输入、上下文、调用身份与能力
|
|
44
|
+
→ 幂等检查
|
|
45
|
+
→ 按范围加载并锁定记录,检查状态与版本
|
|
46
|
+
→ 硬约束(职责分离、额度、二次认证等)
|
|
47
|
+
→ 绑定 reads,只运行 handler 的业务计算
|
|
48
|
+
→ 合并结果,内核设置目标状态,校验字段及不变量
|
|
49
|
+
→ 写记录、版本、审计和 outbox,执行同事务反应
|
|
50
|
+
→ 提交事务 → 返回结果
|
|
51
|
+
worker → 消费 outbox → 异步反应 / 审批 / 连接器
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- `handler(draft, input, deps, ctx)` 描述变化,可读显式声明的依赖,不直接写数据库、发 HTTP 或读写文件。
|
|
55
|
+
- 业务拒绝返回 `fail('业务码', detail?)`。不要抛普通异常来表示可预期的业务拒绝,也不要吞异常后返回成功。
|
|
56
|
+
- `from/to` 决定生命周期。handler 不能靠写 `status` 绕过状态机;已有记录的 `to: null` 明确保留当前状态,新建必须给真实目标状态。
|
|
57
|
+
- 乐观版本冲突用 `CONFLICT` 告知客户端重新加载;幂等用于重复投递同一个请求,二者解决不同问题。
|
|
58
|
+
- SDK 每次调用默认产生新的幂等键,同一次调用内部重试复用。业务要让双击或用户手动重试视为同一次提交时,需要保留并复用该次操作的键,不能假设两次独立调用自动合并。
|
|
59
|
+
|
|
60
|
+
## 同事务与异步的选择
|
|
61
|
+
|
|
62
|
+
| 声明 | 适合用途 | 失败影响 |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| `reaction(..., { tx: 'same' })` | 主动作与资源登记必须同时成功,例如批准与建库存锁 | 反应失败,主命令和审计/outbox 一起回滚 |
|
|
65
|
+
| 默认 `tx: 'outbox'` | 可稍后完成的后续动作,例如取消后的释放 | 主动作已提交;worker 重试,耗尽或永久错误进入死信 |
|
|
66
|
+
| `outbound(...)` | ERP 等事务外的网络写入 | 无法回滚远端;必须设计幂等与补偿 |
|
|
67
|
+
|
|
68
|
+
同事务链不能无限递归,外部 IO 不能放进同事务 handler。异步消息按聚合顺序投递;某条进入死信后,后续同一聚合消息可能被阻塞。先修正原因,再通过死信接口重放或经业务判断丢弃,不直接修改 outbox/业务表。
|
|
69
|
+
|
|
70
|
+
资源标签 `acquires: 'inventory.lock'`、`releases: 'inventory.lock'` 为图规则提供证据。它们不会自动加锁或释放,真正效果来自 `acquireLock/releaseLock` 命令。
|
|
71
|
+
|
|
72
|
+
## 权限是几层判断
|
|
73
|
+
|
|
74
|
+
| 层 | 例子 | 说明 |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| 登录与租户 | 当前用户与租户上下文 | Cookie 会话、OIDC 等由 HTTP 层装配 |
|
|
77
|
+
| 调用身份 | `user/process/job/external` | `process` 命令不给浏览器生成直接写接口;这不是角色名 |
|
|
78
|
+
| 能力点 | `PurchaseOrder.submit`、`PurchaseOrder.read` | 代码声明能力目录,管理员在目录范围内授权 |
|
|
79
|
+
| 数据范围 | 本人、本部门、部门及下级、指定部门、全部 | 决定能触及哪些记录,越范围详情通常表现为 404 |
|
|
80
|
+
| 业务硬约束 | 不是提单人、额度不超过 ceiling | 即使被选为审批人也必须通过 |
|
|
81
|
+
| 明文能力 | `PurchaseOrder.unmask.phone` | 没有该能力时,安全读侧对电话掩码 |
|
|
82
|
+
|
|
83
|
+
`scope.deptSubtree('deptId')` 描述聚合的部门字段和建议范围;**实际范围取决于角色授权数据**。`scope.none()` 表示没有部门/创建人范围字段,仍然需要能力和适当的 `all` 范围授权,不能理解成“任何人能读”。多角色范围合并为并集,缺少显式范围时默认本人范围,不是全部。
|
|
84
|
+
|
|
85
|
+
`useCan()`、`can()` 只决定按钮呈现;前端隐藏按钮不能代替后端授权。新增命令不会自动授给已有生产角色,角色分配和额度调整也受防提权约束。
|
|
86
|
+
|
|
87
|
+
## 数据库连接属于框架核心能力
|
|
88
|
+
|
|
89
|
+
项目提供连接配置,框架管理连接池、事务、上下文变量和 SQL。普通业务不需要自己编写 `pg.Pool`、表仓储或连接释放逻辑。
|
|
90
|
+
|
|
91
|
+
| 配置/对象 | 职责 | 何时使用 |
|
|
92
|
+
| --- | --- | --- |
|
|
93
|
+
| `CAGE_ADMIN_DATABASE_URL` | 已有数据库的管理员连接 | 首次 `cage init` 准备账号;成功后从本地配置移除 |
|
|
94
|
+
| `CAGE_APP_DATABASE_URL` / `cage_app` | API 与 worker 业务写入、系统处理 | 日常运行 |
|
|
95
|
+
| `CAGE_READ_DATABASE_URL` / `cage_read` | 只能查询安全层 | 列表、详情、自定义查询、导出 |
|
|
96
|
+
| `CAGE_MIGRATE_DATABASE_URL` / `cage_migrate` | 结构变更及安全层重建 | 显式 `cage migrate` |
|
|
97
|
+
| `cage_view_owner` | 不可登录的视图所有者 | 安全视图内部使用,无密码配置 |
|
|
98
|
+
|
|
99
|
+
APP、READ、MIGRATE 指向**同一个已经存在的数据库**,用不同账号隔离能力。PostgreSQL 角色属于集群,不能因另一个项目初始化而重置已有角色密码。
|
|
100
|
+
|
|
101
|
+
| 命令 | 改什么 | 不负责什么 |
|
|
102
|
+
| --- | --- | --- |
|
|
103
|
+
| `init` | 角色、schema、授权、随机凭证及 `.env` | 安装 PG、启动 Docker、创建数据库、创建业务表 |
|
|
104
|
+
| `gen` | 本地 contracts、SQL、状态图、迁移草稿 | 应用数据库迁移 |
|
|
105
|
+
| `migrate` | 已有库的表、索引、安全视图、迁移历史 | 每次启动新建数据库 |
|
|
106
|
+
| `dev` | 连接已有库,启动 API、worker、Web,监听声明重新生成 | 自动迁移或内嵌临时数据库兜底 |
|
|
107
|
+
|
|
108
|
+
读路径使用 `safe.*`,业务表位于 `core.*`,组织和运行数据位于 `sys.*`。安全视图结合会话上下文执行范围过滤与掩码;手写报表也必须走这层。连接现有库不意味着自动把历史任意表变成 Cage 聚合,需要专门的映射与迁移方案。
|
|
109
|
+
|
|
110
|
+
## 包之间如何依赖
|
|
111
|
+
|
|
112
|
+
业务 domain 依赖 kernel 的声明 API,按需要引用 approval/connectors 声明;API 与 worker 入口依赖 domain 并装配框架。contracts 由 domain 生成,Web 依赖 contracts 和 client。domain 不能反过来依赖 contracts,否则产生生成循环。
|
|
113
|
+
|
|
114
|
+
框架的 `testkit` 提供真实 PostgreSQL 测试环境与 handler 测试工具;`lint` 检查依赖和危险写法;CLI 负责分析、生成和汇总门禁。生产程序不需要携带整个框架仓库。
|
|
115
|
+
|
|
116
|
+
## 本体图为什么有这些连线
|
|
117
|
+
|
|
118
|
+
图谱抽取命令状态迁移与事件、反应调用、审批 start/cancelOn、约束/路由字段、查询读依赖和外部映射;另以虚线标记按标识推导的所属聚合。关系解释区分显式声明、规则推导与文本匹配,箭头要按各自含义阅读。开发前可用[本体上下文工具](ontology-context.md)检索相关业务与源码。
|
|
119
|
+
|
|
120
|
+
`cage analyze` 将图写到 `.cage/ontology.json`;`cage graph` 提供浏览器工作台。中文显示名写在 `cage.config.json` 的 `graph.labels`,例如 `"command:PurchaseOrder.submit": "提交审批"`。显示名不更改能力标识、源码符号或表名。
|
|
121
|
+
|
|
122
|
+
图规则能检查“离开持有状态是否声明了释放”等结构问题,无法证明 `map` 的任意分支或 handler 计算一定正确。因此重要的资源释放条件、权限拒绝、额度边界仍需对应业务回归用例。
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# 用本体图辅助 AI 开发业务
|
|
2
|
+
|
|
3
|
+
[返回学习入口](README.md) · [开发步骤](workflow.md)
|
|
4
|
+
|
|
5
|
+
本页命令在**应用根目录**运行,使用项目安装的 CLI。工具直接分析当前注册的 domain,无需启动 API、worker 或数据库。不要把 Web 截图作为 AI 理解业务的唯一材料:优先取得结构化上下文,再按源码位置阅读实现。
|
|
6
|
+
|
|
7
|
+
## 开发一项需求的入口
|
|
8
|
+
|
|
9
|
+
以采购模板为例:
|
|
10
|
+
|
|
11
|
+
```powershell
|
|
12
|
+
# 根据中文需求取得一份可阅读的上下文,默认 Markdown。
|
|
13
|
+
pnpm exec cage context "修改采购单取消逻辑"
|
|
14
|
+
# 用完整节点身份缩小入口;保存 JSON 供编程工具读取。
|
|
15
|
+
pnpm exec cage context command:PurchaseOrder.cancel --format json --out .cage/cancel-context.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
报告提供中文名称、稳定 key、候选命中依据、相关业务事实、连接原因与用途、源码位置、契约、前端引用和测试候选、迁移及授权审查提示。没有执行其中的命令或测试,也没有写入数据库。
|
|
19
|
+
|
|
20
|
+
中文检索按名称、description、标识和所属对象匹配,支持相邻中文词片段;它没有调用语言模型,不保证理解任意自然语言需求。比如“采购单取消”和“取消采购单”可以匹配,但业务同义词、否定句、复杂规则仍需要 AI 阅读源码并结合用户需求确认。
|
|
21
|
+
|
|
22
|
+
- `selection.mode=exact`:完整 key、唯一 ID 或唯一中文全称定位到一个入口。
|
|
23
|
+
- `selection.mode=keyword-candidates`:选取得分接近的最多三个入口生成子图,同时返回其他候选和命中原因。先确认入口符合需求;可复制候选 key 再运行一次。
|
|
24
|
+
- 没有命中不表示框架不支持该业务。尝试较短关键词或代码标识。空白模板只注册组织模型,`docs/examples/purchase-admin` 是参考资料,不会被提取为当前项目的采购业务。
|
|
25
|
+
|
|
26
|
+
## 四个命令怎样配合
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
# 1. 按中文或英文找业务;--kind 可限定节点类型。
|
|
30
|
+
pnpm exec cage graph search "取消" --kind command --limit 8
|
|
31
|
+
# 2. 精确查看节点属性、所有直接关联及声明位置。
|
|
32
|
+
pnpm exec cage graph inspect command:PurchaseOrder.cancel
|
|
33
|
+
# 3. 查看两个节点之间的最短关系路径。
|
|
34
|
+
pnpm exec cage graph path command:PurchaseOrder.cancel command:InventoryLock.release
|
|
35
|
+
# 4. 组织为本次开发所需的上下文。
|
|
36
|
+
pnpm exec cage context command:PurchaseOrder.cancel --depth 3 --limit 40
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
这些查询均支持 `--format md|json` 和 `--out <文件>`,默认 Markdown。输出路径相对应用根目录;可通过 `--root <目录>` 指定另一个应用。`cage graph` 不带子命令时仍启动 Web 工作台。
|
|
40
|
+
|
|
41
|
+
| 查询 | 结果与边界 |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `graph search` | 返回排序候选、score、matches 和源码位置;默认最多 10 项,truncated 表示候选被截断 |
|
|
44
|
+
| `graph inspect` | 只接受完整 key、唯一 ID 或唯一中文全称;有歧义或只有模糊匹配时返回候选,请使用完整 key 重试 |
|
|
45
|
+
| `graph path` | 默认沿箭头,深度最多 6;用 `--direction both` 探索双向依赖,每一步明确标出逆向遍历 |
|
|
46
|
+
| `context` | 默认深度 3、最多 40 个节点;附带的表、字段和状态不继续展开,避免扩大为整张系统图 |
|
|
47
|
+
|
|
48
|
+
节点身份由类型与 ID 共同构成,例如 `command:PurchaseOrder.cancel`。命令、状态、能力点可以同名,不能只用 ID 合并节点。审批路由的 ID 自带 `route:`,因此完整 key 可能是 `route:route:po-approval`;直接复制工具返回的 key。
|
|
49
|
+
|
|
50
|
+
路径展示的是**关系链**。读取箭头指向数据来源;双向遍历不改变声明方向。归属虚线不会参与路径搜索,避免经同一所属对象制造两个命令之间的调用关系。没有在深度内找到路径,不代表任意代码之间绝无联系;可提高 `--depth`,或使用双向探索。状态迁移路径会保留 `via` 命令。
|
|
51
|
+
|
|
52
|
+
## 采购单取消的实际阅读方式
|
|
53
|
+
|
|
54
|
+
工具可以追踪以下声明:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
command:PurchaseOrder.cancel
|
|
58
|
+
→ event:OrderCancelled
|
|
59
|
+
→ reaction:releaseOnCancel
|
|
60
|
+
→ command:InventoryLock.release
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
同时会看到 `OrderCancelled → poApproval` 的 `cancels` 关系,依据是审批绑定的 `cancelOn`。这条关系负责取消审批;释放库存锁由另一条业务反应完成,两者分别检查。
|
|
64
|
+
|
|
65
|
+
接着阅读报告指向的 `workflows/purchase-inventory.ts`:`releaseOnCancel.map` 仅在事件 `previousStatus === 'approved'` 时返回释放输入,其余返回 null。图能解释订阅、目标和资源标签,不能仅凭存在一条连线就判定每次取消都会释放资源。
|
|
66
|
+
|
|
67
|
+
源码位置有两个精度:
|
|
68
|
+
|
|
69
|
+
- `declaration`:定位到顶层声明的文件与行号。
|
|
70
|
+
- `aggregate`:字段、状态等只定位到所属聚合声明;继续在该声明内查找具体成员。
|
|
71
|
+
|
|
72
|
+
`source=null` 表示当前项目静态索引没有位置,常见于来自框架依赖的组织模型;应查依赖的公开 API 和本地指南。报告不会伪造字段的精确行号或复制依赖内部实现。
|
|
73
|
+
|
|
74
|
+
## 判断证据强度和覆盖范围
|
|
75
|
+
|
|
76
|
+
每条关系都带 `why`、`purpose` 和 `evidence`:
|
|
77
|
+
|
|
78
|
+
| evidence.basis | 可以据此判断什么 |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| `declared` | 来自 reads、emits、reaction、cancelOn、约束字段等显式声明;仍需阅读执行条件 |
|
|
81
|
+
| `inferred` | 从标识推导归属,或由默认事件映射、出站同名字段规则建立关联;核对映射实现 |
|
|
82
|
+
| `text-match` | 从 SQL/build 文本匹配字段名;可能命中注释或同名内容,只作为查询依赖线索 |
|
|
83
|
+
|
|
84
|
+
前端候选按聚合/查询代码名称匹配,项目测试候选按源码标识匹配,均不是完整依赖分析。派生测试按 subject 选择,不意味着这些用例一定能构造有效输入或已经运行成功。
|
|
85
|
+
|
|
86
|
+
每份报告都带 `extractedAt`、`graphHash`、`freshness`、当前 `findings` 和使用边界。CLI 每次独立进程重新抽取,不读取旧图缓存;Web 复制使用当前图谱快照,明确标为 `displayed-snapshot`,改代码后先点“重新抽取”。`graph.labels` 的显示覆盖独立保存,不改变本体节点 ID 和语义哈希;声明内的 description 仍可能影响语义比较,特别是字段口径说明。
|
|
87
|
+
|
|
88
|
+
`coverage.truncated` 表示节点上限造成遗漏;`depthBoundary` 指出因深度限制未继续展开的节点。扩大 `--limit` / `--depth` 或改用更精确入口;不能把未出现在子图中的对象当成没有影响。测试、前端候选还分别报告自己的截断情况。
|
|
89
|
+
|
|
90
|
+
图规则有错误时,只要仍能抽取出图,就输出报告和问题,CLI 返回非零退出码。静态检查阻止 domain 求值时,先按诊断修复,再重新请求上下文。未命中、inspect 歧义、深度内无路径也返回非零;不要因为已经生成文件就当作成功。
|
|
91
|
+
|
|
92
|
+
## 修改前后形成闭环
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
# 开发前:先取得上下文、阅读实际实现,再保存独立基线。
|
|
96
|
+
pnpm exec cage context "采购单取消"
|
|
97
|
+
pnpm exec cage analyze
|
|
98
|
+
Copy-Item .cage/ontology.json .cage/before-change.json
|
|
99
|
+
# 在源码修改业务声明和实现……
|
|
100
|
+
pnpm exec cage check
|
|
101
|
+
pnpm gen
|
|
102
|
+
pnpm exec cage impact --base-file .cage/before-change.json
|
|
103
|
+
# 按影响和实际风险选择必要测试,审查迁移与管理员授权。
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
查询也会更新 `.cage/ontology.json`。基线必须在改代码前另存,保留到验收结束,不能把每次被覆盖的当前图当作旧图。`context` 用于开发前定位,`impact` 用于修改后比较;二者都不能替代业务验收。
|
|
107
|
+
|
|
108
|
+
可直接交给编程工具的要求:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
先读 AGENTS.md 和 docs/ai/README.md。
|
|
112
|
+
需求:修改……
|
|
113
|
+
先运行 cage context 查询需求相关业务,再用 graph inspect/path 消除入口和关系歧义。
|
|
114
|
+
按报告的源码位置阅读条件与实现;说明选中的业务入口、影响范围和图的覆盖边界。
|
|
115
|
+
修改前另存本体图基线,修改后 check、gen、impact,按风险运行相关验证。
|
|
116
|
+
不要只凭名称、连线或测试候选判断需求已完成。
|
|
117
|
+
```
|