## 1. 数据库迁移：全局标识符注册表

- [x] 1.1 创建迁移文件：`tb_asset_identifier` 表（identifier UNIQUE、asset_type、asset_id、created_at），建立 `idx_asset_identifier_asset(asset_type, asset_id)` 索引
- [x] 1.2 执行迁移，验证表结构和唯一约束正确

## 2. 数据层：AssetIdentifier 模型与 Store

- [x] 2.1 创建 `internal/model/asset_identifier.go`：定义 `AssetIdentifier` 结构体（含 GORM 标签、TableName）
- [x] 2.2 创建 `internal/store/postgres/asset_identifier_store.go`：实现 `Register(ctx, identifier, assetType, assetID)`（写入注册表）、`FindByIdentifier(ctx, identifier)`（精确查询）、`DeleteByAsset(ctx, assetType, assetID)`（删除资产时清理）
- [x] 2.3 在 `internal/bootstrap/stores.go` 注入 `AssetIdentifierStore`

## 3. 数据层：Order 模型新增 asset_identifier 字段

- [x] 3.1 创建迁移文件：`tb_order` 表增加 `asset_identifier VARCHAR(100)` 字段
- [x] 3.2 更新 `internal/model/order.go`：新增 `AssetIdentifier string` 字段（含 GORM 标签和注释）
- [x] 3.3 更新 `internal/store/postgres/order_store.go`：列表查询新增 `identifier` 过滤条件（精确匹配 `asset_identifier`）

## 4. 服务层：Resolve 改走注册表

- [x] 4.1 更新 `internal/service/asset/service.go`：`Resolve` 方法优先查 `AssetIdentifierStore.FindByIdentifier()`，命中则按 asset_type 查对应表；未命中 fallback 原有逻辑
- [x] 4.2 在 `AssetService` 中注入 `AssetIdentifierStore` 依赖

## 5. 服务层：purchase_validation 增加 is_standalone 校验

- [x] 5.1 更新 `internal/service/purchase_validation/service.go`：在 `ValidateCardPurchase()` 中增加 `if !card.IsStandalone { return error "该卡已绑定设备，请前往设备页面购买套餐" }` 校验（在套餐校验之前执行）

## 6. 服务层：资产创建/删除时同步注册表

- [x] 6.1 更新设备导入任务 `internal/task/device_import.go`：创建设备成功后在同一事务内调用 `AssetIdentifierStore.Register()` 注册 VirtualNo；若冲突则拒绝该行
- [x] 6.2 更新 IoT 卡导入任务 `internal/task/iot_card_import.go`：创建卡成功后注册 ICCID（必填）和 VirtualNo（如有）到注册表；冲突则拒绝该行
- [x] 6.3 更新设备/IoT 卡的软删除逻辑：删除时调用 `AssetIdentifierStore.DeleteByAsset()` 清理注册表

## 7. 服务层：订单创建改用 identifier

- [x] 7.1 更新 `internal/service/order/service.go`（B 端）：`Create()` 方法接收 `identifier` 字符串，内部调用 `AssetService.Resolve()` 解析资产，不再接受 `iot_card_id`/`device_id`；写入订单时填入 `asset_identifier` 快照字段
- [x] 7.2 更新 `internal/service/client_order/service.go`（C 端）：同上，接收 `identifier`，解析后写入 `asset_identifier` 快照

## 8. DTO 层：更新请求/响应结构

- [x] 8.1 更新 `internal/model/dto/order_dto.go`：`CreateAdminOrderRequest` 去掉 `IotCardID`/`DeviceID`/`OrderType`，新增 `Identifier string`；`OrderResponse` 新增 `AssetIdentifier string` 和 `AssetType string`；`OrderListRequest` 新增 `Identifier string`
- [x] 8.2 更新 `internal/model/dto/client_order_dto.go`（`CreateOrderRequest`）：同上，去掉 `IotCardID`/`DeviceID`/`OrderType`，新增 `Identifier string`
- [x] 8.3 更新 `internal/model/dto/asset_dto.go`：`AssetTypeIDRequest` 废弃，`AssetResolveRequest` 确认 `Identifier` 字段已有；新增 `AssetIdentifierRequest`（路径参数，供操作接口使用）
- [x] 8.4 确认 `AssetResolveResponse` 新增 `Identifier` 字段（回传请求中使用的标识符）

## 9. Handler 层：B 端资产操作接口更新

- [x] 9.1 更新 `internal/handler/admin/asset.go`：`RealtimeStatus`/`Refresh`/`Packages`/`CurrentPackage`/`UpdatePollingStatus`/`StopDevice`/`StartDevice`/`StopCard`/`StartCard` 均改为从路径参数 `:identifier` 读取标识符，调用 Resolve 解析后操作；合并 Stop/Start 卡和设备为统一的 `Stop`/`Start` handler（内部按资产类型分支）
- [x] 9.2 更新 `internal/handler/admin/asset.go`：新增 `Deactivate` handler（合并 IoT 卡和设备停用，原 `/iot-cards/:id/deactivate` 和 `/devices/:id/deactivate`）
- [x] 9.3 更新 `internal/handler/admin/device.go`：`Delete`/`ListCards`/`BindCard`/`UnbindCard` 改为从路径参数 `:virtual_no` 读取设备标识；`UnbindCard` 第二段路径参数改为 `:iccid`

## 10. Handler 层：B 端订单 Handler 更新

- [x] 10.1 更新 `internal/handler/admin/order.go`：`Create` handler 解析 `CreateAdminOrderRequest.Identifier` 字段，移除 `IotCardID`/`DeviceID` 解析逻辑；`List` handler 支持 `identifier` query 参数传入 Store 过滤

## 11. Handler 层：C 端订单 Handler 更新

- [x] 11.1 更新 `internal/handler/app/client_order.go`：`CreateOrder` handler 解析 `CreateOrderRequest.Identifier`，移除旧字段解析

## 12. 路由层：重注册所有受影响路由

- [x] 12.1 更新 `internal/routes/asset.go`：将所有 `:asset_type/:id` 路由改为 `:identifier`；合并卡/设备的 stop/start/deactivate 路由
- [x] 12.2 更新 `internal/routes/device.go`：`/:id` 改为 `/:virtual_no`；解绑路由 `/:id/cards/:cardId` 改为 `/:virtual_no/cards/:iccid`
- [x] 12.3 更新 `internal/routes/iot_card.go`：移除 `/:id/deactivate`（已并入 asset.go 的统一路由）
- [x] 12.4 更新 `internal/routes/order.go`：无路由变更，仅确认 Handler 已更新

## 13. 文档生成器更新

- [x] 13.1 更新 `cmd/api/docs.go` 和 `cmd/gendocs/main.go`：确保新 Handler 方法已注册（Deactivate 等新合并 handler 需加入）
- [x] 13.2 执行 `go run cmd/gendocs/main.go` 重新生成 OpenAPI 文档，验证新路由和 DTO 正确体现

## 14. 验证

- [x] 14.1 构建验证：`go build ./...` 无编译错误
- [x] 14.2 LSP 诊断：对所有修改文件运行 lsp_diagnostics，无错误/警告
- [ ] 14.3 接口验证（使用 PostgreSQL MCP 和 curl）：
  - 通过 ICCID 调用 `GET /api/admin/assets/:identifier/packages` 返回正确套餐列表
  - 通过 VirtualNo 调用 `POST /api/admin/assets/:identifier/stop` 执行停机
  - 使用绑定设备的卡 identifier 创建订单，验证返回"该卡已绑定设备"错误
  - 使用独立卡 identifier 创建订单成功，OrderResponse 包含 `asset_identifier` 字段
  - 并发写入同一 VirtualNo 到注册表，验证只有一条成功
- [ ] 14.4 订单列表验证：`GET /api/admin/orders?identifier=CARD-001` 返回该资产的订单
