5.5 KiB
设计:报销费用政策与票据门禁生产部署
发布边界
本任务不再修改业务代码。候选包含父任务业务提交 6e999d5 和本部署合同;规划文档提交完成后以最终干净 HEAD 冻结,并在外部审批记录写完整 SHA 与 12 位 bundle marker。当前生产 59dc5f6 是固定应用回滚基线。
生产切换分为三个独立状态:
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 角色包含付款能力,账号在验收窗口外保持 disabled,每次启停均需生产账号写入授权。
- 真实 finance:仅负责 4 张真人单据的业务退回和重提复核,凭据不交给自动化。
隔离部门改名为“系统测试专用(勿分配员工)”。名称用于降低 HR 误分配概率,但每次灰度仍必须以实时成员集合为准:只允许 employee/manager/finance 三个 smoke,任何第四个成员都使灰度门关闭。
合成材料必须是无真实抬头、号码、账户和业务正文的测试 PDF/图片。成功提交的合成单据通过 owner 撤回回到草稿再删除;阻断场景直接删除草稿。审计记录保留。
Migration 与 seed
唯一 migration:20260829120000_reimbursement_expense_policy_invoice_guard。
- migration 新增向前兼容列并回填两项免票类型。
seed:config落地费用类型改名、停用、新建、description、requires_invoice 和 B2 DBforce_off初值。- seed 更新路径不写
account_code_default,部署前后须按 code 对比,防止既有财务映射丢失。 - deploy init 同时运行
seed:trialrun,因此 pre/post 证据必须覆盖 migration 与主数据,而不能只看_prisma_migrations。
B2 配置数据流
生产环境不由 SYNC_ENV=0 自动同步。正确顺序为:
- B1 init 后确认 DB flag 记录已由 seed 显式创建为
force_off,不得接受missing_flag_record,并保存完整快照。 - 经生产配置授权把 env hard gate 设为 true,重启同一候选。
- 验证
envEnabled=true、effectiveEnabled=false、reason=flag_force_off。 - 经灰度授权前实时确认隔离部门只有三个 smoke,并在获批窗口临时启用 finance smoke;随后把 DB 更新为 department allowlist,仅含隔离部门。
- 执行合成验证;失败恢复调用前快照,优先
force_off。 - 灰度 PASS 后,经全局授权更新为 global force_on;验收窗口结束立即 disabled finance smoke。
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 不进入处置动作。
回滚与补偿
回滚分三层,不能混用:
- B2 行为异常:DB flag 立即
force_off,关联数据保留。 - 应用异常:确保 B2 off,使用 existing 入口回滚到
59dc5f6;不逆 migration。 - B1 主数据错误:应用回滚不会恢复 seed 结果。只在单独批准后,依据部署前快照对受影响 code 做精确补偿;不执行整库 restore,不删除新增类型或历史外键。
回滚后重复 build、migration status、runtime/external smoke、挂载、备份合同与公网入口检查。
证据与隐私
报告只保存 PASS/FAIL、SHA、migration 名、类型 code/状态、flag 状态、合成标识和计数。不得保存密码、token、完整账号、真实票据、姓名、业务正文或原始 API payload。材料预览只记录页数、页序和比例,允许保留系统生成的审计记录。