文件
hyb-oa/.trellis/tasks/08-23-isolated-backup-restore-drill/prd.md
T
wangsli和Claude Sonnet 5 5be9f44445 回填隔离备份恢复演练执行记录 [08-23-isolated-backup-restore-drill]
从孤儿 worktree(artifacts/isolated-worktrees/20260909-ops-preparation、
20260910-reimbursement-payment-integration)合并回填两轮从未提交的真实
执行记录:

- 2026-09-09 ARM 管理员会话完成首次隔离数据库恢复,回执 DB_RESTORE_PASS,
  66 项迁移精确匹配、12 类关键表可读。
- 2026-09-11 第二次配对恢复,AC1/AC3/AC6 勾选完成;对发票池一条历史缺失
  附件做 SHA-256 比对、来源元数据核对、生产/ARM 归档/周检查点全量搜索,
  均未命中,按用户决定非破坏性标记、暂不追查(AC4 仍未过)。

无产品代码改动,无生产/ARM 操作;仅补齐 Trellis 任务文档与既有证据记录,
使 in_progress 状态反映真实已发生的执行历史。

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-25 19:45:18 +08:00

18 KiB

隔离备份恢复演练

2026-09-09 最小验真阶段(本地准备已批准,远端执行另批)

用户批准综合规划开始本地实施。本 task 不再把安装器/固定 runner 的完善当作下一次数据库恢复验真的前置;新增受控管理员人工最小路径。只在既有授权通道操作,不能以“不用 sudoers”解释为绕过现有读取权限。未收到本次 ARM 真实备份恢复授权,本轮不连接远端。

本阶段数据库结果和配对附件结果分开:数据库退出 0、来源 migration 与关键表检查通过,才可记 DB_RESTORE_PASS;附件未执行记 STORAGE_NOT_TESTED;不启动应用,不宣称应用或完整灾备 RTO 已验证。原整体 Goal、数据库/附件 AC 和历史 NO_GO 保留;最小阶段通过不自动勾选原整体 AC。原 runner 渲染/安装及分段 RTO 不作为本次最小阶段新增工程前置,仅适用于保留的正式演练合同。

保留生产零写入/零重启、影子目标确认、无宿主端口、批次来源与24小时新鲜度、配对摘要、敏感输出限制、非零失败关闭及本轮精确清理。若本地脚本在实际最新批次上失败,保留脱敏诊断并停止;不得现场放宽条件、转用旧批次或自动重试。Attempt 3 底层原因仍未知,不追认所有失败均为工具问题。

2026-09-11 本轮执行口径

用户认可在当前无业务关联、影响较低的前提下删除或标记。选择非破坏性标记:复核仍为 archived/manual、原件缺失且无当前业务关联后,在现有任务/恢复缺口记录登记"已知历史附件缺失,保留记录,暂不继续追查"。当前票据接口不允许编辑 archived 记录,不为添加备注绕过状态守卫改库,不新增缺失状态或删除记录。"可能是测试数据"仍是推测,不写成已确认事实。此处置不把恢复 AC4 改为通过,不改校验器、不排除缺失项,也不自动授权部署。

该处置已完成:再次只读核对无当前报销/明细/差旅及同路径附件/回单关联,记录和源文件缺失状态未变;已在本 task 和恢复证据中标记,生产数据保持原样。按用户决定暂不追查,不阻塞其他业务开发/验收;技术恢复仍如实记录 1 条附件引用缺失,发布例外及独立复核不由该标记替代。

用户批准对此前明确提供的单份发票 PDF 读取字节计算 SHA-256,并与唯一缺失记录登记的文件摘要、大小比对。不展示文件内容或原始文件摘要,不遍历 input 目录、不读其他文件,不上传原件、不补回或改生产。只读返回匹配/不匹配;匹配不代表原件已补回、备份已更新或恢复已通过,不匹配则停止,不自动扩查。

本次单文件比对已执行:大小和 SHA-256 均不匹配,不能将它补作登记原件。已按约定停止搜索,未补文件、改库或部署;不推断 PDF 业务内容必然不同。当前仍保留单条历史附件缺失,恢复 AC4 未通过;后续需新的明确原件线索或另批缺失处置方案,不重复恢复或自动扩大搜索。

用户另行批准只读核对唯一缺失记录的创建/归档来源元数据。本轮只定位既有记录 SHA-256 与路径 SHA-256,查询该行的时间、状态、归档原因枚举、创建/上传/更新身份关系布尔值及必要技术元数据;不读取人员账号、个人访问历史、审计 payload、票据正文、金额、备注或银行字段,不改数据。结合本地已发布源码解释字段含义;没有确证不得归因为测试数据或手工删除。

此元数据核对已完成:记录创建于 2026-07-27,约 9 分钟后标记 manual 归档,PDF 技术类型,存有 mock OCR 处理记录;当前无报销/明细/差旅关联。没有读取 OCR 结果或文件内容;不因 mock 或手工归档标记认定为测试数据,也不推断是谁删除了文件。来源入口与缺失原因仍未证实,AC4 未通过;后续内容摘要比对必须单独明确读取范围,任何修复仍另批。

用户进一步批准围绕该唯一缺失引用,只读查历史备份目录项和文件元数据以寻找原件。仅在已有生产/ARM 管理渠道可读的正式备份目录内做有界搜索,按已记录的规范化路径 SHA-256 匹配;不读票据正文、不恢复数据库、不解包落盘、不补文件或改引用。找到目录项只算候选原件,内容一致性与可恢复性仍须另验;权限拒绝、覆盖范围不足和未命中必须分开,不以未找到推断永久丢失。

该限定搜索已完成:生产 7 份、ARM 日归档 7 份及周检查点 4 份均未命中;ARM 另 1 个非规范目录项未纳入,不能称为所有历史备份都已检查。管理员已执行且主会话 SSH 回读结果,不再等待该次密码或执行。缺失引用未修复,AC4 继续未通过,不扩大为永久丢失或测试数据结论。

第三次诊断已确认发票池 1 条引用缺文件。用户另行批准生产侧限定只读核对:最小引用/关联状态和源文件存在性,可对照已固定附件归档目录项;不读票据正文、金额或银行资料,不改数据或生产配置。此限定读取是下文历史"生产仅健康探测"范围的显式补充,不授权恢复生产或修复记录。

用户已同意继续做 ARM 一次性 DB+附件隔离配对恢复;不是生产恢复或发布授权。本轮复用已有 shadow 恢复脚本,以一次管理员终端操作完成前置验证、临时恢复、校验与清理,不再安装历史 runner、sudoers 入口或增加分段计时装置。按原 R1–R4 保留输入身份、时效、隔离、迁移和附件配对边界,R5 记录总耗时与安全失败阶段即可。实际配对恢复已执行:DB 通过、附件引用失败,清理完成;不以本地合成通过替代,也不原样重跑已知失败过程。

固定输入来自今日最新源端校验通过的 fe025e65 备份;若执行时 ARM 最新批次、manifest、来源 build/image 或现存 PostgreSQL 镜像变化,暂停刷新证据,不自动取旧批次或拉镜像。恢复不启动 OA 应用,app 必须标 NOT_TESTED;镜像回退和 DB/附件恢复仍是不同能力。09-09 管理员回传的最小 DB_RESTORE_PASS 已有效记录,不再沿用"从未成功恢复数据库"的旧结论。

Goal

在不覆盖、不暂停腾讯云生产 OA 的前提下,使用 ARM 备份机上最新的完整异机批次完成一次数据库与附件的隔离影子恢复,证明“备份存在”进一步达到“最新成对数据备份可恢复”,并记录实测数据恢复 RTO、RPO 和脱敏证据。

Scope

  • 在 ARM 上选择并校验最新正式日归档,使用本轮临时副本恢复数据库与附件。
  • 验证 migration、固定关键表、附件数量与 DB/附件引用一致性,记录数据恢复 RTO/RPO。
  • 复核生产前后 /ready、ARM 监控状态和临时对象清理结果,形成当前 task 内脱敏证据并更新既有事实源摘要。
  • 不修改产品运行代码;允许把演练 runner 模板、附件校验器和可复跑合同收敛到 scripts/qa/。生产、正式归档、企业微信和现有监控均保持只读或零变更。

Background

  • 腾讯云服务器是真实 OA 生产;ARM 只承担异机备份、外部健康监控和受控恢复演练,不是 OA 生产服务器。
  • 2026-08-23 只读复核确认:生产最近 14 天每日异机备份和新鲜度 watchdog 均成功,ARM dead-man 最近成功;企业微信中的“恢复通知”来自公网健康状态恢复,不代表执行过数据恢复。
  • 2026-07-27 曾在 ARM 使用当时的正确异机批次完成真实格式影子恢复,但不能替代对当前最新自动备份的可恢复性验证。
  • 首次演练时生产产品构建为 7b86ffb,已通过公网 /ready 和 migration pending=none;当时仓库与来源构建 ec682565 均有 65 个 Prisma migration 目录,二者之间 migration 目录无变化。该数字是本次现场事实,不再作为跨构建硬编码合同。
  • 现有恢复脚本默认只接受带 shadow、drill 或 restore_test 标记的数据库名,并拒绝生产式目标、确认值不一致、非空附件目标和危险归档路径。

Requirements

R1. 恢复点选择与前置门禁

  • 只选择 ARM 正式日归档中按 UTC 时间最新的一个完整批次,不触碰 inbox、临时事务目录、旧错误批次或周检查点。
  • 批次必须恰含 database.dump、storage.tar.gz、manifest.json 三个普通文件;manifest 必须为 schema v1、complete,相对文件名、字节数、SHA-256 和来源构建身份全部一致。
  • 批次年龄必须不超过 24 小时。manifest buildSha 必须唯一解析为本仓库已知提交,且该提交是演练开始时公网 /ready 实测当前构建的祖先或与其相同;未知提交、旁支/后继提交、超龄、损坏或文件集歧义判定 NO_GO,磁盘空间不足判定 PAUSE。两者都不得自动改选更旧批次掩盖问题。
  • 构建相等只表示“当前发布后已经形成同源恢复点”,不再作为数据备份可恢复性的必要条件。若来源是当前构建的祖先,必须单独记录发布后同源恢复点滞后 finding,不能把它误报为归档损坏。
  • 执行前后各做一次公网 /ready 只读检查,仅用于证明生产未受影响;该结果不得充当影子恢复后的应用启动证据。

R2. ARM 隔离和数据保护

  • 演练仅在 ARM 上创建本轮专属、权限 0700 的临时工作区、一次性 PostgreSQL 16 容器和空附件目录;不得在开发机下载真实备份。
  • PostgreSQL 不发布宿主端口,不加入现有 OA/监控网络,不复用任何现有容器名、数据库名、volume 或目录;影子数据库名必须含 drill 标记。
  • 先把所选批次复制到临时工作区并重新校验 manifest 与三文件 SHA-256,再对临时副本执行恢复;正式 ARM 归档始终只读,不直接解包或改名。
  • 不读取或复用生产 .env、JWT、Webhook、企业微信 Secret、真实数据库口令或业务账号;影子数据库只使用本轮随机临时凭据,凭据不进入聊天、仓库、报告或命令参数证据。
  • 含现场路径、命名或构建值的私有渲染 JSON 和渲染后候选不得进入 Git 历史;若位于仓库内,必须置于专用 ignored 目录,合同脚本须在创建候选前机械验证该 ignore 状态,未忽略即失败关闭。

R3. 数据库恢复验证

  • 使用现有 scripts/restore-db.sh 的 RESTORE_SCOPE=shadow 和精确数据库名确认门禁,将最新 database.dump 恢复到一次性 PostgreSQL 16 容器。
  • pg_restore --list 和实际 restore 必须成功。从 manifest 来源提交动态冻结其 Prisma migration 目录集合;恢复后 _prisma_migrations 中成功且未回滚的 migration 名称必须与该来源集合一致,并且不存在失败、回滚中或来源未知的 migration。不得用硬编码数量替代集合核对。
  • 同时比较来源提交与当前构建的 migration 目录集合:集合相同则记录“当前 schema 无额外升级步骤”;当前构建新增 migration 时,原始备份恢复仍可继续验证,但“升级到当前 schema”标为 PAUSE/未验证,另行设计仅针对影子库的 migration 演练,不在本轮临时执行。
  • 固定核对组织、人员、角色、采购、报销、发票池、付款批次、合同、项目及三类核心附件表的存在性和行数;只记录表名、数量和 PASS/FAIL,不记录业务字段或正文。
  • 所有验证 SQL 必须只读并开启错误即停;不执行 migration、seed、DDL、数据修补或业务写入。

R4. 附件恢复与关联验证

  • 使用现有 scripts/restore-storage.sh 的 shadow 门禁恢复 storage.tar.gz 到本轮空目录;归档路径、链接类型和目标空目录检查必须通过。
  • 归档普通文件数必须与解包后普通文件数一致;对数据库中本地存储型的发票、采购附件、报销附件、付款回单和请假附件引用,验证相对路径安全、目标文件存在,并在已有 SHA-256/大小字段时核对哈希或大小。
  • 发现 s3: 引用、缺失文件、路径逃逸、哈希/大小不一致或 DB 与附件批次不配对时判定 NO_GO;不输出文件名、原始路径、票据内容或附件内容。

R5. 计时、证据和清理

  • RPO 定义为演练开始 UTC 时间减 manifest createdAt;必须小于等于 24 小时才通过。本次实测值只用于当前恢复演练,不形成 SLA 承诺。
  • “数据恢复 RTO”从通过前置门禁后、开始复制批次到临时工作区之前计时,到 DB/附件恢复和全部数据一致性检查通过时结束;不得把历史合成演练耗时或生产 /ready 计入本轮 RTO。
  • 另行记录“同源恢复点可用滞后”:当前发布合同刷新时间到首个相同构建的 ARM 完整批次到达时间。该指标与数据 RPO、数据恢复 RTO 分开,不形成 SLA;即使恢复未执行,观测到的发布后空窗仍是有效演练发现。
  • 证据写入当前 Trellis task,只记录日期、角色、批次脱敏标识、构建短标识、年龄、耗时、数量、状态、finding 类别和清理结果;不保存远端地址、完整目录、凭据、真实账号、业务正文或原始 payload。
  • 成功或失败后只清理本轮明确创建的一次性容器、临时工作区和临时凭据;清理后确认无容器、端口、临时目录残留。任何目标身份不明确时停止清理并人工复核,绝不删除正式归档。

Acceptance Criteria

  • AC1:ARM 最新正式日批次通过文件集、manifest、字节数和 SHA-256 校验,来源构建是当前构建的祖先或相同,且实测 RPO 不超过 24 小时;是否已形成当前构建同源恢复点单独记录。2026-09-11 第二次配对执行已证同源 fe025e65、约 9.97 小时;不代表未来批次自动通过。
  • AC2:腾讯云生产在演练前后 /ready 均正常,生产容器、数据库、附件、配置、timer 和业务数据零写入、零重启、零切换。
  • AC3:一次性 PostgreSQL 16 影子库无宿主端口,数据库恢复成功;恢复 migration 集合与 manifest 来源提交一致且无失败/未知项,来源与当前 migration 差异已明确;固定 12 类关键表均可读并形成仅含数量的脱敏摘要。2026-09-11 第二次配对执行:68 条迁移集合/摘要匹配、异常 0、12 类表通过;附件失败不抹掉此项实证。
  • AC4:附件安全恢复成功,归档与解包普通文件数一致;所有纳入范围的本地附件引用均安全且存在,适用的哈希/大小核对无不一致。
  • AC5:记录本轮数据恢复 RTO、RPO、同源恢复点可用滞后、开始/结束时间、失败点或 finding、Go/Pause/No-Go 结论;即使恢复未开始也保留已观测空窗,不把任何指标表述为完整应用灾备 RTO 或 SLA。
  • AC6:演练结束后本轮容器、端口、网络和临时数据全部清理,ARM 正式归档与现有 dead-man/健康监控不受影响。2026-09-11 第二次配对执行已清理,源归档摘要与 timer 未变;后续新运行须重新核验。
  • AC7:任务校验、Trellis 治理、流程合同、文档审计、敏感扫描和 git diff --check 通过;证据不含敏感信息。

Out of Scope

  • 不在腾讯云生产执行 restore、停机、重启、数据库 reset、migration、DDL、seed、配置修改、timer 修改或业务写入。
  • 不触发新的生产备份,不删除、替换或轮转 ARM 正式归档,不发送企业微信测试消息。
  • 不把真实备份下载到开发机,不把 ARM 变成 OA 部署目标或长期运行 OA server。
  • 本轮不启动隔离 OA 应用容器、不做登录、报销详情或附件下载页面验证,也不对恢复库执行 Prisma migration;因此只形成“原始数据恢复 RTO”和静态 migration 兼容判断,完整应用恢复、schema 升级和切换 RTO 仍需未来灾难恢复专项验证。
  • 不修改备份/恢复产品代码;若现有脚本在真实最新批次上暴露缺陷,先停止并另行回到规划,不现场放宽安全门禁。

Blocking Open Questions

  • 单条历史缺失已按用户决定完成非破坏性标记,来源未证实但暂不继续追查;不再等待其处置授权或管理员密码。实际附件恢复仍未全部通过,不自动改为完整恢复成功。若未来需要修复或生产恢复/部署,仍需对应明确范围与授权。

Test Plan

  • 校验最新批次 manifest、三文件集合、字节数、SHA-256、构建身份和 24 小时新鲜度。
  • 通过现有 shadow 恢复脚本完成 PostgreSQL 16 和附件恢复,验证来源提交的 migration 集合、与当前构建的 migration 差异、固定 12 类表及附件引用聚合。
  • 复核无宿主端口、生产前后 /ready、ARM 监控未受影响和本轮临时对象零残留。
  • 运行 task validate、Trellis governance、process contract、docs registry、敏感扫描和 git diff --check。

2026-09-09 数据库最小恢复执行授权

用户对“通过ARM既有合法管理员通道,核对当时最新正式备份,在一次性隔离PostgreSQL中执行数据库恢复、检查结果并清理本轮临时资源”明确回复“是”。本次只批准数据库,不解包附件、不启动OA、不触碰生产、不改权限或sudoers、不删除正式备份。权限不足或恢复失败停止并报告;不需再次征询同一范围的授权。

最初代理非交互管理员通道检查未通过;随后用户通过既有 root 交互会话执行获批操作。2026-09-09 管理员回传本批次 DB_RESTORE_PASS、66 项 migration 集合匹配、12 类关键表可读和本轮资源清理完成。该结果并非代理独立远端验证;附件与应用仍未验,整体任务保持未完成。详见 research/restore-drill-evidence.md 同日记录。