规划报销费用门禁生产部署(08-30-reimbursement-expense-policy-invoice-guard-deploy)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-08-30 00:38:46 +08:00
父节点 d38d33fbb0
当前提交 faf1a0cff9
共修改 8 个文件,包含 316 行新增和 5 行删除
@@ -31,8 +31,8 @@
## 5. 验证与上线
- [x] 执行 PRD Test Plan 和 Trellis quality gate,做权限/状态/历史草稿/flag 回退专项复核。
- [ ] B1 部署前明确与 `BX-20260828-0017` 的业务处置顺序;建议先完成该单退回、正式 PDF 重传和重提,避免停用 `assets_it_hardware` 与新增事前批准依据门禁叠加。
- [ ] B1 部署前只读核对生产 draft/rejected 报销中是否仍有其他 assets 明细,并据实制定逐单处置,不批量伪造事前批准依据。
- [x] B1 部署与真实单据处置顺序已调整:先部署 B1、隔离验证并启用 B2,再由真实财务统一退回 `BX-20260828-0014/0016/0017/0018`,避免员工在无系统指引时重复返工。
- [x] 已只读核对生产存量:除审批中的 4 张单据外,没有 draft/rejected assets 明细会被 B1 新校验拦住;不得批量伪造事前批准依据。
- [ ] 首次部署只启用 B1;B2 保持关闭,完成 owner 基线和无票补助验证。
- [ ] B2 开启必须单独获得生产配置批准;先专用账号/部门灰度,再按证据决定全局。
- [ ] 关闭 B2 后复核旧提交路径恢复且关联数据未被删除或解绑。
@@ -52,4 +52,4 @@
- Trellis task validate、governance、process contract、docs registry audit 和 `git diff --check` 通过;docs audit 保留既有的 `22` 个未注册文件 warning,exit 0。
- 权限、migration、feature flag、历史兼容和 seed 科目保护已完成三轮只读专项复核,最终 PASS。复核发现并推动修复:pending OCR 关联丢失、flag-off 纯无票补助服务端门禁、PC 无票补助主操作投影。
- 未部署 B1、未应用生产 migration、未开启 B2、未做真实数据写入;本 task 保持 `in_progress`,上线与 B3 交接项不得提前勾选。
- 新增部署排期门:`BX-20260828-0017` 当前使用即将停用的 `assets_it_hardware`。部署前需明确先处置该单还是先上 B1;当前建议先让该单按原口径完成退回、正式 PDF 重传和重提,并只读扫描其他存量 draft/rejected assets 明细。
- 生产只读审计把业务处置范围扩大为 4 张审批中单据:0014 为 5 个发票日期压成 1 条明细且 B2 无法自动拦截;0016/0017/0018 存在未关联票据,0017 另有票面差额。最终顺序改为先部署 B1、隔离验证并全局启用 B2,再由真实财务统一退回,日期粒度继续依赖明确退回说明与人工复核。部署与灰度合同见子任务 `08-30-reimbursement-expense-policy-invoice-guard-deploy`。
@@ -18,7 +18,9 @@
"commit": "6e999d5",
"pr_url": null,
"subtasks": [],
"children": [],
"children": [
"08-30-reimbursement-expense-policy-invoice-guard-deploy"
],
"parent": null,
"relatedFiles": [
"server/prisma/schema.prisma",
@@ -33,6 +35,6 @@
"docs/报销发票附件规则.md",
"docs/需求-报销发票OCR规约.md"
],
"notes": "本地实施和只读专项复核已完成;B2 env/DB 双闸仍默认关闭,未部署、未应用生产 migration、未写生产配置。2,000 元/条明细的选类提示阈值已批准。会计科目映射由财务负责人在 B1 生产启用前提供,目标回填日期 2026-09-05;未取得正式科目表时保持 null,不由开发人员猜测。B1 部署前必须决定与 BX-20260828-0017 的处置顺序,并只读核对其他存量 draft/rejected assets 明细;当前建议先完成 0017 退回、正式 PDF 重传和重提。B3 财务一页式及行内费用标准提示恢复仍为后续任务。",
"notes": "本地实施和只读专项复核已完成;B2 env/DB 双闸仍默认关闭,未部署、未应用生产 migration、未写生产配置。2,000 元/条明细的选类提示阈值已批准。会计科目映射由财务负责人在 B1 生产启用前提供,目标回填日期 2026-09-05;未取得正式科目表时保持 null,不由开发人员猜测。生产只读审计确认 0014/0016/0017/0018 均需退回修正;顺序改为先部署 B1、隔离验证并启用 B2,再由真实财务统一退回。B2 不校验日期粒度,0014 必须按 5 个发票日期拆分并由财务人工复核。部署合同见子任务 08-30-reimbursement-expense-policy-invoice-guard-deploy。B3 财务一页式及行内费用标准提示恢复仍为后续任务。",
"meta": {}
}
@@ -0,0 +1,87 @@
# 设计:报销费用政策与票据门禁生产部署
## 发布边界
本任务不再修改业务代码。候选包含父任务业务提交 `6e999d5` 和本部署合同;规划文档提交完成后以最终干净 `HEAD` 冻结,并在外部审批记录写完整 SHA 与 12 位 bundle marker。当前生产 `59dc5f6` 是固定应用回滚基线。
生产切换分为三个独立状态:
```text
B1 部署:新 schema + 主数据 + 表单合同
env hard gate = off(或 env on 但 DB force_off)
DB flag = force_off
B2 effective = false
B2 隔离灰度:同一应用候选
env hard gate = on
DB flag = force_on + department_allowlist + 隔离空部门
B2 只对 smoke employee 生效
B2 全局启用:同一应用候选
env hard gate = on
DB flag = force_on + global
B2 对全局提交生效
```
任何状态跃迁都必须先完成上一状态的验收,并取得对应生产授权。
## 验收身份与数据隔离
- admin smoke:只用于系统设置、非参与人视图和 flag 操作,不代行财务审批。
- employee smoke:从当前 5 人部门迁入已确认零成员的隔离部门,建立合成草稿并验证 owner 合同;终态常驻该部门,不再迁回。
- manager smoke:新建 manager + employee 的 OA-only 专用身份并设为 employee smoke 的直属 manager。普通 employee 没有直属 manager 时,提交会被 `no_manager_found` 阻断,不会走 finance fallback。
- finance smoke:新建 finance + employee 的 OA-only 专用身份,放入隔离部门,用于财务只读投影;不恢复已消失旧账号,不绑定真人身份。
- 真实 finance:仅负责 4 张真人单据的业务退回和重提复核,凭据不交给自动化。
合成材料必须是无真实抬头、号码、账户和业务正文的测试 PDF/图片。成功提交的合成单据通过 owner 撤回回到草稿再删除;阻断场景直接删除草稿。审计记录保留。
## Migration 与 seed
唯一 migration:`20260829120000_reimbursement_expense_policy_invoice_guard`。
- migration 新增向前兼容列并回填两项免票类型。
- `seed:config` 落地费用类型改名、停用、新建、description、requires_invoice 和 B2 DB `force_off` 初值。
- seed 更新路径不写 `account_code_default`,部署前后须按 code 对比,防止既有财务映射丢失。
- deploy init 同时运行 `seed:trialrun`,因此 pre/post 证据必须覆盖 migration 与主数据,而不能只看 `_prisma_migrations`。
## B2 配置数据流
生产环境不由 `SYNC_ENV=0` 自动同步。正确顺序为:
1. B1 init 后确认 DB flag 记录已由 seed 显式创建为 `force_off`,不得接受 `missing_flag_record`,并保存完整快照。
2. 经生产配置授权把 env hard gate 设为 true,重启同一候选。
3. 验证 `envEnabled=true`、`effectiveEnabled=false`、reason=`flag_force_off`。
4. 经灰度授权把 DB 更新为 department allowlist,仅含隔离部门。
5. 执行合成验证;失败恢复调用前快照,优先 `force_off`。
6. 灰度 PASS 后,经全局授权更新为 global force_on。
flag 更新使用 API 的 expectedVersion 并发控制并自动写审计。关闭 flag 只改变后续行为,不删除已建立的关联。
门禁状态证据使用精确 reason:`env_hard_off` → `flag_force_off` → 名单外 `department_not_allowed` / 隔离部门 `flag_force_on_department_allowed` → 全局 `flag_force_on_global`。普通 flag 列表无法按 actor 完成 strict department 判断,须在受控容器内调用同一 evaluator 做只读诊断,并与详情 DTO 的 `invoiceGuardEnabled` 交叉核对。
## 真实单据处置
B2 全局启用后再退回 4 张真人单据,使员工只重做一次并获得系统关联/金额提示。日期粒度仍由退回说明与财务人工复核承担:
| 单号 | 系统可拦 | 人工要求 |
| --- | --- | --- |
| 0014 | 否 | 5 个日期拆 5 条明细,重提后人工确认 |
| 0016 | 未关联票据 | 至少按 3 个日期拆分并逐票关联 |
| 0017 | 未关联、超票面 | 2 个日期重做、正式 PDF、差额说明 |
| 0018 | 未关联票据 | 修正日期;同日同类可保留一条 |
已付款 0008 与空草稿 0013 不进入处置动作。
## 回滚与补偿
回滚分三层,不能混用:
1. B2 行为异常:DB flag 立即 `force_off`,关联数据保留。
2. 应用异常:确保 B2 off,使用 existing 入口回滚到 `59dc5f6`;不逆 migration。
3. B1 主数据错误:应用回滚不会恢复 seed 结果。只在单独批准后,依据部署前快照对受影响 code 做精确补偿;不执行整库 restore,不删除新增类型或历史外键。
回滚后重复 build、migration status、runtime/external smoke、挂载、备份合同与公网入口检查。
## 证据与隐私
报告只保存 PASS/FAIL、SHA、migration 名、类型 code/状态、flag 状态、合成标识和计数。不得保存密码、token、完整账号、真实票据、姓名、业务正文或原始 API payload。材料预览只记录页数、页序和比例,允许保留系统生成的审计记录。
@@ -0,0 +1,82 @@
# 实施清单:报销费用政策与票据门禁生产部署
## 1. 规划与冻结
- [ ] PRD、design、implement 经用户审查并明确批准进入实施。
- [ ] 本规划提交完成后确认工作区完全干净,以最终 `HEAD` 冻结候选;外部审批记录写死完整 SHA 与 12 位 bundle marker。
- [ ] 冻结后无任何提交、修改或 untracked 文件;发生漂移则重新冻结、重新审查。
## 2. 验收准备(独立生产写入授权)
- [ ] 再次只读确认隔离部门零真人成员,把它固定为常驻 smoke 部门。
- [ ] 新建 OA-only manager smoke(manager + employee)与 finance smoke(finance + employee),凭据写入私有 smoke env,不输出、不绑定真人。
- [ ] 把 employee smoke 迁入常驻 smoke 部门,将 manager smoke 设置为其直属 manager;先用合成空壳草稿确认 workflow 可分配,再创建明显标识的合成历史草稿和非真实票据/附件。
- [ ] 明确授权材料合并预览产生设计内审计记录;真实材料不落测试报告。
## 3. Push 与来源门禁
- [ ] 用户单独批准 push;只推送冻结候选所在 `main`。
- [ ] 确认 `origin/main` 等于或包含候选,严格 provenance PASS,`published=true`、`remoteVerified=true`、`overrideUsed=false`。
- [ ] push/provenance 不推定部署、配置或业务写入授权。
## 4. B1 部署前门禁
- [ ] 用户在 provenance 通过后单独批准 B1 部署。
- [ ] `check-existing-deployment.sh`、生产 identity、existing 数据/附件挂载和备份合同均 PASS。
- [ ] init 前显式记录 Prisma status,pending 只能是 `20260829120000_reimbursement_expense_policy_invoice_guard`。
- [ ] 保存受影响费用类型 code/name/enabled/description/category/account_code 的脱敏快照;记录 B2 env/DB flag 调用前状态。
- [ ] 部署前记录 B2 flag 是否尚不存在;不得把缺失解释为最终关闭合同。若记录已存在则必须为 `force_off`;若 env hard gate 已提前获批设为 true,必须证明 effective 仍为 false。
## 5. B1 正式发布
- [ ] 使用 `deploy-existing.sh`、existing 模式、`SYNC_ENV=0` 执行 migration、seed 和应用切换。
- [ ] init 后显式记录 migration status;核对新增列、两项免票、其余启用类型需票、费用类型改名/停用/新建和 account code 保留。
- [ ] 核对 B2 DB flag 记录明确存在、override=`force_off`、reason 不为 `missing_flag_record`;缺失立即阻断,不继续 B1 验收。
- [ ] `/ready`、12 位 bundle marker、runtime/external smoke、服务状态和备份合同 refresh 全部 PASS。
- [ ] B2 effective off;owner 普通维护、assets 批准依据、2,000 元提示、无票补助和非参与人只读投影 PASS。
- [ ] admin/finance/employee 角色化公网验收 PASS;材料合并预览页序/比例正常并只产生获批审计。
## 6. B2 env hard gate(独立生产配置授权)
- [ ] 保存 env/flag 快照,确认 DB `force_off`。
- [ ] 将生产 `REIMBURSEMENT_INVOICE_GUARD_ENABLED=true` 写入受控 env,重启同一候选,不同步其他 env。
- [ ] 验证 env on、DB force_off、effective off 且 reason=`flag_force_off`;失败则恢复 env 快照并重启。
## 7. B2 隔离灰度(独立 flag 授权)
- [ ] 用 expectedVersion 把 flag 更新为 `force_on + department_allowlist + 隔离部门`;受控容器内只读诊断确认隔离部门 reason=`flag_force_on_department_allowed`、名单外 reason=`department_not_allowed`,并与详情 DTO `invoiceGuardEnabled` 交叉核对。
- [ ] 合成验证 owner 普通提交成功。
- [ ] 合成验证两项无票补助不被阻断。
- [ ] 合成验证多票显式关联成功。
- [ ] 合成验证申报金额高于票面时准确阻断。
- [ ] 合成验证旧草稿补齐关联/批准依据后可提交。
- [ ] 合成验证 admin/finance 非参与人无法写入且零业务副作用。
- [ ] 切回 `force_off` 验证旧提交路径恢复、既有关联不删除不解绑,再恢复灰度快照继续最终判断。
- [ ] 任一失败立即恢复调用前 flag 快照,至少先落 `force_off`;不操作 4 张真人单据。
## 8. B2 全局启用(独立授权)
- [ ] 灰度七项全 PASS,成功合成单据已撤回并删除,失败草稿已删除;审计历史保留。
- [ ] 用户单独批准 global enable;用 expectedVersion 更新为 global force_on。
- [ ] 验证全局 effective on、reason=`flag_force_on_global`、owner 基线、非参与人只读、错误提示、runtime 指标和审计记录。
- [ ] employee/manager/finance smoke 常驻隔离部门,确认部门仍无真人成员;不再执行迁回写入。
## 9. 四张真实单据退回与重提
- [ ] 由真实 finance 退回 0014:说明“5 个发票日期拆成 5 条明细”,重提后人工确认。
- [ ] 由真实 finance 退回 0016:至少按 3 个日期拆分并逐票关联。
- [ ] 由真实 finance 退回 0017:按 2 个日期重做、从发票入口上传正式 PDF、逐票关联并解释 1,949.81 元差额。
- [ ] 由真实 finance 退回 0018:修正日期并逐票关联;同日同类可保留一条。
- [ ] 0008 已付款只留历史关联缺口;0013 空草稿不改。
## 10. 失败与回滚
- [ ] 切换前失败只停止;切换后失败先 B2 `force_off`,再用同一 existing 入口回滚固定应用基线 `59dc5f6`。
- [ ] 不 reset、不逆 migration、不删除关联;主数据问题只凭部署前快照和单独批准做精确补偿。
- [ ] 回滚后复核 build、migration status、runtime/external smoke、DB/附件挂载、备份合同与公网入口。
## 11. 收口
- [ ] 所有生产证据脱敏回填;不保存凭据、真人信息、真实票据或原始 payload。
- [ ] B1/B2 与四张单据处置全部完成后才通知普通用户测试、归档本部署子任务并更新父 task。
- [ ] B3 一页式继续作为独立后续任务;日期粒度自动门禁仍明确不在本轮。
@@ -0,0 +1,107 @@
# 报销费用政策与票据门禁生产部署
## Goal
把已完成并复核的报销费用政策与票据门禁安全发布到生产:先以 B2 有效关闭的状态完成 B1 migration、主数据和 owner 基线验收,再在隔离部门内验证 B2,最后全局启用并让财务统一退回 4 张真实审批中单据。全过程不得拿真人单据做灰度试验,不得因应用回滚误删 migration 或已建立的票据—明细关系。
## Background and Confirmed Facts
- 生产当前运行候选为 `59dc5f6`;本地 `main` 比 `origin/main` 领先 4 个提交,B1/B2 业务实现为 `6e999d5`,尚未推送、部署或应用生产 migration。
- 待应用 migration 固定为 `20260829120000_reimbursement_expense_policy_invoice_guard`,只新增 `expense_types.requires_invoice`(非空、默认 true)、`reimbursement_items.asset_prior_approval_basis`(可空),并把两项补助精确回填为免票。
- init 会运行 migration、`seed:config` 与 `seed:trialrun`;费用类型改名、停用和新建由 seed 落地,不能只核 migration 表。
- B2 是 env hard gate、代码白名单和 DB flag 三件套。生产部署使用 `SYNC_ENV=0`,不会自动把新增 env 写入生产;env 未开启时 DB `force_on` 无效。
- B2 提交门禁只检查:已绑定发票是否关联明细、需票明细是否有关联票面金额、申报金额是否高于关联票面合计。它不自动校验“同一费用类型 + 同一发生日期”的明细粒度。
- 当前 4 张审批中单据均需退回重做:`0014` 票据关联/金额完整但 5 个日期被压成 1 条明细,B2 无法拦截;`0016`、`0017`、`0018` 可被关联或金额门禁拦住,但日期/粒度仍需人工说明和复核。
- 生产现有 admin/employee smoke 可登录,旧 finance smoke 身份已不在 OA 用户表;employee smoke 当前没有自有报销。现有 3 个部门中有 1 个无成员,可在明确授权后作为隔离灰度范围;employee smoke 当前所在部门有 5 个用户,不能直接作为灰度范围。
- 材料合并预览会创建短期进程内预览包并写预览审计记录;这是设计内审计写入,必须纳入验收授权,而不是伪装成零写入检查。
## Scope
- 创建生产验收条件:把现有空部门固定为常驻 smoke 部门,新建专用 OA-only manager/finance smoke 身份,把 employee smoke 迁入并长期保留,建立专用合成草稿和合成票据;凭据只通过私有 env 注入。
- 冻结、推送并严格验证包含 B1/B2 实现与本部署合同的最终候选。
- 使用 existing 部署入口完成 migration、seed、应用切换、构建标识、runtime/external smoke、备份合同刷新和角色化公网验收。
- B1 验收通过后,在 DB 继续 `force_off` 时显式启用生产 env hard gate 并重启同一候选;随后仅对隔离部门开启 B2,验证通过后再全局开启。
- B2 全局开启后,由真实财务角色统一退回 `BX-20260828-0014/0016/0017/0018`;员工按新规则修正并重提,财务人工复核日期粒度。
- 已付款 `BX-20260730-0008` 仅留历史关联缺口记录,不退回、不改付款数据;空草稿 `BX-20260805-0013` 不处理。
## Requirements
### R1 授权与候选冻结
- 规划批准、生产验收准备写入批准、push 批准、生产配置批准、部署批准、B2 灰度批准、B2 全局启用批准和真实单据退回批准互不推定。
- 本次规划文档提交完成后,以最终干净 `HEAD` 冻结候选;具体完整 SHA 和 12 位 bundle marker 记在外部审批记录,不写回仓库。冻结后任何提交、tracked/untracked 变化或 HEAD 漂移都使审批失效。
- push 后必须确认候选是 upstream 祖先,严格 provenance 为 PASS,`published=true`、`remoteVerified=true`、`overrideUsed=false`;禁止 unpublished override。
- 固定应用回滚基线为当前生产候选 `59dc5f6`。不得临场选择其他提交。
### R2 验收身份与合成数据
- 不恢复已从用户表消失的旧 manager/finance smoke;新建角色纯净的 OA-only manager smoke(manager + employee)和 finance smoke(finance + employee),不绑定或重置真实员工身份。
- 把已确认无成员的部门固定为常驻 smoke 部门;employee smoke 迁入后不再迁回,manager smoke 设置为其直属 manager,三类 smoke 身份留在该部门供后续隔离灰度复用。迁移前再次确认部门仍无真人成员。
- 普通 employee 缺直属 manager 时,报销提交会因 `blockOnUnresolvedAssignee=true` 和 `no_manager_found` 返回 409;`owner_self_fallback_role=finance` 只处理 owner 本人持有 CEO 角色的特殊情形,不得把 finance fallback 当作普通 smoke 的兜底方案。
- 合成草稿、明细、票据和附件必须使用明显测试标识与非真实材料;不得复制真人票据、金额、说明或附件。
- 所有成功提交的合成单据在验证后按合法 owner 流程撤回并删除;失败场景草稿直接删除。审计/工作流历史按系统合同保留,不做数据库硬删。
- 材料预览允许产生 `REIMBURSEMENT_MATERIAL_PREVIEW_BUNDLE_ISSUED` / `REIMBURSEMENT_MATERIAL_PREVIEWED` 审计记录;证据只保留状态、页数、页序、比例与构建标识。
### R3 B1 部署
- 部署前必须显式记录 migration status,期望 pending migration 只能包含 `20260829120000_reimbursement_expense_policy_invoice_guard`;多、少或漂移均停止。
- 使用 `deploy/trialrun/deploy-existing.sh`、existing 数据模式和 `SYNC_ENV=0`。不 reset 数据库,不覆盖环境、DB 或附件目录。
- init 后再次显式记录 migration status,并核对:新增列存在、两项补助 `requires_invoice=false`、其他启用类型为 true、费用类型改名/停用/新建准确、`account_code_default` 未被 seed 清空。
- 若正式科目表仍未提供,`account_code_default` 保持 null;责任角色为财务负责人,原目标回填日期 `2026-09-05` 保留在父 task,不由开发猜测编码,也不以此阻断本轮材料门禁上线。
- B1 首次切换后 B2 DB 记录必须由 seed 显式创建且为 `force_off`,不得以 `missing_flag_record` 代替关闭意图;B2 必须保持 effective off。owner 普通草稿维护、assets 事前批准、2,000 元提示、无票补助和非参与人只读投影均须通过。
### R4 B2 hard gate 与隔离灰度
- B1 验收通过后,先确认 DB 为 `force_off`,再经单独生产配置批准把 `REIMBURSEMENT_INVOICE_GUARD_ENABLED=true` 写入受控生产 env,并重启同一候选。重启后应显示 env enabled 但 effective off。
- 隔离灰度只能将 DB flag 设置为 `force_on + department_allowlist + 隔离部门 ID`;不得使用 employee smoke 原部门,不得把 4 张真人单据作为灰度样本。
- 每个状态必须记录精确 reason:env 未开为 `env_hard_off`;env on + DB off 为 `flag_force_off`;灰度名单外部门为 `department_not_allowed`;隔离部门在本轮 `force_on` 模式下为 `flag_force_on_department_allowed`;全局开启为 `flag_force_on_global`。不得只凭提交成功/失败推断门禁已运行。
- 普通 feature flag 列表使用 `strictDepartment=false`,在部门 allowlist 状态只能给出延后判断,不能证明具体 actor 命中。灰度证据必须运行受控容器内只读 actor/department 诊断,并与报销详情 DTO 的 `invoiceGuardEnabled` 交叉验证;诊断不输出部门 ID、账号或原始 payload。
- 隔离灰度必须验证:owner 普通提交成功;两项无票补助不被阻断;多票显式关联成功;超票面准确阻断;旧草稿补齐后可提交;非参与人零写入副作用;切回 `force_off` 后旧提交路径恢复且既有关联数据不删除、不解绑。
- B2 不校验日期粒度的事实必须在验收结论和财务退回说明中保留;不得把 flag PASS 描述为“系统已自动保证明细粒度”。
- 灰度失败立即把 DB 恢复为调用前完整快照,最迟先落 `force_off`;关闭 flag 只回退门禁,不回滚关联数据。
### R5 全局启用与真实单据处置
- 隔离灰度全部通过并清理合成单据后,必须再次获得全局启用批准,才可把 rollout 从部门 allowlist 改为 global;更新使用版本并发控制并产生 feature flag 审计。
- 全局启用后先验证 effective global on、owner 基线、财务/管理员只读投影、错误提示和运行指标,再安排真实财务账号退回 4 张单据。
- `0014` 退回说明必须写死“按 5 个发票日期拆成 5 条明细”,重提后由财务人工确认;B2 不会自动拦截原样重提。
- `0016` 至少按 3 个发票日期拆分并逐票关联;`0017` 按 2 个发票日期重做、上传正式 PDF、逐票关联并解释 `1,949.81 元`差额;`0018` 若同日同类可保留一条,但须改正日期并关联全部 5 张票。
- 退回必须由真实 finance 审批主体执行。admin、smoke admin 或脚本不得代行财务职责;Codex 不保存真实财务凭据。
### R6 失败与回滚
- 切换前失败只停止,不执行应用回滚。migration/seed 或应用切换开始后任一必需门禁失败,先确保 B2 DB `force_off`,再按同一 existing 入口回滚应用到 `59dc5f6`。
- 应用回滚不逆向 migration、不删新增列、不删除票据—明细关联。新增列对旧应用为向前兼容。
- init 已改变费用类型主数据,应用回滚不会自动恢复旧名称/启用状态。部署前必须保存受影响类型的脱敏主数据快照;只有 B1 主数据本身被判定错误且取得单独补偿批准时,才按快照执行精确补偿,不运行整库回滚或重放猜测 SQL。
- 回滚后必须核对 `/ready`、bundle marker、migration status、runtime/external smoke、DB/附件挂载和备份合同;若 env hard gate 已写入,可保持 true,但 DB 必须 `force_off`。若回滚原因涉及 flag 配置或新代码误触发,则同时恢复 env hard-off 并重启旧应用。
## Acceptance Criteria
- [ ] 常驻 smoke 部门、专用 manager/finance smoke、employee smoke 迁入和直属 manager 关系经单独生产写入批准;准备完成后不涉及任何真实员工身份或材料。
- [ ] 最终候选冻结、单独 push、upstream 祖先关系和严格 provenance 全部通过。
- [ ] 用户在 provenance 通过后另行批准 B1 生产部署;pre/post migration status 均明确记录,唯一 migration 正确应用。
- [ ] B1 schema、费用主数据、requires_invoice、assets 批准依据、2,000 元提示和 account code 保留检查通过;B2 DB 记录明确存在且为 force_off,effective off reason 不是 missing record。
- [ ] `/ready`、12 位 bundle marker、runtime/external smoke、备份合同刷新和角色化公网检查通过。
- [ ] owner 合成草稿维护正常;finance/admin 非参与人无维护入口;材料合并预览成功并只产生获批的设计内审计。
- [ ] env hard gate 在 DB `force_off` 状态下单独启用并重启,确认 env on / effective off 后才进入隔离灰度。
- [ ] B2 隔离灰度七项合同全部通过;失败时 DB 快照恢复,既有关联数据未回滚。
- [ ] 用户单独批准后 B2 全局 effective on;合成数据已按合法流程清理,employee/manager/finance smoke 常驻隔离部门且无真人混入。
- [ ] 真实财务按明确说明退回 0014/0016/0017/0018,重提后人工复核日期粒度;0008 与 0013 未被误改。
- [ ] 任一失败按固定回滚/补偿边界处理,无 reset、无逆 migration、无批量伪造批准依据或票据关联。
- [ ] 所有公网门禁完成前不通知普通用户测试、不归档父任务。
## Out of Scope
- 修改 B1/B2 业务代码、把日期粒度新增为服务端阻断、补数量/单价模型或提前实施 B3 一页式。
- 反向修改已付款 0008、替真人财务审批、保存真实凭据、复制真实票据作为测试材料。
- 在本轮编造会计科目编码、重置数据库、回退 migration、批量写入事前批准依据或清空审计记录。
- 把合成灰度批准推定为真实单据退回批准,或把部门灰度 PASS 推定为全局启用批准。
## Test Plan
- 来源:干净工作区、候选 SHA、独立 push、upstream 祖先关系、严格 provenance。
- 生产 preflight:existing 部署合同、身份、数据挂载、唯一 pending migration、受影响主数据快照、B2 env/DB 初始状态。
- B1:init 前后 migration status、schema/seed/account code 断言、build marker、runtime/external smoke、备份合同和角色化页面。
- B2:env on + DB off、隔离部门 allowlist、七项合成业务合同、flag 快照恢复、关联数据保留、全局启用后复核。
- 真实业务:四张单据退回说明逐单核对,重提后财务人工核验日期粒度;0008/0013 零改动。
- 治理:task validate、Trellis governance、process contract、docs registry audit、敏感信息扫描和 `git diff --check`。
@@ -0,0 +1,33 @@
{
"id": "reimbursement-expense-policy-invoice-guard-deploy",
"name": "reimbursement-expense-policy-invoice-guard-deploy",
"title": "报销费用政策与票据门禁生产部署",
"description": "受控部署 B1 migration 与费用主数据,在隔离部门验证 B2 后全局启用,并统一处置四张审批中报销。",
"status": "in_progress",
"dev_type": null,
"scope": "production deployment, migration, feature flag rollout, smoke identities, reimbursement remediation",
"package": "deploy,server,client,trellis",
"priority": "P0",
"creator": "shunli",
"assignee": "shunli",
"createdAt": "2026-08-30",
"completedAt": null,
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": "08-29-reimbursement-expense-policy-invoice-guard",
"relatedFiles": [
"deploy/trialrun/deploy-existing.sh",
"deploy/trialrun/deploy.sh",
"server/prisma/migrations/20260829120000_reimbursement_expense_policy_invoice_guard/migration.sql",
"server/src/scripts/seed-config.js",
"server/src/services/featureFlags/index.js",
"server/src/routes/reimbursements.js"
],
"notes": "规划阶段;不执行 push、生产账号/部门/合成数据写入、migration、部署、env 配置、feature flag 更新或真实单据退回。固定应用回滚基线为 59dc5f6。B2 不校验日期粒度,0014 必须依赖退回说明和财务人工复核。employee/manager/finance smoke 终态常驻隔离部门;普通 employee 无直属 manager 时 workflow 会以 no_manager_found 阻断。B2 DB 记录必须显式存在为 force_off,灰度必须记录 actor 级精确 reason。",
"meta": {}
}