@yss123/cage-cli 0.0.0-stage → 0.1.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 +18 -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 +26 -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 +47 -0
- package/dist/config.js.map +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +47 -0
- package/dist/create.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/database.js +70 -0
- package/dist/database.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 +155 -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 +167 -0
- package/dist/gen/contracts.js.map +1 -0
- package/dist/gen/index.d.ts +19 -0
- package/dist/gen/index.js +137 -0
- package/dist/gen/index.js.map +1 -0
- package/dist/gen/zod-code.d.ts +7 -0
- package/dist/gen/zod-code.js +161 -0
- package/dist/gen/zod-code.js.map +1 -0
- package/dist/graph-snapshot.d.ts +13 -0
- package/dist/graph-snapshot.js +46 -0
- package/dist/graph-snapshot.js.map +1 -0
- package/dist/graph.d.ts +11 -0
- package/dist/graph.js +87 -0
- package/dist/graph.js.map +1 -0
- package/dist/impact.d.ts +28 -0
- package/dist/impact.js +223 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +18 -0
- package/dist/index.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 +176 -0
- package/dist/main.js.map +1 -0
- package/dist/migrate.d.ts +7 -0
- package/dist/migrate.js +69 -0
- package/dist/migrate.js.map +1 -0
- package/dist/ontology.d.ts +41 -0
- package/dist/ontology.js +270 -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/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 +225 -0
- package/dist/static-check.js.map +1 -0
- package/dist/sync.d.ts +5 -0
- package/dist/sync.js +46 -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 +1065 -0
- package/graph-ui/index.html +197 -0
- package/graph-ui/model.js +141 -0
- package/graph-ui/relations.js +125 -0
- package/graph-ui/structure.js +74 -0
- package/graph-ui/style.css +1698 -0
- package/managed/errors/CAGE-APPR-001.md +32 -0
- package/managed/errors/CAGE-APPR-002.md +32 -0
- package/managed/errors/CAGE-APPR-003.md +32 -0
- package/managed/errors/CAGE-APPR-004.md +32 -0
- package/managed/errors/CAGE-APPR-005.md +32 -0
- package/managed/errors/CAGE-APPR-006.md +32 -0
- package/managed/errors/CAGE-APPR-007.md +32 -0
- package/managed/errors/CAGE-APPR-010.md +32 -0
- package/managed/errors/CAGE-AUTH-001.md +32 -0
- package/managed/errors/CAGE-BUDGET-001.md +32 -0
- package/managed/errors/CAGE-BUDGET-002.md +32 -0
- package/managed/errors/CAGE-BUDGET-003.md +32 -0
- package/managed/errors/CAGE-CMD-002.md +32 -0
- package/managed/errors/CAGE-CMD-003.md +34 -0
- package/managed/errors/CAGE-CONN-001.md +32 -0
- package/managed/errors/CAGE-CONN-002.md +32 -0
- package/managed/errors/CAGE-CONN-003.md +32 -0
- package/managed/errors/CAGE-CONN-004.md +32 -0
- package/managed/errors/CAGE-CONN-005.md +32 -0
- package/managed/errors/CAGE-CONN-006.md +32 -0
- package/managed/errors/CAGE-CONN-007.md +32 -0
- package/managed/errors/CAGE-CONN-008.md +32 -0
- package/managed/errors/CAGE-CONN-009.md +32 -0
- package/managed/errors/CAGE-CONN-010.md +32 -0
- package/managed/errors/CAGE-CONN-011.md +32 -0
- package/managed/errors/CAGE-CONN-012.md +32 -0
- package/managed/errors/CAGE-CREATE-001.md +32 -0
- package/managed/errors/CAGE-DECL-001.md +34 -0
- package/managed/errors/CAGE-DECL-002.md +34 -0
- package/managed/errors/CAGE-DECL-003.md +34 -0
- package/managed/errors/CAGE-DECL-004.md +34 -0
- package/managed/errors/CAGE-DEP-001.md +34 -0
- package/managed/errors/CAGE-DEP-002.md +34 -0
- package/managed/errors/CAGE-DEP-003.md +34 -0
- package/managed/errors/CAGE-DEP-004.md +34 -0
- package/managed/errors/CAGE-DEP-005.md +34 -0
- package/managed/errors/CAGE-DLQ-001.md +32 -0
- package/managed/errors/CAGE-ENV-001.md +32 -0
- package/managed/errors/CAGE-EVENT-001.md +32 -0
- package/managed/errors/CAGE-EVENT-002.md +32 -0
- package/managed/errors/CAGE-FIELD-001.md +32 -0
- package/managed/errors/CAGE-FIELD-002.md +32 -0
- package/managed/errors/CAGE-FIELD-003.md +32 -0
- package/managed/errors/CAGE-FIELD-004.md +32 -0
- package/managed/errors/CAGE-GEN-001.md +33 -0
- package/managed/errors/CAGE-GEN-002.md +33 -0
- package/managed/errors/CAGE-GRANT-001.md +32 -0
- package/managed/errors/CAGE-GRANT-002.md +32 -0
- package/managed/errors/CAGE-GRANT-003.md +32 -0
- package/managed/errors/CAGE-IMPACT-001.md +32 -0
- package/managed/errors/CAGE-JOB-001.md +32 -0
- package/managed/errors/CAGE-JOB-002.md +32 -0
- package/managed/errors/CAGE-JOB-003.md +32 -0
- package/managed/errors/CAGE-LINT-001.md +32 -0
- package/managed/errors/CAGE-MIG-001.md +32 -0
- package/managed/errors/CAGE-MIG-002.md +32 -0
- package/managed/errors/CAGE-MIG-003.md +32 -0
- package/managed/errors/CAGE-MIG-004.md +32 -0
- package/managed/errors/CAGE-MIG-005.md +32 -0
- package/managed/errors/CAGE-NAME-001.md +32 -0
- package/managed/errors/CAGE-NAME-002.md +32 -0
- package/managed/errors/CAGE-NAME-003.md +32 -0
- package/managed/errors/CAGE-NAME-004.md +32 -0
- package/managed/errors/CAGE-NAME-005.md +32 -0
- package/managed/errors/CAGE-NAME-006.md +32 -0
- package/managed/errors/CAGE-ORG-001.md +32 -0
- package/managed/errors/CAGE-PAIR-002.md +33 -0
- package/managed/errors/CAGE-QUERY-001.md +32 -0
- package/managed/errors/CAGE-QUERY-002.md +32 -0
- package/managed/errors/CAGE-QUERY-003.md +32 -0
- package/managed/errors/CAGE-REACT-001.md +32 -0
- package/managed/errors/CAGE-REACT-002.md +32 -0
- package/managed/errors/CAGE-READS-001.md +32 -0
- package/managed/errors/CAGE-REG-001.md +32 -0
- package/managed/errors/CAGE-REG-002.md +32 -0
- package/managed/errors/CAGE-REG-003.md +32 -0
- package/managed/errors/CAGE-ROUTE-001.md +32 -0
- package/managed/errors/CAGE-SCOPE-001.md +32 -0
- package/managed/errors/CAGE-SCOPE-002.md +32 -0
- package/managed/errors/CAGE-SECRET-001.md +32 -0
- package/managed/errors/CAGE-SECRET-002.md +32 -0
- package/managed/errors/CAGE-SENS-001.md +32 -0
- package/managed/errors/CAGE-SQL-001.md +32 -0
- package/managed/errors/CAGE-SQL-002.md +32 -0
- package/managed/errors/CAGE-STATE-001.md +32 -0
- package/managed/errors/CAGE-STATE-002.md +32 -0
- package/managed/errors/CAGE-STATE-003.md +32 -0
- package/managed/errors/CAGE-STATE-004.md +32 -0
- package/managed/errors/CAGE-STATE-005.md +32 -0
- package/managed/errors/CAGE-STATE-010.md +32 -0
- package/managed/errors/CAGE-STATE-011.md +32 -0
- package/managed/errors/CAGE-SYNC-001.md +35 -0
- package/managed/errors/CAGE-TEST-001.md +33 -0
- package/managed/errors/CAGE-UNSAFE-001.md +32 -0
- package/managed/errors/CAGE-UPGRADE-001.md +32 -0
- package/managed/errors/README.md +99 -0
- package/package.json +60 -3
- package/templates/app/.dockerignore +10 -0
- package/templates/app/.env.example +17 -0
- package/templates/app/.github/workflows/cage.yml +44 -0
- package/templates/app/AGENTS.md +13 -0
- package/templates/app/Dockerfile +23 -0
- package/templates/app/README.md +58 -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/main.tsx +552 -0
- package/templates/app/apps/web/src/style.css +663 -0
- package/templates/app/apps/web/tsconfig.json +11 -0
- package/templates/app/apps/web/vite.config.ts +16 -0
- package/templates/app/cage.config.json +114 -0
- package/templates/app/compose.yaml +39 -0
- package/templates/app/db/migrations/0001_init.sql +112 -0
- package/templates/app/package.json +25 -0
- package/templates/app/packages/contracts/package.json +16 -0
- package/templates/app/packages/contracts/src/dept.ts +74 -0
- package/templates/app/packages/contracts/src/index.ts +81 -0
- package/templates/app/packages/contracts/src/inventory-lock.ts +52 -0
- package/templates/app/packages/contracts/src/inventory.ts +57 -0
- package/templates/app/packages/contracts/src/purchase-order.ts +72 -0
- package/templates/app/packages/contracts/src/queries.ts +17 -0
- package/templates/app/packages/contracts/src/role.ts +85 -0
- package/templates/app/packages/contracts/src/user.ts +89 -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/approvals.ts +18 -0
- package/templates/app/packages/domain/src/erp.ts +36 -0
- package/templates/app/packages/domain/src/index.ts +9 -0
- package/templates/app/packages/domain/src/inventory.ts +43 -0
- package/templates/app/packages/domain/src/jobs.ts +13 -0
- package/templates/app/packages/domain/src/purchase-order.test.ts +137 -0
- package/templates/app/packages/domain/src/purchase-order.ts +122 -0
- package/templates/app/packages/domain/src/queries.ts +10 -0
- package/templates/app/packages/domain/src/reactions.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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# 推荐运行 pnpm db:setup 自动生成 .env 和随机密码;不要直接使用占位符连接。
|
|
2
|
+
CAGE_POSTGRES_PORT=54329
|
|
3
|
+
CAGE_TEST_POSTGRES_PORT=54330
|
|
4
|
+
POSTGRES_PASSWORD=<开发集群超级用户密码>
|
|
5
|
+
CAGE_TEST_POSTGRES_PASSWORD=<测试集群独立密码>
|
|
6
|
+
CAGE_SUPER_DATABASE_URL=postgresql://postgres:<开发集群超级用户密码>@127.0.0.1:54329/postgres
|
|
7
|
+
CAGE_APP_DATABASE_URL=postgresql://cage_app:<业务写入密码>@127.0.0.1:54329/cage_dev
|
|
8
|
+
CAGE_READ_DATABASE_URL=postgresql://cage_read:<只读密码>@127.0.0.1:54329/cage_dev
|
|
9
|
+
CAGE_MIGRATE_DATABASE_URL=postgresql://cage_migrate:<迁移密码>@127.0.0.1:54329/cage_dev
|
|
10
|
+
# 只允许指向可丢弃的独立测试集群。
|
|
11
|
+
CAGE_TEST_DATABASE_URL=postgresql://postgres:<测试集群独立密码>@127.0.0.1:54330/postgres
|
|
12
|
+
CAGE_COOKIE_SECRET=<随机会话签名密钥>
|
|
13
|
+
CAGE_STAGE=fake
|
|
14
|
+
# 5173 被 Windows 保留时,可改成 15173。端口不会自动漂移,避免访问到错误的服务。
|
|
15
|
+
CAGE_WEB_PORT=5173
|
|
16
|
+
PORT=3000
|
|
17
|
+
HOST=127.0.0.1
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 尚未配置框架发布地址时直接调用同一个 CLI 门禁。
|
|
2
|
+
# 框架发布后可将此任务替换为远端 app-verify.yml 的 uses 引用。
|
|
3
|
+
name: Cage application
|
|
4
|
+
on: [push, pull_request]
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
jobs:
|
|
8
|
+
verify:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
services:
|
|
11
|
+
postgres:
|
|
12
|
+
image: postgres:18
|
|
13
|
+
env: { POSTGRES_PASSWORD: cage_ci }
|
|
14
|
+
ports: ['5432:5432']
|
|
15
|
+
options: --health-cmd "pg_isready -U postgres" --health-interval 5s --health-timeout 5s --health-retries 10
|
|
16
|
+
env:
|
|
17
|
+
CAGE_TEST_DATABASE_URL: postgres://postgres:cage_ci@localhost:5432/postgres
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with: { fetch-depth: 0 }
|
|
21
|
+
- uses: pnpm/action-setup@v4
|
|
22
|
+
with: { version: 10.14.0 }
|
|
23
|
+
- uses: actions/setup-node@v4
|
|
24
|
+
with: { node-version: 24 }
|
|
25
|
+
- run: pnpm install --frozen-lockfile
|
|
26
|
+
- run: pnpm build:app
|
|
27
|
+
- run: pnpm cage verify
|
|
28
|
+
- name: Pull request impact
|
|
29
|
+
if: github.event_name == 'pull_request'
|
|
30
|
+
env:
|
|
31
|
+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
32
|
+
run: |
|
|
33
|
+
pnpm cage impact --base "$BASE_SHA" --format md --out .cage/impact.md
|
|
34
|
+
cat .cage/impact.md >> "$GITHUB_STEP_SUMMARY"
|
|
35
|
+
- run: pnpm audit --prod --audit-level high
|
|
36
|
+
- uses: actions/upload-artifact@v4
|
|
37
|
+
if: always()
|
|
38
|
+
with:
|
|
39
|
+
name: cage-report
|
|
40
|
+
include-hidden-files: true
|
|
41
|
+
path: |
|
|
42
|
+
.cage/verify.json
|
|
43
|
+
.cage/test-results.json
|
|
44
|
+
.cage/impact.md
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- cage:begin v0.1.0 -->
|
|
2
|
+
## Cage 框架约定
|
|
3
|
+
|
|
4
|
+
1. 先声明聚合、状态、命令、约束和事件,再实现 handler、查询与页面。
|
|
5
|
+
2. 修改后运行 cage check、cage gen、cage verify;用 cage impact --base-file 旧本体图.json 查看影响。
|
|
6
|
+
3. domain 的声明必须是模块顶层 export const,并从 index.ts 导出。
|
|
7
|
+
4. handler 的读依赖写入 reads;写入只走命令,第三方 IO 通过连接器。
|
|
8
|
+
5. 前端从 @app/contracts 导入契约;生成物通过 cage gen 更新。
|
|
9
|
+
6. 不得手写 HTTP 路由、拼接 SQL 或嵌入密钥;unsafe 必须注明 reason、owner。
|
|
10
|
+
7. 迁移草稿需审查,已发布的迁移不可修改;新增能力点由管理员授权。
|
|
11
|
+
8. 错误码见 docs/errors;完整示例见框架仓库 examples/purchase-admin。
|
|
12
|
+
<!-- cage:end -->
|
|
13
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 独立业务仓库使用已发布的 @yss123/cage-* 依赖;先提交 pnpm-lock.yaml。
|
|
2
|
+
# --framework-path 创建的 link: 本地依赖只用于源码开发,不能拷贝进独立镜像。
|
|
3
|
+
FROM node:24-bookworm-slim AS build
|
|
4
|
+
RUN corepack enable && corepack prepare pnpm@10.14.0 --activate
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
COPY . .
|
|
7
|
+
RUN pnpm install --frozen-lockfile && pnpm build:app
|
|
8
|
+
RUN pnpm --filter @app/api deploy --prod --legacy /out/api
|
|
9
|
+
|
|
10
|
+
# 发布过程先单独运行此 target,迁移账号只注入迁移任务。
|
|
11
|
+
FROM build AS migration
|
|
12
|
+
CMD ["pnpm", "cage", "migrate"]
|
|
13
|
+
|
|
14
|
+
# API 与 worker 共用运行时镜像,通过启动命令区分职责。
|
|
15
|
+
FROM node:24-bookworm-slim AS runtime
|
|
16
|
+
WORKDIR /app
|
|
17
|
+
COPY --from=build --chown=node:node /out/api /app
|
|
18
|
+
COPY --from=build --chown=node:node /app/apps/web/dist /app/web
|
|
19
|
+
ENV NODE_ENV=production PORT=3000 WEB_DIR=/app/web
|
|
20
|
+
USER node
|
|
21
|
+
EXPOSE 3000
|
|
22
|
+
CMD ["node", "dist/main.js"]
|
|
23
|
+
# worker 启动命令:node dist/worker.js
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# 采购工作台
|
|
2
|
+
|
|
3
|
+
这是可启动的标准范例:组织管理、采购单、审批待办、库存台账、库存锁生命周期和 ERP 出入站映射。
|
|
4
|
+
|
|
5
|
+
## 启动
|
|
6
|
+
|
|
7
|
+
在框架仓库根目录执行 `pnpm install`、`pnpm build`,然后进入本目录。独立模板项目先执行 `pnpm install`、`pnpm build:app`、`pnpm cage gen`。
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
pnpm cage db setup
|
|
11
|
+
pnpm cage db up
|
|
12
|
+
# 仅首次初始化独立新集群时执行;已有库随后用 cage migrate。
|
|
13
|
+
pnpm cage db init
|
|
14
|
+
pnpm dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
连接池、事务、数据库初始化和凭证生成均由框架提供,项目不写连接或建库脚本。`cage db setup` 生成随机密码和本地 `.env`,重复运行保留已有配置。开发库位于 `127.0.0.1:54329/cage_dev`,测试库位于独立容器的 54330 端口。`cage db down` 停止容器但保留开发数据卷;`cage db up` 再次启动。package.json 中的 `db:*` 是相同命令的简写。
|
|
18
|
+
|
|
19
|
+
CLI 自动读取项目 `.env`,部署环境变量优先。`CAGE_APP_DATABASE_URL`、`CAGE_READ_DATABASE_URL`、`CAGE_MIGRATE_DATABASE_URL` 分别连接写入、只读和迁移账号。超级用户仅用于初始化,API/worker 不接收其凭证。
|
|
20
|
+
|
|
21
|
+
测试环境会初始化集群级角色,因此 `CAGE_TEST_DATABASE_URL` 必须指向独立测试集群。运行 `pnpm cage verify` 验证示例;框架仓库根目录的 `pnpm test:docker` 验证全部框架测试。
|
|
22
|
+
|
|
23
|
+
浏览器打开 <http://localhost:5173>。初始管理员凭证在 API 终端显示一次。
|
|
24
|
+
如果 Windows Docker/Hyper-V 保留了该端口,在 `.env` 设置 `CAGE_WEB_PORT=15173`;终端会打印实际地址。`PORT` 控制 API 端口,Vite 代理同步使用它。未配置数据库连接串时才使用原有内嵌 PostgreSQL。
|
|
25
|
+
|
|
26
|
+
## 体验完整采购流程
|
|
27
|
+
|
|
28
|
+
1. 管理员在“库存台账”登记 `A-01` 等物料。
|
|
29
|
+
2. 进入 `/admin/` 创建采购员、经理,分别分配采购命令和审批能力;经理的 `PurchaseOrder.approve` 参数配置 `ceiling`。
|
|
30
|
+
3. 把经理设为采购员所在部门的负责人。提单人与审批人必须不同。
|
|
31
|
+
4. 采购员新建并提交采购单;worker 建立审批待办。
|
|
32
|
+
5. 经理在“审批待办”通过,内核同事务生成库存锁;worker 调用 fake ERP 并回写单号。
|
|
33
|
+
6. 超过 50,000 元的采购走财务第二步,需另建 code 为 `finance` 的角色并分配审批人。
|
|
34
|
+
7. 取消单据或收到 ERP 收货回调后,通过异步反应释放锁。回调需要 `ERP_WEBHOOK_SECRET` 对原始 JSON 的 HMAC-SHA256 签名。
|
|
35
|
+
|
|
36
|
+
`Inventory.available` 是演示台账数量。本例验证库存锁生命周期,尚未实现仓库级的并发扣减、实物库存及退货核算。
|
|
37
|
+
|
|
38
|
+
本例的取消只改变本地单据并释放锁,尚未对接真实 ERP 的取消补偿接口。ERP 单号应答可能晚于取消或收货到达,`recordErpNo` 使用 `to: null` 保留当时的单据状态;它仍然检查允许的起始状态、调用身份和版本,并写入审计。上线前需确定外部订单撤销、退货或人工补偿的业务规则。
|
|
39
|
+
|
|
40
|
+
## 文件怎么读
|
|
41
|
+
|
|
42
|
+
在本目录运行 `pnpm exec cage graph`,浏览器打开终端输出的 <http://127.0.0.1:15418>,即可用图谱查看业务关系。页面支持中文/英文搜索、类型筛选、拖拽缩放、聚焦关联、声明位置与重新抽取,不需要启动数据库。
|
|
43
|
+
|
|
44
|
+
默认“对象与字段”按表卡片展示采购单、库存台账和库存锁,字段收在对象卡片中,显示中文含义、类型、必填标记及实际表名。拖动表头可以移动整张卡片。勾选“包含系统组织模型”查看部门、用户等对象;字段引用从字段行连到目标表头。“业务流程”和“完整本体”用于查看命令、事件、审批等更完整的关系。页面所说的业务对象,技术上叫“聚合”,包含共同遵守业务规则的字段、状态和命令,不只是数据库表。
|
|
45
|
+
|
|
46
|
+
线上的中文名称说明关系类型;点击连线、标签或节点详情中的“解释”,查看连接原因、业务用途、箭头方向和声明依据。可搜索 `PurchaseOrder.deptId` 后点击“聚焦关联”,看到采购单的所属部门字段**引用**部门卡片。字段详情中还可查看“采购审批分支”怎样用它**确定审批人**,点击解释会切换到完整本体显示对应连线。审批流程的“允许审批读取”表示字段可用范围,实际选人依据另有解释。
|
|
47
|
+
|
|
48
|
+
图谱主标题显示中文业务名称,下面保留英文代码标识。框架会读取声明现有的 `description`;本项目在 `cage.config.json` 的 `graph.labels` 中补充状态、字段等名称,也可覆盖较长描述。例如 `"command:PurchaseOrder.approve": "通过审批"`。键为 `节点类型:本体节点 ID`,可从节点详情复制 ID;中文标题只用于显示,不改变命令、权限标识或数据库。新增业务声明时同时补上需要的名称,然后在图谱中点击“重新抽取”。
|
|
49
|
+
|
|
50
|
+
- `packages/domain/src/inventory.ts`:最简聚合和库存锁。
|
|
51
|
+
- `purchase-order.ts`:状态、命令、约束和事件。
|
|
52
|
+
- `reactions.ts`:同事务建锁与异步释放,包含资源配对标记。
|
|
53
|
+
- `approvals.ts`、`erp.ts`:封闭审批路由、出站和入站映射。
|
|
54
|
+
- `queries.ts`、`jobs.ts`:安全视图查询及过期草稿清理。
|
|
55
|
+
- `apps/api/src`:API 和 worker 的薄启动入口。
|
|
56
|
+
- `apps/web/src`:仅依赖生成契约的 React 界面。
|
|
57
|
+
|
|
58
|
+
先运行 `pnpm cage gen` 再提交契约和迁移草稿;`pnpm cage verify` 检查完整工具链。派生测试遇到无法推断的业务输入会显示跳过,`purchase-order.test.ts` 另外准备真实业务数据覆盖成功审批和约束反例。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@app/api",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -p tsconfig.json",
|
|
7
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
8
|
+
"start": "node dist/main.js",
|
|
9
|
+
"worker": "node dist/worker.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@app/domain": "workspace:*",
|
|
13
|
+
"@yss123/cage-http": "0.1.0",
|
|
14
|
+
"@yss123/cage-connectors": "0.1.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// 启动入口只装配框架:认证、业务路由和 /admin 都由 createServer 提供。
|
|
2
|
+
// WEB_DIR 在部署镜像中指向 Vite 构建产物;本地由 Vite 独立提供前端。
|
|
3
|
+
import { createServer } from '@yss123/cage-http';
|
|
4
|
+
import * as domain from '@app/domain';
|
|
5
|
+
|
|
6
|
+
const server = createServer({ domain, webDir: process.env.WEB_DIR, title: 'Cage 采购工作台' });
|
|
7
|
+
await server.listen();
|
|
8
|
+
// 退出时释放数据库池及 LISTEN 连接,部署滚动替换时不会留下旧连接。
|
|
9
|
+
process.once('SIGINT', () => void server.close());
|
|
10
|
+
process.once('SIGTERM', () => void server.close());
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// API 与 worker 使用相同声明。worker 专门处理审批启动、异步反应和 ERP 推送。
|
|
2
|
+
import { startWorker } from '@yss123/cage-http/worker';
|
|
3
|
+
import { fakeConnector, stage } from '@yss123/cage-connectors';
|
|
4
|
+
import * as domain from '@app/domain';
|
|
5
|
+
|
|
6
|
+
// 本地和测试的 ERP 返回确定的单号,便于查看同步记录;生产环境走真实出口。
|
|
7
|
+
if (stage() === 'fake') {
|
|
8
|
+
fakeConnector(domain.erp, {
|
|
9
|
+
pushOrder: (request) => ({ erpNo: `DEMO-${request.externalId.slice(0, 8)}` }),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
const worker = await startWorker({ domain });
|
|
13
|
+
process.once('SIGINT', () => void worker.stop());
|
|
14
|
+
process.once('SIGTERM', () => void worker.stop());
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
6
|
+
<meta name="theme-color" content="#153c35" />
|
|
7
|
+
<title>Cage · 采购工作台</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@app/web",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "tsc --noEmit && vite build",
|
|
8
|
+
"typecheck": "tsc --noEmit"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@app/contracts": "workspace:*",
|
|
12
|
+
"@tanstack/react-query": "^5.87.1",
|
|
13
|
+
"react": "^19.1.1",
|
|
14
|
+
"react-dom": "^19.1.1"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/react": "^19.1.13",
|
|
18
|
+
"@types/react-dom": "^19.1.9",
|
|
19
|
+
"vite": "^7.1.4",
|
|
20
|
+
"typescript": "~5.9.3"
|
|
21
|
+
}
|
|
22
|
+
}
|