# Capability: 资产操作路由标识符标准化

## Purpose

定义 B 端资产操作类接口统一使用资产标识符（ICCID 或 VirtualNo）作为路径参数的规范，废弃原有基于数据库主键 ID 的路由，并规定标识符解析的性能要求。

## Requirements

### Requirement: B 端资产操作接口统一使用标识符路径参数

B 端所有资产操作类接口 SHALL 使用资产标识符（ICCID 或 VirtualNo）作为路径参数，废弃原有基于数据库主键 ID 的路由。系统内部通过注册表将标识符解析为资产实体，Handler 层无需关心 ID。

**标识符规则**：
- IoT 卡：接受 ICCID 或 VirtualNo（均为全局唯一）
- 设备：接受 VirtualNo（全局唯一）
- 不接受 IMEI/SN/MSISDN（非唯一，仅 Resolve 的 fallback 路径支持）

**废弃的旧路由 → 新路由映射**：

| 旧路由（废弃） | 新路由 |
|---|---|
| `GET /api/admin/assets/:asset_type/:id/realtime-status` | `GET /api/admin/assets/:identifier/realtime-status` |
| `POST /api/admin/assets/:asset_type/:id/refresh` | `POST /api/admin/assets/:identifier/refresh` |
| `GET /api/admin/assets/:asset_type/:id/packages` | `GET /api/admin/assets/:identifier/packages` |
| `GET /api/admin/assets/:asset_type/:id/current-package` | `GET /api/admin/assets/:identifier/current-package` |
| `GET /api/admin/assets/:asset_type/:id/wallet` | `GET /api/admin/assets/:identifier/wallet` |
| `GET /api/admin/assets/:asset_type/:id/wallet/transactions` | `GET /api/admin/assets/:identifier/wallet/transactions` |
| `PATCH /api/admin/assets/:asset_type/:id/polling-status` | `PATCH /api/admin/assets/:identifier/polling-status` |
| `POST /api/admin/assets/device/:device_id/stop` | `POST /api/admin/assets/:identifier/stop` |
| `POST /api/admin/assets/device/:device_id/start` | `POST /api/admin/assets/:identifier/start` |
| `POST /api/admin/assets/card/:iccid/stop` | `POST /api/admin/assets/:identifier/stop`（合并） |
| `POST /api/admin/assets/card/:iccid/start` | `POST /api/admin/assets/:identifier/start`（合并） |
| `DELETE /api/admin/devices/:id` | `DELETE /api/admin/devices/:virtual_no` |
| `GET /api/admin/devices/:id/cards` | `GET /api/admin/devices/:virtual_no/cards` |
| `POST /api/admin/devices/:id/cards` | `POST /api/admin/devices/:virtual_no/cards` |
| `DELETE /api/admin/devices/:id/cards/:cardId` | `DELETE /api/admin/devices/:virtual_no/cards/:iccid` |
| `PATCH /api/admin/devices/:id/deactivate` | `PATCH /api/admin/assets/:identifier/deactivate` |
| `PATCH /api/admin/iot-cards/:id/deactivate` | `PATCH /api/admin/assets/:identifier/deactivate`（合并） |

#### Scenario: 通过 ICCID 操作 IoT 卡
- **WHEN** 管理员请求 `GET /api/admin/assets/898600XXXXXXXX/packages`
- **THEN** 系统解析 ICCID，找到对应 IoT 卡，返回该卡的套餐列表

#### Scenario: 通过 VirtualNo 操作设备
- **WHEN** 管理员请求 `POST /api/admin/assets/DEV-001/stop`
- **THEN** 系统解析 VirtualNo，找到对应设备，执行批量停机（停该设备下所有已实名卡）

#### Scenario: 通过 VirtualNo 操作绑定了设备的 IoT 卡（停机）
- **WHEN** 管理员请求 `POST /api/admin/assets/CARD-001/stop`，CARD-001 是 IoT 卡的 VirtualNo
- **THEN** 系统解析 VirtualNo，找到 IoT 卡，执行单卡停机

#### Scenario: stop/start 接口对卡和设备行为差异
- **WHEN** identifier 解析为 IoT 卡时调用 stop
- **THEN** 执行单卡停机
- **WHEN** identifier 解析为设备时调用 stop
- **THEN** 执行设备停机（批量停机该设备下所有已实名卡）

#### Scenario: 标识符不存在
- **WHEN** 管理员请求的 `:identifier` 在注册表和 fallback 查询中均未找到对应资产
- **THEN** 返回 HTTP 404，错误消息"资产不存在"

#### Scenario: 无权限操作该资产
- **WHEN** 代理用户请求的 identifier 对应的资产不属于该代理的数据权限范围
- **THEN** 返回 HTTP 403，错误消息"无权限操作该资源或资源不存在"

#### Scenario: 设备绑卡管理使用设备 VirtualNo
- **WHEN** 管理员请求 `GET /api/admin/devices/DEV-001/cards`
- **THEN** 系统通过 VirtualNo 找到设备，返回该设备绑定的卡列表

#### Scenario: 设备解绑卡使用 ICCID
- **WHEN** 管理员请求 `DELETE /api/admin/devices/DEV-001/cards/898600XXXXXXXX`
- **THEN** 系统通过 VirtualNo 找到设备，通过 ICCID 找到卡，执行解绑

---

### Requirement: 新路由下标识符的解析性能

资产操作接口中标识符解析 SHALL 优先走注册表（单次精确查询），保证解析延迟不超过 10ms（在正常数据库负载下）。

#### Scenario: 注册表命中路径
- **WHEN** 请求携带的 identifier 存在于 `tb_asset_identifier`
- **THEN** 系统单次查询注册表得到 asset_type 和 asset_id，无需扫描 tb_device 或 tb_iot_card

#### Scenario: 注册表未命中（fallback）
- **WHEN** 请求携带的 identifier 不在注册表（如 IMEI 或旧数据）
- **THEN** 系统 fallback 到原有多字段 OR 查询，同样能定位资产（性能稍低，为次要路径）
