Files
junhong_cmp_fiber/openspec/changes/fix-device-import-slot-mapping/design.md

5.1 KiB
Raw Blame History

Context

当前设备导入链路分为两段:

  1. pkg/utils/excel.go 负责按固定列读取设备导入 Excel。
  2. internal/task/device_import.go 负责校验卡并创建 tb_device_sim_binding 记录。

现状问题在于解析层只保留“非空 ICCID 列表”,没有保留“这个 ICCID 原来来自第几个卡槽列”。任务层随后按数组顺序写入 slot_position = i + 1,使得源文件中的空槽位被压缩。这个问题不涉及新接口,也不需要调整数据库结构,但会跨越解析层与任务执行层,适合先通过设计文档把数据语义钉死。

约束条件:

  • 必须遵守现有 Handler → Service → Store → Model 分层,不把槽位推断逻辑散落到多处。
  • 不新增表结构,不引入新依赖。
  • 设备导入仍走 Asynq 异步任务,保持当前事务边界和幂等行为。
  • 文档、日志、错误消息保持中文。

Goals / Non-Goals

Goals:

  • 保留 Excel 卡1~卡4 的原始槽位信息,避免前置空槽被压缩。
  • 让导入创建的 slot_position 与 Excel 列号严格一致。
  • max_sim_slots 之外的已填写 ICCID 给出明确失败规则。
  • 让后续查询设备绑定关系、切卡和运维判断都基于正确槽位数据。

Non-Goals:

  • 不新增或修改导入 API。
  • 不修复历史上已经错误导入的数据。
  • 不改变设备导入任务的权限、批次、实名策略等既有能力。
  • 不引入自动化测试要求,本次仅定义实现任务和手工验收路径。

Decisions

决策1在解析结果中保留“槽位 + ICCID”映射而不是仅保留 ICCID 列表

选择 设备导入解析结构需要显式表达每张卡来自哪个槽位,例如保留 slot_positioniccid 的成对关系,或者使用等价的固定槽位结构。

理由

  • 只有解析层知道 ICCID 来自哪一列,到了任务层再推断已经丢失上下文。
  • 把槽位语义前置到解析结果,可以让任务层只负责校验和落库,职责更清晰。

备选方案

  • 在任务层根据 ICCID 顺序反推槽位:不可行,前置空槽信息已丢失。
  • 用占位空字符串继续传 []string:可读性差,容易在后续处理中再次被压缩或忽略。

决策2绑定记录的 slot_position 直接使用源列位,不再使用连续下标

选择 创建设备卡绑定时,slot_position 必须直接使用解析出的槽位编号,而不是 i + 1

理由

  • tb_device_sim_binding.slot_position 本来就是槽位语义字段,应该存真实槽位。
  • 这样可以保持导入、查询、切卡、展示四个环节的语义一致。

备选方案

  • 继续写连续下标并在展示层修正:会污染底层数据,后续所有依赖槽位的逻辑都要补丁式兼容,不可接受。

决策3填写超过 max_sim_slots 的 ICCID 时整行失败

选择 如果 Excel 某行声明 max_sim_slots=2,却填写了 卡3卡4,该行导入失败,并给出明确失败原因。

理由

  • 超出设备最大槽位的绑定关系本身就是无效数据,不能静默忽略。
  • 失败比“部分导入 + 隐式丢弃”更容易让运营发现模板问题。

备选方案

  • 静默忽略越界槽位:会造成运营以为导入成功,但设备绑定不完整。
  • 自动上调 max_sim_slots:篡改源数据含义,不符合设备真实硬件能力。

决策4沿用现有事务边界不扩大导入任务架构

选择 仍在当前单行事务中完成设备创建、资产标识注册、卡绑定创建、卡快照更新和钱包创建,只替换槽位数据来源。

理由

  • 问题根因是数据语义错误,不是事务模型错误。
  • 保持现有事务边界可以减少改动范围和回归风险。

Risks / Trade-offs

  • [风险] 解析结构变更会波及设备导入任务中遍历 ICCID 的逻辑 → Mitigation只在设备导入专用结构中调整不影响卡导入等其他解析路径。

  • [风险] 历史错误导入的数据仍然存在,修复后新旧数据表现不一致 → Mitigation在提案中明确本次仅修复“后续导入行为”历史数据如需修复需单独立项。

  • [风险] 运营模板可能继续填写越界槽位,修复后失败数会上升 → Mitigation在失败原因中明确指出“填写槽位超出最大SIM槽数”并更新导入使用说明。

Migration Plan

  1. 先更新 device-import 规格,明确“列位即槽位”。
  2. 调整设备导入解析结构与任务执行逻辑。
  3. 使用手工构造的 Excel 样例做导入验收,覆盖空槽保留和越界失败两类场景。
  4. 上线后仅影响新导入任务,无需数据迁移。
  5. 如需回滚,恢复解析和绑定逻辑即可;本次不涉及表结构变更。

Open Questions

  • 历史错误导入的数据是否需要补录或脚本修正;如果需要,应拆成独立变更处理。
  • 前端模板文案是否要把 iccid_1 ~ iccid_4 明确标注为“槽1 ~ 槽4”这会影响使用体验但不阻塞后端修复。