Files
docs/财务管理/财务历史迁移与上线验收方案.md

563 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 财务历史迁移与上线验收方案
> 版本:V1.0
> 编制日期:2026-08-10
> 状态:首发已确认不迁移历史;本文仅保留为未来补迁/导入参考,不纳入首发门禁
> 适用范围:Finance F0 财务底座、F1 客户应收与对账首发上线
> 关联文档:[财务管理闭环盘点与范围建议](README.md)、[财务服务边界设计](财务服务边界设计.md)、[财务管理产品确认表](财务管理产品确认表.md)
## 一、目标与基本结论
**首发产品结论:没有需要迁移的历史财务数据,Finance 只接收正式启用后的新费用来源。** 因此首发不得执行历史批量导入,也不要求准备线下已结算排除台账。本文后续迁移步骤仅在未来明确提出历史补迁时重新启用并复核。
本方案用于把 Finance 上线前已经存在于 Firstleg 的历史对客费用,安全地接入独立 `finance-service` 和 `baiyue_finance`,并定义 F0/F1 从测试、灰度到正式启用的验收门禁。
本方案不把“费用已发送/已发布”推断为“客户尚欠款”,也不把入库测量与计费计费状态推断为财务结算状态。历史迁移分成三个明确步骤:
```text
Firstleg 历史费用候选集
-> 迁移暂存与规则校验
-> Finance 财务来源池(不自动生成应收)
-> 经业务确认的可出账来源(才允许生成对账单/应收)
```
正式上线采用以下技术原则:
- Firstleg 是历史业务费用事实来源,Finance 不跨库 Join、不直接写 Firstleg 数据库;
- 迁移通过受保护的导出/查询契约或离线只读导出文件完成,导入由 Finance 执行;
- 每一条历史来源保留来源服务、来源主键、业务编号、版本、金额、币种和内容哈希;
- 迁移批次可重跑、单条记录幂等,同一来源版本不会重复入池;
- 线下已结算、已作废、已被替代或无法证明归属的记录默认排除,不自动形成应收;
- 历史数据迁移完成且对账通过后,才开启实时费用事件消费;
- Finance 上线前不回写或批量修改 Firstleg 历史费用状态;
- 已生成财务单据后不物理删除,错误通过冲销、反核销或补偿记录修正。
## 二、确认状态
### 2.1 技术已定事项
| 事项 | 结论 |
|---|---|
| 服务与数据库 | 独立 `finance-service`、独立 `baiyue_finance` |
| 数据读取 | 受保护 DTO 查询或只读导出;禁止跨库 Join |
| 迁移层次 | 暂存、财务来源池、出账三层分离 |
| 幂等键 | `sourceService + sourceType + sourceId + sourceVersion`;批次另有唯一 `migrationBatchNo` |
| 内容冲突 | 同一幂等键且哈希不同必须拒绝,进入人工冲突队列 |
| 历史留痕 | 保存原始来源快照、迁移规则版本、批次号和校验结果 |
| 上线切换 | 先历史迁移水位,再实时事件追平;用时间水位与事件 ID 防止漏单/重单 |
| 回滚原则 | 未激活暂存记录可整批废弃;已入账记录只补偿/冲销,不物理删除 |
| 发布策略 | 测试环境验证 → 生产影子接入 → 小范围灰度 → 全量启用 |
### 2.2 待产品/业务确认事项
以下事项影响哪些历史记录成为客户欠款,不能由技术自行推断:
| 编号 | 待确认业务口径 | 本方案安全默认值 |
|---|---|---|
| M-BIZ-01 | 历史费用纳入起始日期/截止日期 | 不预设;首次执行前按财务主体、客户和业务日期书面冻结 |
| M-BIZ-02 | 历史候选费用的最终状态组合 | 仅考虑已审核、已发布/发送、参与结算且未作废的应收方向费用 |
| M-BIZ-03 | 线下已结算的判定依据 | 以产品确认的线下结算台账、到账凭证或财务签字清单为准;无法判断的先隔离 |
| M-BIZ-04 | 部分线下结算如何处理 | 默认整条隔离,不自动拆分余额;确认后按“原金额 + 期初已结金额/余额”专门迁移 |
| M-BIZ-05 | 历史费用是否直接生成对账单/应收 | 默认只进入来源池,财务人工选择后生成 |
| M-BIZ-06 | 历史到期日、账期和逾期计算 | 未确认时不补算逾期;待客户结算条款和基准日确认 |
| M-BIZ-07 | 历史费用调整链如何取版本 | 默认仅取每条业务来源当前最终有效版本,调整/冲销链必须成组校验 |
| M-BIZ-08 | 已线下结算数据是否需要作为期初档案展示 | 默认不进 F1 应收;如需要,只读迁入“历史已结算档案”,不得产生可收余额 |
| M-BIZ-09 | 首批灰度客户及财务主体 | 上线前由产品、财务、运营共同给出白名单 |
| M-BIZ-10 | 迁移差异允许阈值 | 金额与条数默认要求零差异;确需容差必须逐币种、逐类型确认,且不得自动抹平差额 |
上述事项未确认不阻断 Finance 骨架、暂存区、校验器、批次和报表开发,但阻断生产历史数据激活及 F1 对客户开放。
## 三、历史数据范围
### 3.1 候选来源
首批只处理能够追溯到 Firstleg 已发布对客费用版本的 `RECEIVABLE` 数据。当前入库测量与计费费用用于证明业务计费结果,不直接证明应收、收款或核销事实。
每条候选记录至少应能提供:
- 客户 ID、客户名称快照;
- 入库单 ID、入仓码/业务单号;
- 来源费用 ID、来源费用单号、来源版本;
- 费用项目 ID/编码/名称快照、费用方向;
- 业务发生日、发布时间、审核时间;
- 币种、原币金额、计费量及计费快照摘要;
- 审核状态、发布状态、参与结算标记、作废/调整状态;
- 来源更新时间、内容哈希;
- 可用于判断调整链的前序/后续来源引用(如已有)。
### 3.2 纳入规则
历史候选记录只有同时满足以下规则,才能进入“待激活财务来源池”:
1. 费用方向为客户应收 `RECEIVABLE`;
2. 已审核通过;
3. 已发布/已发送给客户;
4. `settlementIncluded=true`,或经产品确认的等价历史标志;
5. 来源版本有效,未作废,未被后续有效版本完全替代;
6. 客户、币种、金额、业务日期和费用项目完整且合法;
7. 能唯一映射到一个客户和一个财务主体;
8. 不在“线下已结算/不再追收”排除清单中;
9. 未在 Finance 以相同来源版本入池;
10. 通过金额、版本链和哈希校验。
其中第 4、7、8 项的最终业务映射表必须在生产执行前由产品/财务确认。
### 3.3 默认排除与隔离
| 排除/隔离原因码 | 场景 | 处理方式 |
|---|---|---|
| `OFFLINE_SETTLED` | 已在线下收款并结清 | 排除,不生成可收余额;按 M-BIZ-08 决定是否迁入只读档案 |
| `OFFLINE_PARTIAL_UNKNOWN` | 已部分结算但剩余金额不可靠 | 隔离,禁止自动拆分或生成应收 |
| `VOIDED` | 费用已作废 | 排除,保留统计和证据 |
| `SUPERSEDED_VERSION` | 已被后续有效版本替代 | 排除旧版本,保留版本链核验 |
| `NOT_APPROVED` | 未审核或审核驳回 | 排除 |
| `NOT_PUBLISHED` | 仅试算/确认但未发布 | 排除 |
| `NOT_SETTLEMENT_INCLUDED` | 不参与结算 | 排除 |
| `NON_RECEIVABLE` | 应付或方向未知 | 不进入 F1;后续 F2 单独评估 |
| `CUSTOMER_UNMAPPED` | 客户缺失、重复或无法映射 | 隔离,禁止用默认客户兜底 |
| `ENTITY_UNMAPPED` | 财务主体无法确定 | 隔离 |
| `CURRENCY_INVALID` | 币种缺失或非 ISO 三位码 | 隔离,不自动假定 CNY |
| `AMOUNT_INVALID` | 金额为空、精度不合法或业务不允许的负数 | 隔离 |
| `VERSION_CONFLICT` | 同一来源版本内容哈希不同 | 冲突队列,停止该来源链激活 |
| `DUPLICATE_BUSINESS_FACT` | 不同 ID 疑似同一业务费用 | 隔离,人工确认,不自动去重 |
| `OUT_OF_RANGE` | 不在确认的迁移日期/客户范围 | 排除本批次,可在后续批次纳入 |
每条排除或隔离记录必须保存原因码、规则版本、原始摘要和处理人;不得只记录一条汇总数量。
## 四、线下已结算防重复机制
### 4.1 结算排除台账
上线前由业务/财务提供结构化“线下结算排除台账”,禁止仅以聊天记录或口头说明作为迁移依据。至少包含:
```text
客户标识
财务主体
币种
关联业务单号/入库单号/费用单号(至少一种可唯一定位)
费用项目(按需)
线下结算金额
结算日期
结算凭证号或证明附件引用
结算状态(全额/部分/不再追收)
确认人
确认批次
备注
```
排除台账导入后也要版本化,计算文件哈希,不允许覆盖旧版本。每一次迁移批次明确引用一个排除台账版本。
### 4.2 匹配优先级
匹配按确定性从高到低执行:
1. 来源费用 ID + 来源版本;
2. 费用单号 + 费用明细 ID;
3. 入库单号 + 费用项目 + 币种 + 金额;
4. 客户 + 币种 + 业务日期范围 + 金额。
只有前两级可自动排除。第 3、4 级产生“疑似匹配”,必须人工复核;禁止仅因金额相等就自动认定已结算。
### 4.3 上线保护
- 历史迁移来源默认 `activationStatus=PENDING_REVIEW`;
- 只有排除台账匹配完成、差异报告签字后才能变为 `ACTIVE`;
- 历史来源激活不自动发送客户通知,不自动生成账单;
- 客户看到历史账单前必须经过财务制单和复核;
- 对已经线下结算却误生成应收的情况,立即停止对应客户灰度,使用冲销/作废流程修正,禁止伪造收款核销来“做平”。
## 五、迁移批次与幂等设计
### 5.1 批次状态
```text
CREATED
-> EXTRACTED
-> VALIDATED
-> IMPORTED_PENDING_REVIEW
-> RECONCILED
-> APPROVED
-> ACTIVATED
任一执行中状态 -> FAILED
未激活批次 -> ABANDONED
已激活批次 -> COMPENSATING -> COMPENSATED/PARTIALLY_COMPENSATED
```
状态迁移由服务端校验。`ACTIVATED` 后不得回到编辑态;批次重跑必须沿用原批次重试号或新建补偿批次。
### 5.2 批次元数据
每批至少记录:
- `migrationBatchNo`、环境、规则版本、排除台账版本;
- 提取范围:客户、财务主体、业务时间、来源更新时间水位;
- 提取开始/结束时间、操作者、审批者;
- 来源总数、导入数、排除数、隔离数、冲突数;
- 按客户和币种汇总的来源金额、导入金额和差异;
- 输入文件/响应摘要哈希、执行程序版本或提交 SHA;
- 各阶段开始/结束时间、错误摘要和重试次数;
- 对账报告、审批记录和激活时间。
### 5.3 单条幂等与冲突
Finance 财务来源唯一键:
```text
(source_service, source_type, source_id, source_version)
```
处理规则:
- 唯一键不存在:写入来源快照和批次关联;
- 唯一键已存在且 `sourceHash` 相同:返回第一次结果,记为重复但成功;
- 唯一键已存在且 `sourceHash` 不同:拒绝写入,记 `VERSION_CONFLICT`;
- 同一批次重复上传:不重复增加条数和金额;
- 同一来源在后续批次出现:只增加批次检测关系,不新建第二条有效来源;
- 同一业务操作的超时重试必须返回可查询的原处理结果。
### 5.4 历史与实时切换水位
为避免迁移期间新费用漏入,按以下顺序切换:
1. 记录历史提取截止水位 `T0`(来源更新时间 + 稳定排序键);
2. 导入并对账 `<= T0` 的历史数据;
3. Finance 实时消费者先以影子模式接收事件并写 Inbox,不激活来源;
4. 历史批次对账通过后,重放/处理 `> T0` 的 Inbox 事件;
5. 核对 `T0` 边界前后窗口,确认无缺号、无重复、无哈希冲突;
6. 开启实时来源激活,再开放制单入口。
时间戳不能单独作为游标;同一时间戳必须带稳定主键/事件 ID 排序,边界查询应采用重叠窗口并依赖幂等去重。
## 六、迁移执行流程
### 6.1 预演
1. 冻结产品业务口径、首批客户和日期范围;
2. 从 Firstleg 只读提取候选记录,生成不可修改的输入快照;
3. 导入线下结算排除台账;
4. 执行 `dry-run`,只生成纳入、排除、隔离和冲突报告;
5. 财务逐客户、逐币种核对金额和异常;
6. 修正映射或排除台账后新建规则/台账版本重新预演;
7. 产品、财务、技术共同签署预演报告。
### 6.2 正式迁移
1. 校验目标环境、批次号、规则版本、输入哈希和审批记录;
2. 写入迁移暂存区,不直接写对账单、应收单或收款单;
3. 完成字段、引用、版本链、重复和金额校验;
4. 将通过的数据幂等写入待复核来源池;
5. 生成逐客户/逐币种对账报告;
6. 对账通过并审批后激活来源;
7. 追平 `T0` 之后的实时事件;
8. 仅对灰度客户开放 Finance 制单与客户查看。
### 6.3 数据映射约束
- Firstleg 历史 `tenantId` 仅作为当前客户隔离兼容字段使用,Finance 产品层仍使用“客户/企业”,不得迁移出可见的租户层;
- 平台公共仓 `tenant_id=0` 不能被误映射成客户;
- 客户、费用项目、财务主体映射必须版本化,禁止运行时按名称模糊匹配;
- 金额按原币定点小数迁移,不在迁移时自动折算本位币;
- 原始金额和币种不得被清洗规则覆盖;修正必须形成明确映射或补偿记录;
- 历史缺失的财务字段使用 `UNKNOWN/PENDING` 类显式状态(若模型允许),不得伪造默认凭证号、结算日或操作人;
- 文件附件只保存 File 服务引用和当时元数据快照,不复制二进制文件。
## 七、校验与对账
### 7.1 四级校验
| 级别 | 校验内容 | 失败处理 |
|---|---|---|
| 结构校验 | 必填字段、类型、精度、币种、日期、枚举 | 单条隔离 |
| 引用校验 | 客户、财务主体、费用项目和业务单据能唯一映射 | 单条隔离 |
| 业务校验 | 状态组合、方向、结算标记、作废和版本链 | 排除或隔离 |
| 财务校验 | 按客户/币种的条数、原币金额、排除金额和激活金额平衡 | 批次不得审批 |
### 7.2 对账恒等式
每个批次必须逐客户、逐币种满足:
```text
候选条数 = 纳入条数 + 排除条数 + 隔离条数
候选原币金额 = 纳入原币金额 + 排除原币金额 + 隔离原币金额
Finance 待复核来源条数 = 本批纳入唯一来源条数
Finance 待复核来源金额 = 本批纳入原币金额
```
重复幂等命中作为独立统计项展示,但不得重复进入金额恒等式。负数、零金额和冲销记录须按记录性质单列,禁止用正负汇总抵消后隐藏异常。
### 7.3 必须生成的报告
- 批次总览报告;
- 逐客户、逐币种、逐费用项目的条数/金额报告;
- 线下已结算自动匹配、疑似匹配和未匹配报告;
- 排除/隔离原因明细;
- 重复与哈希冲突明细;
- 调整/作废版本链完整性报告;
- 历史水位与实时 Inbox 衔接报告;
- Finance 来源到 Firstleg 来源的抽样追溯报告。
技术验收要求条数与原币金额零差异。业务决定的排除不是“差异”,但必须在等式中有明细、有金额、有审批。
### 7.4 抽样规则
自动全量校验之外,人工抽样至少覆盖:
- 每个灰度客户;
- 每种币种和主要费用项目;
- 最大金额、最小非零金额、零金额/负数(如业务允许);
- 多版本调整、已作废、线下已结算和疑似重复记录;
- 跨月边界、迁移截止水位前后记录;
- 金额合计前 80% 的高金额样本,以及不少于 30 条随机样本。
## 八、回滚与补偿
### 8.1 未激活阶段
`CREATED` 至 `APPROVED` 的批次不对 F1 制单开放。失败时可以:
- 标记批次 `FAILED` 或 `ABANDONED`;
- 清理可重建的暂存数据,保留批次元数据、输入哈希、日志和差异报告;
- 修正规则或映射后,以新规则版本重跑;
- 不修改 Firstleg 原始数据。
### 8.2 已激活但未出账
发现问题时先冻结批次和相关客户的制单入口,再执行补偿:
- 将错误来源标记为不可出账/已补偿;
- 记录补偿批次、原因和原来源关联;
- 重新迁移正确版本;
- 已产生但仍为草稿的账单按受控作废流程处理,不物理删除审计记录。
### 8.3 已出账、收款或核销
不得通过删表、改余额或回写旧快照回滚。应按对象状态使用:
- 账单作废或重开;
- 应收冲销/补差;
- 核销反核销;
- 收款撤销(仅在真实到账事实允许时);
- 新补偿来源和新单据。
补偿执行前必须生成影响清单:客户、币种、账单、应收、收款、核销、余额和客户可见内容。若已经向客户发送账单,业务负责人与财务必须确认沟通方案。
### 8.4 服务发布回滚
- Finance 服务、Gateway 路由和前端可独立回滚;
- 数据库迁移采用向前兼容的增量脚本,服务回滚版本必须能读取已存在结构;
- 不以回退数据库结构作为常规回滚手段;
- 关闭 Finance 功能开关或客户白名单时,实时事件仍进入 Inbox/Outbox 重试链,不得丢弃;
- 回滚后再次上线必须从已记录的消费水位恢复,并先完成积压对账。
## 九、灰度上线方案
### 9.1 阶段划分
| 阶段 | 开放范围 | 退出条件 |
|---|---|---|
| G0 测试环境 | 测试数据与脱敏历史样本 | F0/F1 自动化及业务回归通过 |
| G1 生产影子 | 全量或限定来源只入 Inbox/待复核池;用户不可见、不可制单 | 连续观察期无漏单、重复或冲突;观察时长待上线评审确定 |
| G2 内部灰度 | 白名单客户;仅平台财务可见和制单 | 财务逐日对账通过,无 P0/P1 缺陷 |
| G3 客户灰度 | 白名单客户只读查看 | 客户侧金额和状态一致,通知无重复 |
| G4 全量 | 全部已确认客户 | 灰度总结批准,监控、值守和补偿预案就绪 |
### 9.2 灰度维度
灰度至少同时受以下开关控制:
- 环境;
- 财务主体;
- 客户白名单;
- 功能(来源接入、制单、发送、客户只读查看、收款、核销、反核销);
- 历史批次号与实时事件起始水位。
开关由服务端执行,前端隐藏按钮不能代替权限或灰度校验。
## 十、监控与告警
### 10.1 必须监控的指标
| 类别 | 指标 |
|---|---|
| 事件接入 | Firstleg Outbox 待发送数/最老年龄、Finance Inbox 积压数/最老年龄、消费成功率、重试数 |
| 幂等与冲突 | 重复命中数、哈希冲突数、乱序等待数、死信数 |
| 迁移 | 各批次状态、处理速率、排除/隔离比例、长时间无进展批次 |
| 对账 | 逐客户/币种条数差、金额差、历史与实时水位差 |
| F1 台账 | 来源入池数、账单生成数、应收余额变化、收款未核销余额、超额/跨币种拒绝数 |
| 稳定性 | API 错误率、延迟、数据库连接池、锁等待、乐观锁冲突、定时任务失败 |
| 安全审计 | 越权拒绝、跨客户访问、反核销/作废/关账等高风险操作 |
告警阈值在上线评审时结合基线确定;以下事件不等待阈值,首次发生即告警:哈希冲突、跨客户数据命中、超额核销成功、同一来源生成两条有效来源、金额对账非零差异、审计写入失败。
### 10.2 可观测性要求
- 跨服务请求保留 `requestId`、`traceId`、`eventId`、`migrationBatchNo`;
- 日志不得输出银行账号全量、凭证附件内容或客户敏感信息;
- 每个批次和事件可查询最后处理状态、失败原因、重试次数和下一步动作;
- Dashboard 按环境、财务主体、客户和币种筛选;
- 审计、迁移和业务日志的保留期限待合规要求确认,但不得短于上线问题追溯周期。
## 十一、F0 上线验收用例
### 11.1 正常用例
| 编号 | 场景 | 预期结果 |
|---|---|---|
| F0-N01 | Finance 独立启动、注册并连接财务库 | 健康检查通过,只访问 `baiyue_finance` |
| F0-N02 | 合法历史来源首次导入 | 生成一条待复核来源,快照、哈希、批次和审计完整 |
| F0-N03 | 相同批次重复提交 | 返回原处理结果,不重复条数/金额 |
| F0-N04 | 相同来源由后续批次再次导入 | 幂等命中,不生成第二条有效来源 |
| F0-N05 | Firstleg 发布实时费用事件 | Inbox 记录并生成来源;可追溯至事件和上游快照 |
| F0-N06 | 历史水位后事件追平 | 边界窗口无漏单,重复事件被幂等吸收 |
| F0-N07 | 按客户/币种生成迁移对账 | 条数、金额和原因分类满足恒等式 |
| F0-N08 | 有权限人员查看迁移批次/冲突 | 数据范围正确,查询和处理均有审计 |
### 11.2 异常用例
| 编号 | 场景 | 预期结果 |
|---|---|---|
| F0-E01 | 同一幂等键内容哈希不同 | 拒绝并告警,原来源不被覆盖 |
| F0-E02 | 事件重复、乱序、超时重试 | 不重复入池;乱序进入等待/核验,不错误激活 |
| F0-E03 | 客户或财务主体无法映射 | 单条隔离,不使用默认归属 |
| F0-E04 | 币种缺失、金额精度非法 | 单条隔离并显示明确原因 |
| F0-E05 | 已作废/未审核/未发布来源 | 排除,不进入可出账来源池 |
| F0-E06 | 线下已结算精确匹配 | 排除并关联排除台账证据 |
| F0-E07 | 仅金额相同的疑似线下结算 | 不自动排除,进入人工复核 |
| F0-E08 | 跨客户查询或激活 | 服务端拒绝并产生安全审计 |
| F0-E09 | 批次中途失败后重跑 | 已成功记录不重复,失败记录可续跑,汇总一致 |
| F0-E10 | 审计落库失败 | 财务写操作整体失败,不出现无审计的成功记录 |
| F0-E11 | Finance 暂时不可用 | Firstleg 业务费用事实不回滚;Outbox 保留并重试 |
| F0-E12 | 数据库/服务发布回滚 | 来源与 Inbox 不丢失,恢复后从原水位继续 |
## 十二、F1 上线验收用例
### 12.1 正常主链路
| 编号 | 场景 | 预期结果 |
|---|---|---|
| F1-N01 | 财务从激活来源池按客户+币种+账期生成账单 | 来源只进入一张有效账单,金额合计正确 |
| F1-N02 | 账单内部复核、发送、客户只读查看 | 状态按平台出账模型流转,平台与客户显示一致 |
| F1-N03 | 平台录入线下异议 | 记录原因和争议明细,原快照不被覆盖,由平台财务调整/作废重开 |
| F1-N04 | 确认账单形成应收 | 应收金额、余额、到期日和来源关系正确 |
| F1-N05 | 登记一笔收款核销多张应收 | 每条分配关系可追溯,收款和应收余额正确 |
| F1-N06 | 一张应收被多笔收款部分核销 | 状态依次为 OPEN/PARTIALLY_SETTLED/SETTLED,累计不超额 |
| F1-N07 | 反核销 | 原核销变为 REVERSED,应收及收款可用余额恢复,审计完整 |
| F1-N08 | 已出账费用发生调整 | 原账单不覆盖,通过补差/冲销来源进入后续流程 |
### 12.2 异常和并发
| 编号 | 场景 | 预期结果 |
|---|---|---|
| F1-E01 | 同一来源被并发生成账单 | 只有一个请求成功,另一请求返回明确冲突 |
| F1-E02 | 跨币种生成账单或核销 | 服务端拒绝 |
| F1-E03 | 收款核销金额超过应收余额 | 服务端拒绝,所有余额不变 |
| F1-E04 | 多请求并发核销同一余额 | 乐观锁/原子约束保证不超额,不产生部分脏写 |
| F1-E05 | 重复提交收款或核销 | 返回首次结果,不重复记账 |
| F1-E06 | 无权限执行收款、核销、反核销或作废 | 服务端拒绝并审计 |
| F1-E07 | 客户访问其他客户账单或内部字段 | 服务端拒绝;供应商成本、内部备注和凭证不可见 |
| F1-E08 | 已关闭期间直接改账 | 拒绝,提示使用后续期间调整/冲销 |
| F1-E09 | 已确认账单原地删除或改金额 | 拒绝,原记录保持不变 |
| F1-E10 | 附件服务失败 | 财务单据不伪造附件成功;按业务动作原子性返回失败或保留可重试状态 |
| F1-E11 | 客户通知失败 | 财务单据状态不回滚,通知独立重试且不重复发送业务动作 |
| F1-E12 | 线下已结算历史来源误入池 | 停止客户灰度,禁止继续制单,按补偿流程处理并出具影响报告 |
## 十三、上线门禁
### 13.1 开发开工门禁
- Finance 服务边界和 Firstleg 事件/内部查询契约书面冻结;
- F0/F1 对象、状态机、金额精度、权限码、错误码和审计事件冻结;
- M-BIZ 未确认项保持显式配置或阻断,不硬编码业务假设;
- 迁移暂存、来源池、账单、应收、收款、核销是独立对象;
- 数据库脚本、回滚兼容策略和部署映射纳入评审。
### 13.2 测试环境部署门禁
- 仅部署受影响单元,执行目标模块声明的 Maven 测试;
- Finance 纳入 Maven、Nacos、Gateway、OpenAPI、Docker Compose、服务映射和 Jenkins 增量部署;
- 数据库初始化/迁移必须获得当前对话或发布审批的明确授权,不能借普通服务部署自动执行;
- 不得跳过测试,不得在范围不明时执行后端全量部署;
- 测试数据不使用真实客户敏感信息;
- F0/F1 正常、异常、并发、越权用例全部有证据。
### 13.3 生产迁移门禁
- M-BIZ-01 至 M-BIZ-10 已确认或有书面暂缓方案;
- 首批客户、财务主体、时间范围、规则版本和线下排除台账冻结;
- 至少完成一次等规模 dry-run,条数与金额零差异;
- 所有隔离项有责任人和处理结论,高风险冲突为零;
- 回滚/补偿演练通过,明确停止开关和联系人;
- 监控、告警、Dashboard、日志和审计查询可用;
- 发布版本、完整 commit SHA、数据库脚本、配置和镜像可追溯;
- 生产数据库变更和发布已获得对应授权;
- 财务、产品、技术共同签署上线检查单。
### 13.4 客户开放门禁
- 影子接入和内部灰度观察完成;
- 对应客户历史来源及实时来源逐币种对账通过;
- 该客户线下已结算排除清单已确认;
- 客户侧只读权限、脱敏、空态和错误态验收通过;平台线下异议录入验收通过;
- 不发送历史自动账单;首张账单由财务人工复核后发送;
- 客服/运营已获得争议、误账和通知失败处理说明。
## 十四、上线后检查与退出条件
### 14.1 上线后立即检查
1. 核对服务注册、健康状态、Gateway 路由和数据库连接;
2. 核对历史批次状态、实时 Inbox 水位和 Firstleg Outbox 积压;
3. 抽取首批来源追溯到 Firstleg 原始快照;
4. 逐灰度客户、逐币种核对来源条数和金额;
5. 完成一条真实但受控的“来源 → 账单 → 应收 → 收款 → 核销 → 反核销”回归;
6. 检查 Admin/Client 金额、状态、权限和客户隔离一致;
7. 记录构建号、commit、配置版本、批次号、测试证据、`requestId/traceId`。
### 14.2 扩大灰度条件
- 当前灰度范围内无金额差异、无重复有效来源、无跨客户问题;
- 无 P0/P1 缺陷,未发生未解释的哈希冲突;
- 事件积压和失败重试在既定服务水平内;
- 财务日结核对通过;
- 已发现问题均有补偿结果并复核。
### 14.3 立即停止扩大灰度的条件
- 任何客户金额串用或越权可见;
- 来源、账单、应收、收款或核销出现重复记账;
- 对账出现无法解释的非零差异;
- 超额核销、跨币种核销或关闭期间改账成功;
- 审计缺失、迁移输入不可追溯或补偿路径不可用;
- Firstleg 与 Finance 水位持续扩大且无法追平。
停止扩大灰度不等于删除数据。应先关闭相关功能/客户白名单、保留事件接收和证据,再按影响范围决定补偿或服务版本回滚。
## 十五、交付证据清单
每次预演、迁移或上线至少归档:
- 已确认的业务口径和灰度白名单;
- 迁移批次元数据、输入哈希、规则版本、排除台账版本;
- 条数/金额对账报告及排除、隔离、冲突明细;
- 自动化测试、并发测试、权限测试和业务回归结果;
- 数据库迁移审批与执行结果;
- Jenkins Job、构建号、分支、commit SHA、镜像版本和下游结果;
- 健康检查、真实 API/浏览器验收证据;
- 告警和 Dashboard 截图/导出;
- 回滚/补偿演练记录;
- 产品、财务、技术的上线与灰度扩大结论。
## 十六、当前阻断项
截至 2026-08-10,本方案技术设计无架构阻断,可以进入 F0/F1 详细设计与开发准备;以下事项阻断生产历史迁移激活或客户开放:
1. M-BIZ-01 至 M-BIZ-10 尚未由产品/财务确认;
2. 线下已结算排除台账尚未提供,无法证明历史费用不会重复追收;
3. Firstleg 历史费用版本链和等价状态映射需要在迁移开发前以真实数据抽样确认;
4. 首批灰度客户、财务主体和时间范围尚未确定;
5. 财务服务尚未实施,Jenkins/Nacos/Gateway/数据库部署单元尚未建立;
6. 生产数据库迁移、生产发布和任何真实数据写入均需独立授权与上线审批。
这些阻断项不应通过默认 CNY、默认客户、默认未结算或直接导入应收来绕过。