# 客户端核心业务 API — 功能总结

## 概述

本提案为客户端（C 端个人客户）提供完整的业务接口，覆盖资产查询、钱包充值、套餐购买、实名跳转、设备操作 5 大模块共 18 个 API 端点，全部挂载在 `/api/c/v1/` 路径下。

**前置依赖**：提案 0（数据模型修复）、提案 1（C 端认证系统）。

## API 端点一览

### 模块 B：资产信息（4 个接口）

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/c/v1/asset/info` | B1 资产基本信息查询 |
| GET | `/api/c/v1/asset/packages` | B2 可购买套餐列表 |
| GET | `/api/c/v1/asset/package-history` | B3 历史套餐列表 |
| POST | `/api/c/v1/asset/refresh` | B4 手动刷新资产状态 |

### 模块 C：钱包与充值（5 个接口）

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/c/v1/wallet/detail` | C1 钱包详情（不存在自动创建） |
| GET | `/api/c/v1/wallet/transactions` | C2 钱包流水列表 |
| GET | `/api/c/v1/wallet/recharge-check` | C3 充值预检（强充检查） |
| POST | `/api/c/v1/wallet/recharge` | C4 创建充值订单（JSAPI 支付） |
| GET | `/api/c/v1/wallet/recharges` | C5 充值订单列表 |

### 模块 D：套餐购买（3 个接口）

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/c/v1/orders/create` | D1 创建套餐购买订单（含强充分流） |
| GET | `/api/c/v1/orders` | D2 套餐订单列表 |
| GET | `/api/c/v1/orders/:id` | D3 套餐订单详情 |

### 模块 E：实名认证（1 个接口）

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/c/v1/realname/link` | E1 获取实名跳转链接 |

### 模块 F：设备能力（5 个接口）

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/c/v1/device/cards` | F1 设备卡列表 |
| POST | `/api/c/v1/device/reboot` | F2 设备重启 |
| POST | `/api/c/v1/device/factory-reset` | F3 恢复出厂设置 |
| POST | `/api/c/v1/device/wifi` | F4 设置 WiFi |
| POST | `/api/c/v1/device/switch-card` | F5 切卡 |

## 核心设计决策

### 1. 数据权限绕过

客户端调用后台复用 Service 时，统一使用 `gorm.SkipDataPermission(ctx)` 绕过 shop_id 自动过滤，避免个人客户因非店铺主体被误拦截。

### 2. 归属校验

所有涉及资产操作的接口统一前置归属校验：查询 `PersonalCustomerDevice` 条件 `customer_id = 当前登录客户` 且 `virtual_no = 资产虚拟号`，未命中返回 403。

### 3. Generation 过滤

客户端历史查询统一附加 `WHERE generation = 资产当前 generation`，确保转手后数据隔离。

### 4. OpenID 安全规范

支付接口（C4/D1）所需 OpenID 由后端按 `customer_id + app_type` 查询，客户端禁止传入 OpenID。根据 `app_type` 选择对应的微信 AppID 创建支付实例。

### 5. 强充两阶段

- 第一阶段（同步）：充值入账、更新状态
- 第二阶段（异步 Asynq）：钱包扣款 → 创建订单 → 激活套餐

`AssetRechargeRecord.auto_purchase_status` 字段追踪异步状态（pending/success/failed）。

## 新增文件

```
internal/model/dto/client_asset_dto.go            # 资产模块 DTO
internal/model/dto/client_wallet_dto.go            # 钱包模块 DTO
internal/model/dto/client_order_dto.go             # 订单模块 DTO
internal/model/dto/client_realname_device_dto.go   # 实名+设备模块 DTO
internal/handler/app/client_asset.go               # 资产 Handler
internal/handler/app/client_wallet.go              # 钱包 Handler
internal/handler/app/client_order.go               # 订单 Handler
internal/handler/app/client_realname.go            # 实名 Handler
internal/handler/app/client_device.go              # 设备 Handler
internal/service/client_order/service.go           # 客户端订单编排 Service
internal/task/auto_purchase.go                     # 强充异步自动购买任务
migrations/000084_add_auto_purchase_status_*.sql   # 数据库迁移
```

## 修改文件

```
pkg/constants/constants.go      # 新增 auto_purchase_status 常量 + 任务类型
pkg/constants/redis.go           # 新增客户端购买幂等键
pkg/errors/codes.go              # 新增 NEED_REALNAME/OPENID_NOT_FOUND 错误码
internal/model/asset_wallet.go   # AssetRechargeRecord 新增字段
internal/bootstrap/types.go      # 5 个 Handler 字段
internal/bootstrap/handlers.go   # Handler 实例化
internal/routes/personal.go      # 18 个路由注册
pkg/openapi/handlers.go          # 文档生成 Handler
cmd/api/docs.go                  # 文档注册
cmd/gendocs/main.go              # 文档注册
```

## 新增错误码

| 错误码 | 常量名 | 消息 |
|--------|--------|------|
| 1187 | CodeNeedRealname | 该套餐需实名认证后购买 |
| 1188 | CodeOpenIDNotFound | 未找到微信授权信息，请先完成授权 |

## 数据库变更

- 表：`tb_asset_recharge_record`
- 新增字段：`auto_purchase_status VARCHAR(20) DEFAULT '' NOT NULL`
- 迁移版本：000084
