文件
hyb-oa/.trellis/tasks/08-08-production-deployment-execution/design.md
T
wangsli 4596ed0686
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
规划(08-08-production-deployment-execution): 生产部署执行与验收
2026-08-08 12:01:59 +08:00

5.5 KiB
原始文件 Blame 文件历史

生产部署执行与验收:设计说明

1. 设计边界

这是一次受控运维执行,不是新的产品开发。已归档的 08-08-production-deployment-validation 提供部署 tooling、target gate、迁移 reconciliation 和报告脱敏实现;本 task 只负责在明确批准的生产窗口调用它们、读取结果、分流失败并形成证据。

不修改应用代码、Prisma schema、生产环境变量或业务数据模型。若运行中发现实现缺陷,保留现场并另建 task,不在部署窗口临时修复。

2. 状态序列与硬门禁

候选发布来源
  -> 上游/工作区/13 项部署体检
  -> 生产 target identity(只读)
  -> Prisma pre-status + _prisma_migrations 对账(只读)
  -> terminated 行数与 rollbackWindow(只读)
  -> 变更冻结确认
  -> deploy-existing(唯一允许的迁移/发布写入)
  -> post-status(只读)
  -> /ready、SHA、smoke、权限负向(只读)
  -> 证据收口 / PAUSED 分类

每一条箭头都是 fail-closed 闸门。任何闸门失败都不得执行下一步;特别是 pre-status、窗口判定和权限负向检查必须先于任何真实终止写入(本 task 不执行该写入)。

3. 候选来源与发布授权

  • 先在本地完成 task 规划提交,使工作区 clean;再以明确的已提交 commit 作为候选。
  • 运行 check-source-provenance.mjs,要求候选 commit 已进入配置的上游远端且 remote verification 为 true。
  • deploy-existing.sh 拒绝 DEPLOY_ALLOW_UNPUBLISHED_COMMIT 和 DEPLOY_UNPUBLISHED_REASON;不得通过环境变量绕过。
  • 当前只读发现本地发布线领先远端,因此“是否将精确候选发布到上游”是执行前唯一外部授权问题。未获批准时停在 planning/PAUSED,不连接生产。

4. 目标身份与迁移读取

deploy-existing.sh 从受控 systemd unit 读取六个部署合同值,不从 Compose 标签猜路径或 SSH 身份。它先执行既有聚合体检,再将合同值和运行时输入传给 production-preflight.mjs。

远端 helper 的顺序固定为:

  1. 比较 APP_ORIGIN、POSTGRES_DB、NODE_ENV、COOKIE_SECURE 与执行时 hash 输入;拒绝 HTTPS 以外、回环、本地回归库和 staging/trialrun 身份。
  2. 检查唯一 server/db 容器、运行时 DATABASE_URL host/database 和当前数据库名。
  3. 执行 npx prisma migrate status,在 marker 内输出原始结果。
  4. 只读查询 _prisma_migrations,计算 applied、异常和 pending 集合,与候选 manifest 和批准 allowlist 精确对账。
  5. 查询 contract_registry 的 terminated 行数并输出 rollbackWindow=OPEN|CLOSED。

status 原文仅存在受控 SSH/执行现场;本地 helper 写入 prisma-migrate-status.txt 时去除 datasource、连接串和预期身份值,并将稳定摘要写入 preflight-output.txt。报告目录复用时只删除两个已知文件,防止旧 PASS 污染新证据。

5. 发布与 post gate

只有 target/pre-status/窗口/冻结全部通过,才调用:

DEPLOY_SERVER=<受控目标> \
DEPLOY_REFRESH_SERVER=<受控刷新目标> \
EXPECTED_PRODUCTION_ORIGIN=<进程输入> \
EXPECTED_PRODUCTION_DB_NAME=<进程输入> \
EXPECTED_PENDING_MIGRATIONS=<明确 allowlist> \
bash deploy/trialrun/deploy-existing.sh

包装器固定 SYNC_ENV=0、DEPLOY_DATA_MODE=existing 和 DEPLOY_STATUS_OUTPUT_MODE=quiet。deploy.sh 内部的 prisma migrate deploy 是本 task 唯一允许的 schema 写入;不允许 seed、业务 API 写入、reset、resolve 或手工 DDL。

部署后 helper 以空 pending allowlist重新执行 target/status/reconciliation,要求 schema up to date;随后才执行 refresh 和只读 readiness。refresh 失败分类为 DEPLOYED_BUT_CONTRACT_REFRESH_FAILED,不重复发布应用。

6. 回滚窗口

部署前查询 SELECT count(*) FROM contract_registry WHERE status = 'terminated':

  • 0 → rollbackWindow=OPEN;应用健康失败可按既有发布合同回退兼容版本,但不得 drop 三列。
  • >0 → rollbackWindow=CLOSED;旧应用不识别 terminated,只能 roll-forward 或兼容 hotfix。

窗口在第一条已提交记录产生的事件时刻关闭,不按时间计算。当前 task 不写入该记录,因此不主动改变窗口状态。任何 rollback 决策必须引用部署前实际读数,而不是部署后补查。

7. 证据与失败分流

阶段 成功证据 失败处理
来源/13 项体检 commit、published/remoteVerified、13 项 PASS 计数 停止,不 SSH 写入
target/pre-status/窗口 原始受控输出引用、脱敏副本、pending/异常计数、窗口状态 PAUSED,不进入 deploy
migrate deploy deploy wrapper 返回、候选 migration ID 保留现场,不 reset/resolve/drop/重复部署
post-status/readiness applied、schema up to date、/ready/SHA/smoke 按窗口状态决定回退或 roll-forward
refresh exact forced-command PASS DEPLOYED_BUT_CONTRACT_REFRESH_FAILED,只修复合同

缺少生产凭据、真机或公网条件的项目必须标 PAUSED/SKIP,不能转写为 PASS。所有结果都要记录“是否发生真实业务写入=否”。

8. 只读复核与收口

本任务涉及生产部署、迁移和回滚规则,实施后启动只读 reviewer;reviewer 只检查门禁顺序、原始/脱敏证据、失败分流和回滚窗口,不修改代码或生产状态。最终只有在所有获批生产、公网和必要真机检查通过时才可告知用户可以测试,否则保留 PAUSED。