文件
wangsli和Claude Opus 5.5 36b949ecf6
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
借款出借人增加员工与公司组合数据库唯一约束(09-17-company-loan-principal-repayment)
- 新迁移 20261011010000_loan_lender_employee_unique:(legal_entity_id, employee_id) 唯一,归档计入、无员工出借人不冲突;生产只读排查重复 0 组
- 触到约束时返回原有 loan.employee_lender_conflict,不报 500 或误报请求重复;员工行锁与代码检查保留
- 测试改为断言数据库拒绝模糊旧数据,补空员工共存与归档占用;变异 12 项含去索引与数据库兜底两种运行
- PRD 补本迁移回退说明;独立只读复核无阻断,发布窗口需重跑重复计数(AC59)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 13:21:08 +08:00
..

hyb-oa Server Runbook (P0/P1)

1. 环境准备

  • Node.js: >=22 <23
  • Docker + Docker Compose
  • 本地工具:curl、jq
  • 配置文件:从 server/.env.example 复制为 server/.env 并按需修改
cd server
cp .env.example .env

2. Gate 基线命令(必须顺序执行)

2.1 启动数据库

cd ..
export POSTGRES_PASSWORD="<local-only-db-password>"
export JWT_SECRET="<local-only-jwt-secret>"
docker compose up -d db

根级 Compose 不再内置数据库口令或 JWT 密钥;请仅在本地 shell 或未提交的环境文件中设置,并让 server/.env 的 DATABASE_URL 使用同一数据库口令。

2.2 应用迁移

cd server
npm run prisma:migrate:deploy

2.3 执行 seed(幂等)

cd server
SEED_DEV_ALLOW=1 SEED_DEV_DATABASE_CONFIRM=hyb_oa npm run seed:dev

说明:

  • seed:dev 永久拒绝 production,只接受 loopback PostgreSQL,并要求确认 URL 中的数据库名。
  • 开发账号资料和口令可通过 SEED_* 环境变量覆盖;脚本不会打印口令。
  • 默认保留已有账号密码。新建账号以及主动设置 SEED_DEV_RESET_PASSWORDS=1 后轮换的账号,首次登录都必须改密。
  • 开发账号配置不得复用于试运行或生产。

试运行管理员引导(E20):

cd server
TRIALRUN_ADMIN_EMAIL="<admin-email>" \
TRIALRUN_ADMIN_PHONE="<admin-phone>" \
TRIALRUN_ADMIN_PASSWORD="" \
npm run seed:trialrun

说明:

  • TRIALRUN_ADMIN_PASSWORD 为空时会生成并打印一次性口令(请立刻保存)。
  • 若管理员已存在,脚本只确保其为 active 且具备 admin+employee 角色,不会改动密码。

2.3.1 认证安全说明(P5)

  • POST /api/auth/login 成功响应包含 mustChangePassword:
    • true:表示该账号处于“首次登录/管理员重置密码后”状态;前端应强制引导改密后再进入业务页。
    • 改密接口:POST /api/auth/change-password(需要 authorization: Bearer <token> + x-device-fingerprint)。
  • 登录失败锁定(默认):
    • 15 分钟内失败 5 次会锁定 30 分钟,返回 423 AUTH_002(含 lockedUntil)。
    • 解锁:POST /api/users/:id/unlock(权限:system.users)。
  • 弱密码拦截:
    • 采用 zxcvbn 评分,默认 score < 2 拒绝(返回 VALID_001.details.password)。
  • 可通过 WEAK_PASSWORD_CHECK_ENABLED=false 关闭(不建议生产关闭)。

2.3.2 邮件通知(可选,F15)

  • 默认关闭:EMAIL_ENABLED=false
  • 开启后支持触发邮件(失败降级不阻塞主流程):
    • 新待办分配(workflow.task_assigned)
    • 审批结果(approved/rejected/returned)
    • 付款完成(reimbursement.paid)
    • 密码重置(forgot-password / reset-password)
  • 需要配置 SMTP:
    • SMTP_HOST、SMTP_PORT(默认 587)、SMTP_SECURE(465 通常为 true)
    • SMTP_USER、SMTP_PASS(按 SMTP 服务要求)
    • EMAIL_FROM(发件人地址)
    • EMAIL_BASE_URL(可选,邮件内“查看详情”链接的站点前缀;为空则尝试使用 APP_ORIGIN 的第一个值)

2.3.3 作业系统(cron vs pg-boss)(F19~F19d)

  • 默认:JOB_DRIVER=cron(同进程 node-cron 调度)
  • 可选升级:JOB_DRIVER=pgboss(Postgres 队列,适配单机/多进程;避免引入 Redis)
    • PG_BOSS_SCHEMA(默认 pgboss)
    • JOBS_ENABLED=false 可整体关闭作业(仅用于排障/紧急回滚)
  • 目前迁移的作业:
    • ocr.tick(受 OCR_PROVIDER 控制,off 时不调度)
    • delegation.revoke-expired
    • invoice.archive-unused
  • 回滚策略:
    • 将 JOB_DRIVER 切回 cron(无需 schema 迁移回滚,风险低)

2.3.4 Worker 进程拆分(可选,F20)

目的:单机也能用“API 进程 + Worker 进程”模式运行,便于未来横向扩展;不改变对外 API。

  • API 进程:只提供 HTTP(可选托管 client/dist),不跑作业
  • Worker 进程:只跑作业(OCR/委派回收/超期归档),不监听端口

本地双进程示例:

# 终端 A:API(不跑作业)
cd <repo-root>/server
JOBS_ENABLED=false npm run dev

# 终端 B:Worker(只跑作业)
cd <repo-root>/server
JOBS_ENABLED=true npm run worker

试运行 compose(推荐,见 deploy/trialrun/runbook.md):

  • 启用 worker profile:--profile worker
  • 同时将 server 的 JOBS_ENABLED=false(worker 进程内强制为 true)

2.3.5 存储驱动(local vs S3/MinIO)(F21)

目标:把“票据文件存储”从本地目录可选演进到 S3 兼容(单机优先 MinIO),保持签名 URL 契约不变。

  • 默认:STORAGE_DRIVER=local(写入 STORAGE_DIR)
  • 可选:STORAGE_DRIVER=s3(写入 S3/MinIO)
    • 需要配置:S3_ENDPOINT/S3_REGION/S3_BUCKET/S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEY/S3_FORCE_PATH_STYLE
    • 为兼容混合存储,invoice_pool.storage_path 对 S3 会写成 s3:<key>(无 schema 变更)

签名 URL 兼容策略:

  • /api/invoice-pool/:id/signed-url 仍返回本系统 URL(带 token)
  • /api/invoice-pool/:id/file 内部按 storage_path 自动从本地或 S3 读取并返回文件流

2.4 启动服务

cd <repo-root>/server
npm run dev

2.5 冒烟验证

cd <repo-root>/server
./scripts/smoke-test.sh

2.6 本地最小门禁(P1-b)

cd <repo-root>
./scripts/check-minimal.sh

说明:

  • 该脚本只做静态/构建级门禁,不启动服务与数据库。
  • 全量回归仍通过 server/scripts/regression-all.sh 执行。

3. 1 分钟快速验证

cd <repo-root>/server
./scripts/smoke-test.sh

也可直接探活:

curl -fsS http://127.0.0.1:3000/health
curl -fsS http://127.0.0.1:3000/ready
curl -fsS http://127.0.0.1:3000/metrics | head

说明:

  • /health:liveness(不查 DB)
  • /ready:readiness(SELECT 1 探活 DB,失败返回 503)
  • /metrics:Prometheus 指标(可通过 METRICS_ENABLED=false 关闭)

4. 回归入口

4.1 脚本回归(推荐)

cd <repo-root>/server
BASE_URL=http://127.0.0.1:3000 ./scripts/smoke-test.sh

4.2 判重专项回归(dedup)

cd <repo-root>/server
DATABASE_URL='<local-postgresql-url>' \
BASE_URL=http://127.0.0.1:3000 ./scripts/regression-dedup.sh

4.3 工作流动作回归

cd <repo-root>/server
./scripts/regression-workflow-actions.sh

可选并发校验:

cd <repo-root>/server
RUN_DELEGATION_CONCURRENCY_CHECK=1 ./scripts/regression-workflow-actions.sh

覆盖场景:

  • reject:实例=rejected,报销=rejected
  • return:实例=terminated,报销=draft
  • withdraw:审批未处理前可撤回
  • return 后二次 submit:创建新实例
  • PERM_002:非 assignee 无法操作
  • no_actionable_approver:全链无可执行审批人阻断
  • negative_not_allowed:负金额防御
  • manager skip:直属上级缺失时跳过并记录
  • transfer:转审成功(任务改派 + 任务/转审记录/history 三处证据)
  • transfer 参数校验:reason<10 返回 VALID_002
  • transfer 同人转审:返回 VALID_001(same_assignee_not_allowed)
  • transfer 链路上限:同 task 第 4 次转审阻断(chain_limit_exceeded)
  • transfer 目标校验:目标审批人须 active 且具备 expense.approve
  • pay:财务付款成功(approved -> paid,发票 bound -> archived(used_complete))
  • pay 权限:非财务返回 PERM_001
  • pay 状态校验:非 approved/paid 返回 VALID_001
  • pay 幂等:重复付款返回 200(archivedInvoiceCount 可为 0)
  • pay 幂等冲突:已付款后提交冲突凭证字段返回 409 VALID_001(already_paid_conflict)
  • delegation:有效期内可代办并在 history 写入 delegation 证据
  • delegation 过期:代理人返回 PERM_002,自动回收任务可撤销过期委派
  • delegation 并发回收(可选):RUN_DELEGATION_CONCURRENCY_CHECK=1 时双并发只回收一次并仅写一条自动回收审计

4.4 一键全量回归

cd <repo-root>/server
./scripts/regression-all.sh

串联 smoke-test.sh + regression-dedup.sh + regression-workflow-actions.sh + regression-audit.sh + regression-ocr.sh,适用于 CI 或发版前检查。

可选关闭审计/OCR:

cd <repo-root>/server
RUN_AUDIT_REGRESSION=0 RUN_OCR_REGRESSION=0 ./scripts/regression-all.sh

可选打开组织/配置回归(org + settings):

cd <repo-root>/server
RUN_ORG_SETTINGS_REGRESSION=1 ./scripts/regression-all.sh

可选打开认证安全回归(auth security):

cd <repo-root>/server
RUN_AUTH_SECURITY_REGRESSION=1 ./scripts/regression-all.sh

独立执行:

cd <repo-root>/server
./scripts/regression-audit.sh
OCR_PROVIDER=mock ./scripts/regression-ocr.sh
./scripts/regression-org-settings.sh
./scripts/regression-auth-security.sh

4.5 Postman 回归

  • Collection: server/postman/hyb-oa.postman_collection.json
  • Environment: server/postman/hyb-oa.postman_environment.json
  • 核心链路:
    1. Login Employee
    2. Create Reimbursement
    3. Upload Invoice
    4. Bind Invoice
    5. Submit Reimbursement
    6. Login CEO
    7. Approve Workflow Task
    8. Get Signed URL

4.6 前端壳联调(P1-5)

cd <repo-root>/client
npm install
npm run dev

说明:

  • 前端开发地址默认 http://127.0.0.1:5173。
  • 通过 Vite 代理将 /api 转发到 http://127.0.0.1:3000。
  • Access Token 仅保存在内存,Refresh Token 通过 HttpOnly Cookie 续签。

4.7 单域托管 client/dist(可选,试运行建议)

cd <repo-root>/client
npm run build

cd <repo-root>/server
SERVE_CLIENT_DIST=true npm run dev

说明:

  • 访问 http://127.0.0.1:3000 即可打开前端(同域 cookie,减少 CORS 复杂度)。
  • SPA 路由(如 /dashboard)会回退到 index.html;/api/* 不参与回退。

4.8 试运行部署包(Docker Compose)

试运行/上线演练建议使用仓库内置部署包:

  • deploy/trialrun/runbook.md
  • deploy/trialrun/docker-compose.yml
  • deploy/trialrun/.env.example
  • deploy/trialrun/checklist.md

备份/恢复脚本(E14):

cd <repo-root>
DB_TOOL_MODE=docker DB_CONTAINER=hyb-oa-trialrun-db ./scripts/backup-all.sh
./scripts/qa/run-backup-restore-drill.sh

成对备份会生成 DB、附件和脱敏 manifest。恢复脚本只允许显式影子目标;真实事故恢复、异机副本和 /ready 验收按 deploy/trialrun/runbook.md 的授权门执行,不直接在 README 复制破坏性命令。

优雅停机(E21):

  • docker stop / Ctrl+C 会触发 SIGTERM/SIGINT,server 会调用 app.close() 完成收敛关闭(定时任务/HTTP/DB)。

5. P2 API 摘要

5.1 付款标记(pay)

  • POST /api/reimbursements/:id/pay
  • 权限:expense.finance.pay
  • 可选请求体:paymentVoucherNo、paymentDate(YYYY-MM-DD)、paymentChannel(bank/alipay/wechat/cash/other)
  • 语义:
    • approved -> paid:返回 200,并归档关联 bound 发票
    • 已 paid 重复同值:返回 200(payment.idempotent=true)
    • 已 paid 重复冲突值:返回 409 VALID_001,details.payment=already_paid_conflict

5.2 委派管理

  • POST /api/delegations:创建委派(scope + validFrom/validTo)
  • GET /api/delegations/mine:查看我发起/我接收的委派
  • POST /api/delegations/:id/revoke:撤销委派
  • 委派仅作用于 assignee_id 任务,不改写 assignee_role 语义。
  • 自动回收实现采用 FOR UPDATE SKIP LOCKED + UPDATE ... RETURNING,多实例并发下确保同一委派仅回收一次。

5.3 OCR 异步状态查询

  • 上传发票在 OCR 开启且 ocr_type=vat 时会进入 pending_ocr。
  • GET /api/invoice-pool/:id 可轮询 OCR 处理状态(pending_ocr/available/ocr_failed)。

5.4 审计日志查询

  • GET /api/audit-logs
  • 权限:system.audit.view(finance_mgr/admin)
  • 支持分页与筛选(actor/action/targetType/date range)。

5.5 工作流查询增强(P3)

  • GET /api/workflow/tasks:支持 status/page/pageSize,返回 page/pageSize/total/items。
  • GET /api/workflow/tasks/:taskId:任务详情(实例、报销摘要、可执行动作、处理历史)。
  • GET /api/workflow/approvers:转审候选人列表(active + 具备 expense.approve)。

5.6 部门管理(P5 蓝图 F26)

  • GET /api/departments:部门列表 + 树(登录即可;默认不含归档部门)
    • 可选:GET /api/departments?includeArchived=1(包含归档部门)
  • POST /api/departments:创建部门(system.users)
  • PATCH /api/departments/:id:更新部门(system.users;已归档禁止修改;禁止形成父子环)
  • POST /api/departments/:id/archive:归档部门(system.users)
    • 归档约束:有子部门/有在职员工则禁止归档
    • 幂等:已归档重复调用返回 outcome=already_archived

5.7 列表查询接口(P3)

  • GET /api/reimbursements:支持 page/pageSize/status/scope。
  • GET /api/invoice-pool:支持 page/pageSize/status/ownerScope。

5.8 定时任务(可手动执行)

cd <repo-root>/server
npm run job:revoke-expired-delegations
npm run job:ocr-once

5.9 账号与角色管理(E17,试运行运营)

  • GET /api/users:员工列表(分页/搜索)
  • POST /api/users:创建员工(含初始密码)
  • GET /api/users/:id:员工详情(管理员可看全部;员工可看自己;敏感字段仅返回脱敏)
  • POST /api/users/:id/disable:禁用员工(tokenVersion+1 + 撤销 refresh)
  • POST /api/users/:id/enable:启用员工(tokenVersion+1 + 撤销 refresh)
  • POST /api/users/:id/reset-password:重置密码(返回一次性口令,tokenVersion+1)
  • POST /api/users/:id/roles:设置角色(tokenVersion+1 + 撤销 refresh)
  • GET /api/users/:id/sensitive:敏感字段明文查询(F25)
  • PATCH /api/users/:id/sensitive:敏感字段更新(F25)

权限:

  • system.users(hr/admin;admin 具备 *)
  • system.users_sensitive(仅特权账号;用于解密查看/更新银行卡、身份证等)

6. 关键环境变量

  • DATABASE_URL: PostgreSQL 连接串
  • JWT_SECRET: JWT & signed-url token 签名密钥
  • FIELD_ENCRYPTION_KEY: 敏感字段加密密钥(AES-256-GCM;base64 32 bytes;用于银行卡/身份证等)
  • APP_TIMEZONE: 默认 Asia/Shanghai
  • REIMBURSEMENT_MAX_AGE_DAYS: 报销费用日期提示期限,默认 365,仅允许 180 或 365;超期和跨自然年度只预警,不自动阻断
  • STORAGE_DIR: 默认 generated/storage(相对 server/)
  • SERVE_CLIENT_DIST: 是否由 server 托管 client/dist(默认 false)
  • CLIENT_DIST_DIR: 前端构建产物目录(默认 ../client/dist,相对 server/)
  • SIGNED_URL_TTL_SECONDS: 默认 600
  • MAX_UPLOAD_SIZE_BYTES: 默认 10485760(10MB)
  • RATE_LIMIT_ENABLED: 是否启用关键接口限流(默认:production=true,其它环境=false)
  • RATE_LIMIT_LOGIN_MAX: /api/auth/login 等接口限流次数(默认 10)
  • RATE_LIMIT_LOGIN_WINDOW: 限流时间窗(默认 1 minute,支持 ms 格式如 30s/1m)
  • DELEGATION_REVOKE_CRON: 委派自动回收定时表达式(默认 0 * * * *)
  • OIDC_ENABLED: 是否启用 OIDC 登录(可选;默认 false)
  • OIDC_ISSUER_URL: OIDC issuer URL(发现地址)
  • OIDC_CLIENT_ID / OIDC_CLIENT_SECRET: OIDC client 配置
  • OIDC_REDIRECT_URI: 回调地址(例如 http://127.0.0.1:3000/api/auth/oidc/callback)
  • OIDC_SCOPES: 默认 openid profile email
  • OCR_PROVIDER: off / mock / tencent(默认 off)
  • OCR_BATCH_SIZE: 每轮 OCR 认领数量(默认 10)
  • OCR_LOCK_TTL_SECONDS: OCR 锁超时秒数(默认 300)
  • OCR_POLL_CRON: OCR 轮询 cron(默认 * * * * *)
  • OCR_MAX_ATTEMPTS: OCR 最大重试次数(默认 3)
  • OCR_TIMEOUT_MS: 腾讯 OCR SDK 超时(默认 5000)
  • TENCENT_SECRET_ID / TENCENT_SECRET_KEY / TENCENT_OCR_REGION: 腾讯 OCR 配置

安全基线(P4):

  • 安全头:默认启用 @fastify/helmet(CSP 默认关闭,避免误伤 SPA 本地调试)。
  • 限流:/api/auth/login、/api/auth/forgot-password、/api/auth/reset-password 在 RATE_LIMIT_ENABLED=true 时启用限流。
  • 日志脱敏:authorization/cookie/password/code/newPassword 等敏感字段会被 redaction。

回滚策略:

  • 若限流误伤,可先设置 RATE_LIMIT_ENABLED=false(无需改代码)。
  • 若安全头造成兼容性问题,可回退 server/src/app.js 中 helmet 注册逻辑。

生产提示:大表加索引需评估 CREATE INDEX CONCURRENTLY,避免锁表影响。


7. 常见失败排查

现象 可能原因 解决方案
prisma migrate deploy 失败 DATABASE_URL 未配置/不可达 检查 server/.env 与数据库容器状态
npm run seed:dev 重复执行报错 seed 脚本被改坏,未保持幂等 检查 seed-config.js/seed-dev.js 的 upsert / skipDuplicates
signed-url 接口返回 403 JWT_SECRET 不一致、token 过期、访问人无权限 统一服务密钥、确认 URL 在 TTL 内、检查账号角色
上传返回 file_too_large 文件超 MAX_UPLOAD_SIZE_BYTES 调整环境变量或使用更小文件
上传失败且报目录/权限错误 STORAGE_DIR 不存在或不可写 创建目录并修正权限;Docker 需确认 volume 挂载
OCR 长期停留 pending_ocr OCR_PROVIDER=off、mock未开启或腾讯密钥无效 检查 OCR 环境变量,优先用 OCR_PROVIDER=mock npm run job:ocr-once 验证链路
委派过期后仍可操作 自动回收任务未运行 检查 DELEGATION_REVOKE_CRON,手动执行 npm run job:revoke-expired-delegations

8. 手工故障注入(非阻塞)

8.1 STORAGE_DIR 不可写路径

  • 临时将 STORAGE_DIR 指向只读目录,执行上传接口,确认错误可观测(日志+返回码)。

8.2 磁盘空间不足(ENOSPC)

  • 在受控环境中制造磁盘满条件后重试上传。
  • 预期:错误路径可观测(日志中能定位到 I/O 错误),不要求纳入日常 CI 冒烟。

9. P6-P10 增量能力(验真 / 看板 / 预算 / 集成 / 生产硬化)

9.1 特性开关(默认值)

  • INVOICE_VERIFICATION_ENABLED=false
  • VERIFICATION_PROVIDER=mock
  • BUDGET_CONTROL_MODE=warn
  • ERP_SYNC_ENABLED=false
  • ERP_SYNC_PROVIDER=mock
  • ERP_SYNC_ENDPOINT=
  • ERP_SYNC_TIMEOUT_MS=5000
  • ERP_SYNC_AUTH_TOKEN=
  • TRAVEL_SYNC_ENABLED=false
  • IM_NOTIFIER_ENABLED=false

9.1.1 Feature Flag 治理(P11)

  • 新增统一管理 API:
    • GET /api/system/feature-flags
    • PUT /api/system/feature-flags/:key
  • 首期纳管键:erp_sync、invoice_verification。
  • 优先级规则:Env硬闸 > DB在线灰度。即使 DB 放开,若 Env 为 false 仍会关闭。
  • 部门灰度模式:rolloutType=department_allowlist 时,仅白名单部门生效。

建议:先在测试组织灰度开启,再逐步扩大范围。

9.2 新增 API 摘要

  • 发票验真:
    • POST /api/invoice-pool/:id/verify
    • GET /api/invoice-pool/:id/verification
    • POST /api/invoice-pool/:id/verification/retry
  • 看板聚合:
    • GET /api/dashboard/expense-overview
    • GET /api/dashboard/trends
    • GET /api/dashboard/top-categories
    • GET /api/dashboard/approval-efficiency
  • 预算管理:
    • GET /api/budgets
    • POST /api/budgets
    • PATCH /api/budgets/:id
    • POST /api/budgets/:id/archive
  • 外部集成:
    • POST /api/integrations/erp/sync/:reimbursementId
    • POST /api/travel/orders/import
    • GET /api/notifications/channels
    • POST /api/notifications/channels/test

9.3 新增回归脚本

cd <repo-root>/server
./scripts/regression-verification.sh
./scripts/regression-dashboard.sh
./scripts/regression-budget.sh
./scripts/regression-integrations.sh
./scripts/regression-feature-flags.sh

可通过总回归开关启用:

cd <repo-root>/server
RUN_VERIFICATION_REGRESSION=1 \
RUN_DASHBOARD_REGRESSION=1 \
RUN_BUDGET_REGRESSION=1 \
RUN_INTEGRATIONS_REGRESSION=1 \
RUN_FEATURE_FLAGS_REGRESSION=1 \
./scripts/regression-all.sh

9.4 单次任务脚本(调试)

cd <repo-root>/server
VERIFICATION_RECORD_ID=<uuid> npm run job:verification-once
npm run job:integration-outbox-once

9.5 回滚建议

  1. 先关闭特性开关(验真/ERP/差旅/IM)。
  2. 再停止相关任务调度(verification / integration outbox)。
  3. 不回滚审计与历史台账数据,保持可追溯。

9.6 P9/P10 维护性与硬化说明

  • 票据路由拆分:验真端点已拆到 src/routes/invoicePool/verification.js,读路径端点已拆到 src/routes/invoicePool/read.js,主入口仍为 src/routes/invoicePool.js,API 路径不变。
  • Shared 抽象:src/routes/invoicePool/shared/{selects,mappers,schemas,helpers}.js 统一验真映射与票据查询 select,避免字段漂移。
  • 看板聚合:/api/dashboard/trends 与 /api/dashboard/top-categories 已改为数据库聚合(groupBy),降低大数据量下内存聚合开销。
  • 看板回归:./scripts/regression-dashboard.sh 新增重复请求一致性断言;可通过 DASHBOARD_PERF_CHECK=1 打印趋势接口耗时探针。
  • ERP硬化回归:./scripts/regression-integrations.sh 内嵌最小 Node Mock ERP 服务,覆盖 success / 4xx(dead_letter) / 5xx(retry) / timeout(retry)。
  • 矩阵门禁:scripts/validate-feature-matrix.py 默认校验 P5 + P6-P8 + P9 + P10 四事实源;./scripts/check-minimal.sh 会自动执行该校验。