Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
- 新增 GET /api/admin/devices/by-imei/:imei 接口,支持通过设备号查询设备详情 - 新增 GET /api/admin/iot-cards/by-iccid/:iccid 接口,支持通过ICCID查询单卡详情 - 添加对应的 Service 层方法和 Handler - 更新 OpenAPI 文档 - 添加集成测试并修复测试环境配置(使用环境变量) - 归档已完成的 OpenSpec 变更记录 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
3.2 KiB
3.2 KiB
修复设备-SIM卡绑定隐患
Why
当前设备-SIM卡绑定机制存在多个隐患:竞态条件可能导致同一张卡被绑定到多个设备、设备导入时未校验卡的归属权导致数据不一致、部分绑定失败时缺乏清晰反馈、以及代码组织不合理。这些问题在生产环境的高并发场景下会导致数据完整性问题,需要立即修复。
What Changes
1. 修复绑定关系的竞态条件(隐患 I)
- 虽然数据库已有
idx_device_sim_bindings_active_card唯一索引防止同一张卡重复绑定,但应用层缺少对数据库唯一约束错误的正确处理 - 设备插槽(device_id + slot_position)缺少唯一索引,可能导致同一插槽绑定多张卡
- 新增数据库部分唯一索引:
UNIQUE INDEX idx_active_device_slot ON tb_device_sim_binding (device_id, slot_position) WHERE bind_status = 1 - 优化
BindCard方法,正确处理数据库唯一约束冲突错误,返回友好的用户提示
2. 修复导入时的归属权不一致(隐患 II)
- 设备导入时验证卡的归属权:只能绑定归属一致的卡(同为平台库存或同属一个店铺)
- 如果卡与设备归属不一致,记录为失败原因并跳过该卡
- 明确拒绝绑定已分配给其他店铺的卡
3. 修复导入时的部分成功问题(隐患 III)
- 当 CSV 行指定了多张卡但只有部分有效时,需要明确反馈哪些卡绑定成功、哪些失败
- 新增
warningItems字段记录部分成功的情况 - 更新导入结果结构,区分"完全成功"、"部分成功"和"失败"三种状态
- BREAKING:
DeviceImportTask模型新增warning_count和warning_items字段
4. 代码组织优化
- 将
DeviceSimBinding模型从internal/model/package.go移动到internal/model/device_sim_binding.go
Capabilities
New Capabilities
无新增能力。
Modified Capabilities
device-management: 优化设备-SIM卡绑定逻辑,增强并发安全性和归属权校验device-import: 增强导入时的卡归属权校验和部分成功反馈机制
Impact
数据库
- 新增迁移文件,添加
tb_device_sim_binding表的部分唯一索引 - 新增迁移文件,
tb_device_import_task表新增warning_count和warning_items字段
代码变更
| 文件 | 变更类型 | 说明 |
|---|---|---|
internal/model/package.go |
删除 | 移除 DeviceSimBinding 定义 |
internal/model/device_sim_binding.go |
新增 | DeviceSimBinding 模型独立文件 |
internal/model/device_import_task.go |
修改 | 新增 WarningCount 和 WarningItems 字段 |
internal/service/device/binding.go |
修改 | 优化 BindCard 错误处理 |
internal/task/device_import.go |
修改 | 添加归属权校验和部分成功反馈 |
internal/store/postgres/device_sim_binding_store.go |
修改 | 新增唯一约束错误检测方法 |
API 影响
- 设备导入任务结果 API 响应结构新增
warning_count和warning_items字段 - 现有 API 行为不变,仅增强错误信息的准确性
向后兼容性
- API 响应新增字段为可选字段,不影响现有客户端
- 数据库迁移为增量变更,不影响现有数据