Files
break 54c4ec7ba4
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 14m42s
fix(设备实名): 无当前卡时按绑定卡实名回退并初始化单槽当前卡
- 设备资产解析外层 real_name_status:存在当前使用卡时沿用该卡状态,无任何当前卡时任一有效绑定卡已实名即视为已实名
- 手工绑定与设备导入:设备最大槽位为 1 且有效绑定唯一时,在同一事务内将该绑定初始化为当前使用卡;多卡设备不推断
- 同步 asset-device、personal-customer 主 Spec;归档变更并附存量核对清单(75 条单槽唯一待修复绑定,其中 16 条已实名)
2026-09-18 17:49:12 +08:00

78 lines
5.5 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
- 设备资产解析在 `internal/service/asset` 内一次组装绑定卡、外层实名与套餐摘要C 端资产信息 DTO 只暴露 `real_name_status` 一个外层实名信号(不含 `real_name_at`),逐卡实名由卡列表返回。
- `is_current` 目前只在运营商设备观测、显式切卡、解绑与删设备路径写入导入与手工绑定创建时不写DB 默认 false。
- 设备在运营商侧的识别标识为 IMEI 优先、空则用 SN读取侧资产信息实时状态与观测侧卡观测序列口径一致。
- 生产只读核对:有有效绑定的设备 19031 台,其中 639 台无任何当前卡标识;这 639 台里 76 台存在已实名绑定卡16 台为单槽单卡,其余为多卡设备)。
- 既有约束:自动化测试当前为 N/A用户决策生产写入由维护者按生产运行说明执行Agent 只做只读诊断。
## Goals / Non-Goals
**Goals:**
- 让「设备没有任何当前卡标识」这一分支不再把已实名设备展示为未实名。
- 让单槽单卡设备在绑定后即具备当前卡标识,消除「当前卡」展示为空的产生条件。
- 给存量同类数据一个可复核、可回滚的核对与修复口径。
**Non-Goals:**
- 不改变存在当前卡标识时的判定结果。
- 不改变管理端设备列表既有的「任一有效绑定卡已实名」筛选,以及设备激活状态判定。
- 不为多卡设备推断当前卡,不改变运营商观测/切卡对 `is_current` 的写入职责。
- 不处理运营商侧设备登记(如 Gateway 返回设备号无效)的修复。
- 不引入 Schema 变更、迁移、一次性常驻命令或自动化测试。
## Decisions
### 1. 回退判定放在读取侧,不改写业务事实
无当前卡时,外层实名按有效绑定卡的实名状态取或(任一已实名即已实名),实现位置为设备资产解析中的外层实名判定。
- 理由:读取侧回退只影响展示,不把「哪张卡在用」变成猜测事实;多卡设备无当前卡写侧无法推断,回填会污染 `is_current` 语义。
- 备选:在所有情况下都改为「任一有效绑定卡已实名」(否决,等于回退既有当前卡语义);在读取时按最大槽位推断当前卡(否决,会让 `is_current` 出现第二套判定来源)。
### 2. 保留「当前卡优先」分支,仅补分支缺口
存在 `is_current=true` 的有效绑定时沿用该卡实名状态;仅在一条当前卡标识都没有时进入回退。如此本 change 不改变有当前卡设备的既有返回。
### 3. 绑定创建时初始化单槽单卡的当前卡标识
判据:设备最大槽位为 1且绑定创建后该设备的有效绑定唯一。此时设备只有唯一的可能当前卡标记为当前使用卡是事实而非猜测。写入与绑定创建放在同一事务保证绑定与当前卡标识一致可见导入与手工绑定两条创建路径都要覆盖。
- 理由:多卡设备的当前卡必须来自运营商观测或显式切卡,绑定时不猜。
- 备选:绑定后异步触发一次设备观测(否决,依赖外部调用且失败时仍留空)。
### 4. 存量数据走受控人工修复,不写一次性代码
只读核对口径(识别待修复绑定):
```sql
SELECT d.id AS device_id, b.id AS binding_id, b.iot_card_id
FROM tb_device_sim_binding b
JOIN tb_device d ON d.id = b.device_id AND d.deleted_at IS NULL
WHERE b.bind_status = 1
AND d.max_sim_slots = 1
AND NOT EXISTS (SELECT 1 FROM tb_device_sim_binding x
WHERE x.device_id = b.device_id AND x.bind_status = 1 AND x.is_current)
AND (SELECT count(*) FROM tb_device_sim_binding y
WHERE y.device_id = b.device_id AND y.bind_status = 1) = 1;
```
受控修复:仅对上述结果集内的绑定置 `is_current = true`,同一设备只允许一条;执行前留存核对结果,执行后抽样比对设备卡列表与资产信息。
- 理由:生产写操作由维护者执行;一次性命令会长期留在仓库成为隐性维护面。
- 备选:新增数据修复命令或迁移(否决,超出必要范围且规则与绑定创建规则重复)。
## Risks / Trade-offs
- [无当前卡集合里包含「当前卡标识因观测缺失而丢失」的设备,回退可能把实际在用卡未实名的设备显示为已实名] → 以绑定卡本地事实为准,卡列表仍逐卡返回真实状态;上游设备登记类问题另行在运维侧处理,不在本 change。
- [绑定即置当前卡可能让设备观测的期望值提前满足] → 判据限定最大槽位为 1 且有效绑定唯一,此时可被切换的目标只有同一张卡;多卡设备不写入。
- [存量修复误伤多卡或重复当前卡] → 核对口径限定单槽且唯一有效绑定,修复语句限定 `bind_status = 1` 并保证同一设备至多一条 `is_current`;先只读核对,再小批执行。
- [C 端展示口径变化无自动化测试覆盖] → 按用户既有决策不新增自动化测试改为对案例设备19090与抽样设备做发布后实接口核对。
## Migration Plan
1. 代码发布:无 Schema 变更,随常规二进制发布生效;展示口径回退只需回滚二进制,无数据残留。
2. 存量修复:先在只读环境按核对口径确认结果集,再由维护者按生产运行说明执行修复;不随发布自动执行。
3. 发布后核对:以案例设备 `90001595626` 与抽样多卡设备比对资产信息外层实名、卡列表当前卡标识。