## Why

现有 `CardReplacementRecord` 模型仅支持简单换卡，无法满足完整换货需求：缺少收货地址、快递信息、设备换货、全量数据迁移等功能。客户端换货场景中，后台发起换货 → 客户端收到通知填写收货信息 → 后台发货+确认完成（含全量迁移）→ 旧资产可"转新"重新销售，是一个跨后台/客户端的完整业务闭环。

**前置依赖**：提案 0（`asset_status`/`generation` 字段已就位）、提案 1（客户端认证）。

## What Changes

### 新增模型

- **ExchangeOrder（换货单）**：完整的换货生命周期模型，包含旧/新资产信息、收货地址、物流信息、迁移状态。状态机：`1-待填写信息 → 2-待发货 → 3-已发货待确认 → 4-已完成`，1 或 2 时可取消(→5)

### 删除旧模型

- **CardReplacementRecord**：表改名为 `tb_card_replacement_record_legacy`，代码引用替换为 ExchangeOrder

### 后台换货管理（模块 H，7 个接口）

- **H1 发起换货** `POST /api/admin/exchanges`：验证资产无进行中换货单，创建 status=1
- **H2 换货列表** `GET /api/admin/exchanges`：支持状态筛选、资产标识符搜索、时间范围
- **H3 换货详情** `GET /api/admin/exchanges/:id`
- **H4 发货** `POST /api/admin/exchanges/:id/ship`：填写物流信息+新资产标识符，验证 status=2、同类型资产、新资产 asset_status=1（在库）
- **H5 确认完成** `POST /api/admin/exchanges/:id/complete`：验证 status=3，如 migrate_data=true 则执行全量迁移（11 张表事务内操作），旧资产 asset_status→3
- **H6 取消换货** `POST /api/admin/exchanges/:id/cancel`：验证 status IN (1,2)，已发货不可取消
- **H7 旧资产转新** `POST /api/admin/exchanges/:id/renew`：旧资产 asset_status 从 3→1，generation+1，清除客户绑定和累计状态，创建新空钱包

### 客户端换货（模块 G，2 个接口）

- **G1 查询换货通知** `GET /api/c/v1/exchange/pending?identifier=xxx`：查是否有进行中的换货单
- **G2 填写收货信息** `POST /api/c/v1/exchange/:id/shipping-info`：验证 status=1，更新收货信息，status→2

### 换货状态机

```
后台发起换货
    │
    ▼
┌─────────────────────┐
│ 1-待填写信息        │ ←── ExchangeOrder 创建
│ (等待客户端填写)     │
└──────────┬──────────┘
           │
    客户端填写收货信息 [G2]
           │
           ▼
┌─────────────────────┐
│ 2-待发货            │
│ (等待后台填写物流)   │
└──────────┬──────────┘
           │
    后台发货 [H4] (填物流+新资产)
           │
           ▼
┌─────────────────────┐
│ 3-已发货待确认      │
│ (等待后台确认完成)   │
└──────────┬──────────┘
           │
    后台确认完成 [H5]
    (可选: 全量迁移)
           │
           ▼
┌─────────────────────┐
│ 4-已完成            │
└─────────────────────┘

取消: status=1 或 2 时可取消 → 5-已取消
已发货(status=3)后不可取消
```

### 全量迁移流程（H5 确认完成时触发）

```
确认完成 (migrate_data=true)
    │
    ▼
事务开始
    │
    ├── 1. 钱包余额转移
    │   旧 AssetWallet.Balance → 新 AssetWallet
    │   生成迁移流水 AssetWalletTransaction
    │
    ├── 2. 生效中套餐关联新资产
    │   PackageUsage WHERE iot_card_id/device_id=旧 AND status IN (生效中)
    │   → UPDATE iot_card_id/device_id = 新
    │
    ├── 3. 累计充值/首充状态迁移
    │   IotCard/Device 的 AccumulatedRecharge/FirstCommissionPaid
    │   等字段复制到新资产
    │
    ├── 4. 标签复制
    │   ResourceTag WHERE resource_type=? AND resource_id=旧
    │   → 为新资产创建相同标签
    │
    ├── 5. 个人客户绑定更新
    │   PersonalCustomerDevice WHERE virtual_no=旧虚拟号
    │   → UPDATE virtual_no = 新虚拟号
    │
    ├── 6. 旧资产标记
    │   旧资产 asset_status → 3（已换货）
    │
    └── 7. 记录迁移信息
        ExchangeOrder: migration_completed=true,
        migration_balance=转移金额
    │
    ▼
事务提交
    │
    ▼
ExchangeOrder status → 4（已完成）

注意:
- 设备换设备时不迁移 DeviceSimBinding（卡绑定关系）
- 新设备自带新的 SIM 卡，旧设备的卡绑定保持不变
- 保留不修改的表: tb_order, tb_commission, tb_data_usage_record,
  tb_asset_recharge_record（历史记录保留，通过 generation 隔离）
```

### 转新流程（H7）

```
旧资产 (asset_status=3 已换货)
    │
    ▼
POST /api/admin/exchanges/:id/renew
    │
    ├── 1. asset_status: 3 → 1（在库）
    ├── 2. generation: +1（进入新世代）
    ├── 3. 清除: 累计充值状态、首充触发状态
    ├── 4. 清除: PersonalCustomerDevice 绑定
    ├── 5. 创建新空钱包（新 wallet_id）
    └── 6. 不删除历史数据（通过 generation 隔离）
    │
    ▼
旧资产可重新销售给新客户
新客户查询时按当前 generation 过滤
看不到旧周期数据
```

## Capabilities

### New Capabilities

- `exchange-order-model`：ExchangeOrder 模型定义、状态机、状态常量、换货单号生成规则
- `exchange-admin-management`：后台换货管理 CRUD（H1~H3）、发货（H4，含同类型资产校验+新资产在库校验）、确认完成（H5，含全量迁移事务）、取消（H6）、转新（H7，含 generation 自增+状态重置）
- `exchange-data-migration`：全量迁移逻辑，11 张数据表的事务内操作规则，设备不迁移卡绑定的特殊规则
- `exchange-client-notification`：客户端换货通知查询（G1）、收货信息填写（G2）

### Modified Capabilities

- `iot-card`：IotCard 新增换货相关行为——`asset_status=3` 标记、转新时 generation 自增+状态重置
- `device`：Device 同上
- `personal-customer`：PersonalCustomerDevice 绑定关系在换货迁移时更新虚拟号
- `card-replacement`：**REMOVED** — CardReplacementRecord 模型废弃，表改名为 legacy，代码引用替换为 ExchangeOrder

## Impact

- **新增文件**：`internal/model/exchange_order.go`（模型）；`internal/handler/admin/exchange.go`（后台 Handler）；`internal/handler/app/client_exchange.go`（客户端 Handler）；`internal/service/exchange/service.go`（Service，含迁移逻辑）；`internal/store/postgres/exchange_order_store.go`（Store）；DTO 文件；迁移文件；常量和错误码
- **修改文件**：`internal/model/card_replacement.go`（删除或标记废弃）；`internal/store/postgres/iot_card_store.go`（移除 `is_replaced` 过滤改为查新表）；`internal/model/system.go`（AutoMigrate 移除旧模型+注册新模型）；`internal/routes/`（新增后台+客户端路由）；`internal/bootstrap/`（注册新模块）；`cmd/api/docs.go` + `cmd/gendocs/main.go`（文档生成器）
- **新增 API 路由**：后台 `/api/admin/exchanges/` 下 7 个端点 + 客户端 `/api/c/v1/exchange/` 下 2 个端点
- **数据库变更**：新建 `tb_exchange_order` 表；旧表 `tb_card_replacement_record` 改名为 `tb_card_replacement_record_legacy`
- **全量迁移涉及 11 张表**：`tb_asset_wallet`、`tb_asset_wallet_transaction`、`tb_asset_recharge_record`、`tb_package_usage`、`tb_package_usage_daily_record`、`tb_order`、`tb_commission`、`tb_data_usage_record`、`tb_resource_tag`、`tb_personal_customer_device`、`tb_iot_card`/`tb_device`
