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

112 lines
5.1 KiB
Markdown
Raw 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.
## 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_position``iccid` 的成对关系,或者使用等价的固定槽位结构。
**理由**
- 只有解析层知道 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”这会影响使用体验但不阻塞后端修复。