Files
junhong_cmp_fiber/openspec/changes/archive/2026-04-07-asset-identifier-standardization/proposal.md
huang 80c6f6c756
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
主要变更:
- 新增 AssetIdentifier 模型及 Store,统一管理资产标识符(ICCID/IMEI/SN 等)
- 新增迁移:asset_identifier 表、order 表新增 asset_identifier 字段、iot_card.virtual_no NOT NULL 约束
- 资产 Handler/Service/Route 全面重构,支持标识符路由查询与解析
- 新增资产历史订单查询接口,支持跨设备/卡/钱包维度的订单聚合
- 设备与物联卡导入任务强制校验虚拟号,缺失时直接拒绝
- Excel 工具函数优化,前端导入指引文档同步更新
- 归档三个 OpenSpec 提案:asset-identifier-standardization、asset-historical-orders、import-mandatory-virtual-no
- 更新 OpenAPI 文档及相关 DTO

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-07 17:39:36 +08:00

54 lines
3.7 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.
## Why
当前系统的 B 端资产操作接口大量使用数据库主键 ID`/assets/:asset_type/:id/``/devices/:id/`)作为路径参数,导致接口语义模糊、前端被迫持有无业务含义的 ID、换货后旧 ID 失效等问题。与此同时IoT 卡和设备的虚拟号VirtualNo没有跨表全局唯一约束ICCID/VirtualNo 在多个子系统中的使用也不一致。现阶段系统尚处于开发测试期,是建立资产标识符规范的最佳窗口。
## What Changes
- **[BREAKING]** B 端资产操作接口路径参数统一改为资产标识符ICCID 或 VirtualNo废弃基于数据库主键 ID 的路由
- **[BREAKING]** 订单创建接口B 端 + C 端)从传入 `iot_card_id`/`device_id` 主键改为传入 `identifier` 标识符
- **[NEW]** 新增全局资产标识符注册表 `tb_asset_identifier`,在数据库层保证 ICCID/VirtualNo 跨 `tb_iot_card``tb_device` 两表全局唯一,防止并发写入冲突
- **[NEW]** 资产解析服务Resolve主路径改走注册表单次查询即可定位资产替代原有的跨表 OR 查询
- **[FIX]** 修复:已绑定设备的 IoT 卡(`is_standalone=false`)可被单独购买套餐的 Bug改为直接报错并引导用户至设备页面购买
- 订单查询列表新增按资产标识符过滤条件
- 订单响应新增资产标识符字段,前端无需二次查询
- 所有 B 端 `:id` 路由同步更新,前端需切换调用方式
## Capabilities
### New Capabilities
- `asset-identifier-registry`:全局资产标识符注册表(`tb_asset_identifier`)的模型定义、写入/查询接口,以及 Resolve 服务的注册表主路径改造
- `asset-identifier-routes`B 端统一标识符路由规范——将 `/assets/:asset_type/:id/*``/devices/:id/*``/iot-cards/:id/*` 全线迁移为 `/assets/:identifier/*``/devices/:virtual_no/*`
### Modified Capabilities
- `asset-resolve`:主查询路径改走 `tb_asset_identifier`IMEI/SN/MSISDN 降级为 fallback 模糊查询
- `order-management`CreateAdminOrderRequest 改用 `identifier`OrderResponse 新增 `asset_identifier` 字段OrderListRequest 新增 `identifier` 过滤条件
- `client-order-purchase`CreateOrderRequest 改用 `identifier`,系统内部解析资产类型
- `package-purchase-validation`:新增 `is_standalone` 校验——若卡已绑定设备则拒绝单卡购买套餐
## Impact
**受影响的代码**
- `internal/model/`:新增 `AssetIdentifier` 模型;`Order` 模型新增 `asset_identifier` 快照字段
- `internal/store/postgres/`:新增 `asset_identifier_store.go``order_store.go` 新增标识符过滤
- `internal/service/asset/``Resolve` 方法改走注册表
- `internal/service/purchase_validation/`:新增 `is_standalone` 校验
- `internal/handler/admin/``asset.go``device.go``iot_card.go``order.go` 全面更新路径参数和请求/响应 DTO
- `internal/handler/app/``client_order.go` 更新请求 DTO
- `internal/routes/``asset.go``device.go``iot_card.go``order.go` 路由重注册
- `internal/model/dto/``asset_dto.go``order_dto.go``client_order_dto.go` 字段变更
- `migrations/`:新增迁移文件创建 `tb_asset_identifier`
**受影响的 APIBREAKING**
- `GET /api/admin/assets/:asset_type/:id/*`7 个端点)
- `POST /api/admin/assets/device/:device_id/stop|start`
- `DELETE /api/admin/devices/:id`
- `GET|POST|DELETE /api/admin/devices/:id/cards*`
- `PATCH /api/admin/devices/:id/deactivate`
- `PATCH /api/admin/iot-cards/:id/deactivate`
- `POST /api/admin/orders`(请求体变更)
- `POST /api/c/v1/orders/create`(请求体变更)
**前端影响**:所有使用 `asset_id` 做路径参数的页面必须切换为使用 `identifier`ICCID 或 VirtualNo