## 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` 与抽样多卡设备比对资产信息外层实名、卡列表当前卡标识。