All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 10m49s
3.1 KiB
3.1 KiB
Context
现有 step2 依据旧套餐的类型、状态、生效时间和到期时间分类生命周期;分类后只要同一资产有多条 active 就阻断。奇成数据中的少量续费记录缺少生效时间且仍标为正常,无法从通用字段推断先后关系。
Goals / Non-Goals
Goals:
- 用映射配置表达经运营确认的逐卡裁决。
- 在生成 SQL 前验证裁决完整性,确保不静默丢失或重复迁移套餐。
- 将覆盖后的状态写入现有审核产物,保持可追溯性。
Non-Goals:
- 不修改奇成老库记录。
- 不依据到期时间、创建时间或套餐时长引入全局自动裁决规则。
- 不改变未覆盖资产的现有分类和阻断逻辑。
Decisions
使用 ICCID 与生命周期 ID 的显式覆盖
在 mapping.yaml 增加 package_lifecycle_overrides。每项包含完整 ICCID、一个 active_life_id、可选的 pending_life_ids 与 skipped_life_ids。
生命周期 ID 是老库主键,避免到期时间存在 UTC/本地时区展示差异或同日期重复时的歧义。完整 ICCID 与 step2 的资产键一致。
未采用“最早到期记录为当前”的规则:已确认的第三张异常卡表明未来记录并不必然均应作为待生效迁移。
覆盖在冲突检测前重分类
先获取老库原始生命周期及既有通用分类,再按 ICCID 应用覆盖,最后执行现有映射、唯一 active 校验与 SQL 生成。覆盖只改变配置明确列出的记录状态;同卡其他通用分类为 active 或 pending 的正式套餐必须也被覆盖明确裁决,否则报配置错误并阻断该资产。
配置与运行时双重校验
加载时校验字段格式、同一覆盖内 ID 不重复且状态集合不重叠。读取老库后校验每个被引用 ID 都属于该 ICCID 的 tbl_card_life 记录、active 恰好一个、覆盖未遗漏其他原本可迁移记录。错误沿用 step2 的错误 CSV,且不生成该资产套餐 SQL。
本批已确认裁决
实现时将下列裁决写入迁移配置:
| ICCID | active | pending | skipped |
|---|---|---|---|
89860624630055027529 |
DD74BA52EC8242FF94815532DC19389B |
AB77C853EEF444E2AF20A8475F61CFA7 |
无 |
89860624630055035589 |
4ACDBC19027A4E90BF500F515093E0A3 |
2D247EF7877C4CE18E74EF9B139B7FCD |
无 |
89860624590009246403 |
186B9062F3904AACB4A231041B6B5E98 |
无 | EB006800000D49EB9A18024922657680 |
Risks / Trade-offs
- [运营裁决填写错误] → 覆盖按老库主键校验,并在审核 CSV 输出覆盖后的每条记录状态。
- [老库后续新增套餐记录] → 完整性校验拒绝遗漏的可迁移记录,要求重新确认配置。
- [覆盖配置被误用于常规数据] → 不提供全局或通配符规则,覆盖仅作用于单一完整 ICCID。
Migration Plan
- 发布包含覆盖能力与上述三项配置的迁移脚本。
- 在隔离环境重新生成 step2,核对三张卡各一条 active,前两张各一条 pending,第三张无额外套餐。
- 线上仅执行经审核的生成 SQL;若需回退,移除对应覆盖后重新生成,不写老库。