# Admin Service API 文档

## 目录

- [1. API 概述](#1-api-概述)
- [2. 认证](#2-认证)
- [3. 通用响应格式](#3-通用响应格式)
- [4. 错误处理](#4-错误处理)
- [5. API 端点](#5-api-端点)
- [6. 数据模型](#6-数据模型)
- [7. 使用示例](#7-使用示例)

---

## 1. API 概述

### 1.1 基本信息

| 项目 | 值 |
|-----|---|
| **Base URL** | `http://localhost:3005/api/v1` |
| **协议** | HTTP/HTTPS |
| **数据格式** | JSON |
| **字符编码** | UTF-8 |
| **API 版本** | v1 |

### 1.2 API 分类

| 分类 | 端点数 | 说明 |
|-----|-------|------|
| 版本管理 | 5 | 创建、启用、禁用、查询版本 |
| 版本检查 | 1 | 移动端检查更新 |

---

## 2. 认证

### 2.1 认证方式 (待实现)

当前版本 API **未实现认证机制**，生产环境需要添加 JWT 认证。

**计划认证方案**:
```http
Authorization: Bearer <JWT_TOKEN>
```

**获取 Token** (待实现):
```http
POST /api/v1/auth/login
Content-Type: application/json

{
  "username": "admin",
  "password": "password123"
}
```

**响应**:
```json
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 7200
}
```

### 2.2 权限级别 (待实现)

| 角色 | 权限 |
|-----|------|
| **admin** | 完全权限：创建、启用、禁用、删除版本 |
| **developer** | 创建、查询版本 |
| **public** | 仅检查更新 (无需认证) |

---

## 3. 通用响应格式

### 3.1 成功响应

**200 OK** - 查询成功:
```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "platform": "android",
  "versionCode": 100,
  "versionName": "1.0.0",
  "buildNumber": "1",
  "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk",
  "fileSize": 52428800,
  "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "changelog": "Initial release",
  "isEnabled": true,
  "isForceUpdate": false,
  "createdBy": "admin",
  "createdAt": "2025-01-02T10:00:00.000Z",
  "updatedBy": "admin",
  "updatedAt": "2025-01-02T10:00:00.000Z"
}
```

**201 Created** - 创建成功:
```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "platform": "android",
  "versionCode": 101,
  ...
}
```

**204 No Content** - 操作成功无返回内容

### 3.2 分页响应 (待实现)

```json
{
  "data": [...],
  "meta": {
    "total": 50,
    "page": 1,
    "pageSize": 10,
    "totalPages": 5
  }
}
```

---

## 4. 错误处理

### 4.1 错误响应格式

```json
{
  "statusCode": 400,
  "message": "Invalid version code",
  "error": "Bad Request",
  "timestamp": "2025-01-02T10:00:00.000Z",
  "path": "/api/v1/version"
}
```

### 4.2 HTTP 状态码

| 状态码 | 说明 | 常见场景 |
|-------|------|---------|
| **200** | 成功 | 查询成功 |
| **201** | 已创建 | 创建版本成功 |
| **204** | 无内容 | 启用/禁用成功 |
| **400** | 请求错误 | 参数验证失败 |
| **401** | 未认证 | Token 缺失或无效 |
| **403** | 禁止访问 | 权限不足 |
| **404** | 未找到 | 版本不存在 |
| **409** | 冲突 | 版本号重复 |
| **500** | 服务器错误 | 内部异常 |

### 4.3 业务错误码 (待实现)

| 错误码 | 说明 |
|-------|------|
| `VERSION_ALREADY_EXISTS` | 版本已存在 |
| `INVALID_VERSION_CODE` | 版本号格式错误 |
| `INVALID_VERSION_NAME` | 版本名称格式错误 |
| `INVALID_SHA256` | SHA256 格式错误 |
| `VERSION_NOT_FOUND` | 版本不存在 |
| `FILE_SIZE_INVALID` | 文件大小无效 |

---

## 5. API 端点

### 5.1 创建版本

**端点**: `POST /api/v1/version`

**权限**: 需要认证 (待实现)

**请求体**:
```json
{
  "platform": "android",
  "versionCode": 100,
  "versionName": "1.0.0",
  "buildNumber": "1",
  "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk",
  "fileSize": 52428800,
  "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "changelog": "Initial release",
  "isEnabled": true,
  "isForceUpdate": false,
  "createdBy": "admin"
}
```

**字段说明**:

| 字段 | 类型 | 必填 | 说明 | 验证规则 |
|-----|------|-----|------|---------|
| `platform` | string | ✅ | 平台 | `android` 或 `ios` |
| `versionCode` | number | ✅ | 版本号 | 正整数 |
| `versionName` | string | ✅ | 版本名称 | 语义化版本 (x.y.z) |
| `buildNumber` | string | ✅ | 构建号 | 非空字符串 |
| `downloadUrl` | string | ✅ | 下载链接 | 有效 URL |
| `fileSize` | number | ✅ | 文件大小 (字节) | > 0 |
| `fileSha256` | string | ✅ | SHA256 哈希 | 64 位十六进制 |
| `changelog` | string | ✅ | 更新日志 | 非空字符串 |
| `isEnabled` | boolean | ❌ | 是否启用 | 默认 `true` |
| `isForceUpdate` | boolean | ❌ | 是否强制更新 | 默认 `false` |
| `createdBy` | string | ✅ | 创建者 | 非空字符串 |

**响应**: `201 Created`
```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "platform": "android",
  "versionCode": 100,
  "versionName": "1.0.0",
  "buildNumber": "1",
  "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk",
  "fileSize": 52428800,
  "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "changelog": "Initial release",
  "isEnabled": true,
  "isForceUpdate": false,
  "createdBy": "admin",
  "createdAt": "2025-01-02T10:00:00.000Z",
  "updatedBy": "admin",
  "updatedAt": "2025-01-02T10:00:00.000Z"
}
```

**错误响应**:
```json
// 400 Bad Request - 版本号无效
{
  "statusCode": 400,
  "message": "Version code must be a positive integer",
  "error": "Bad Request"
}

// 409 Conflict - 版本已存在
{
  "statusCode": 409,
  "message": "Version already exists for this platform",
  "error": "Conflict"
}
```

**cURL 示例**:
```bash
curl -X POST http://localhost:3005/api/v1/version \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "android",
    "versionCode": 100,
    "versionName": "1.0.0",
    "buildNumber": "1",
    "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk",
    "fileSize": 52428800,
    "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "changelog": "Initial release",
    "isEnabled": true,
    "isForceUpdate": false,
    "createdBy": "admin"
  }'
```

---

### 5.2 查询所有版本

**端点**: `GET /api/v1/version`

**权限**: 需要认证 (待实现)

**查询参数**:

| 参数 | 类型 | 必填 | 说明 | 示例 |
|-----|------|-----|------|------|
| `platform` | string | ❌ | 过滤平台 | `android` |
| `isEnabled` | boolean | ❌ | 过滤启用状态 | `true` |
| `page` | number | ❌ | 页码 (待实现) | `1` |
| `pageSize` | number | ❌ | 每页数量 (待实现) | `10` |

**请求示例**:
```http
GET /api/v1/version?platform=android&isEnabled=true
```

**响应**: `200 OK`
```json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "platform": "android",
    "versionCode": 101,
    "versionName": "1.0.1",
    ...
  },
  {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "platform": "android",
    "versionCode": 100,
    "versionName": "1.0.0",
    ...
  }
]
```

**cURL 示例**:
```bash
curl -X GET "http://localhost:3005/api/v1/version?platform=android&isEnabled=true"
```

---

### 5.3 查询单个版本

**端点**: `GET /api/v1/version/:id`

**权限**: 需要认证 (待实现)

**路径参数**:

| 参数 | 类型 | 说明 |
|-----|------|------|
| `id` | string (UUID) | 版本 ID |

**请求示例**:
```http
GET /api/v1/version/550e8400-e29b-41d4-a716-446655440000
```

**响应**: `200 OK`
```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "platform": "android",
  "versionCode": 100,
  "versionName": "1.0.0",
  ...
}
```

**错误响应**:
```json
// 404 Not Found
{
  "statusCode": 404,
  "message": "Version not found",
  "error": "Not Found"
}
```

**cURL 示例**:
```bash
curl -X GET http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440000
```

---

### 5.4 启用版本

**端点**: `PATCH /api/v1/version/:id/enable`

**权限**: 需要认证 (待实现)

**路径参数**:

| 参数 | 类型 | 说明 |
|-----|------|------|
| `id` | string (UUID) | 版本 ID |

**请求体**:
```json
{
  "updatedBy": "admin"
}
```

**请求示例**:
```http
PATCH /api/v1/version/550e8400-e29b-41d4-a716-446655440000/enable
Content-Type: application/json

{
  "updatedBy": "admin"
}
```

**响应**: `204 No Content`

**错误响应**:
```json
// 404 Not Found
{
  "statusCode": 404,
  "message": "Version not found",
  "error": "Not Found"
}
```

**cURL 示例**:
```bash
curl -X PATCH http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440000/enable \
  -H "Content-Type: application/json" \
  -d '{"updatedBy": "admin"}'
```

---

### 5.5 禁用版本

**端点**: `PATCH /api/v1/version/:id/disable`

**权限**: 需要认证 (待实现)

**路径参数**:

| 参数 | 类型 | 说明 |
|-----|------|------|
| `id` | string (UUID) | 版本 ID |

**请求体**:
```json
{
  "updatedBy": "admin"
}
```

**请求示例**:
```http
PATCH /api/v1/version/550e8400-e29b-41d4-a716-446655440000/disable
Content-Type: application/json

{
  "updatedBy": "admin"
}
```

**响应**: `204 No Content`

**业务逻辑**:
- 禁用版本时，会自动将 `isForceUpdate` 设置为 `false`
- 禁用后的版本不会出现在 "检查更新" 结果中

**cURL 示例**:
```bash
curl -X PATCH http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440000/disable \
  -H "Content-Type: application/json" \
  -d '{"updatedBy": "admin"}'
```

---

### 5.6 检查更新 (移动端)

**端点**: `GET /api/v1/version/check`

**权限**: 公开 (无需认证)

**查询参数**:

| 参数 | 类型 | 必填 | 说明 | 示例 |
|-----|------|-----|------|------|
| `platform` | string | ✅ | 平台 | `android` |
| `versionCode` | number | ✅ | 当前版本号 | `100` |

**请求示例**:
```http
GET /api/v1/version/check?platform=android&versionCode=100
```

**响应 1**: `200 OK` - 有更新
```json
{
  "hasUpdate": true,
  "latestVersion": "1.0.1",
  "downloadUrl": "https://cdn.example.com/app-v1.0.1.apk",
  "isForceUpdate": false,
  "changelog": "Bug fixes and performance improvements"
}
```

**响应 2**: `200 OK` - 无更新
```json
{
  "hasUpdate": false
}
```

**响应 3**: `200 OK` - 强制更新
```json
{
  "hasUpdate": true,
  "latestVersion": "2.0.0",
  "downloadUrl": "https://cdn.example.com/app-v2.0.0.apk",
  "isForceUpdate": true,
  "changelog": "Major security update. Please update immediately!"
}
```

**错误响应**:
```json
// 400 Bad Request - 参数缺失
{
  "statusCode": 400,
  "message": ["platform should not be empty", "versionCode must be a number"],
  "error": "Bad Request"
}
```

**业务逻辑**:
1. 查询指定平台的所有启用版本 (`isEnabled = true`)
2. 按 `versionCode` 降序排序，取第一个作为最新版本
3. 如果最新版本的 `versionCode` > 当前版本号，返回更新信息
4. 否则返回 `hasUpdate: false`

**移动端处理逻辑**:
```typescript
// Flutter 示例
async function checkForUpdate() {
  const response = await fetch(
    `${API_BASE}/version/check?platform=android&versionCode=100`
  );
  const data = await response.json();

  if (data.hasUpdate) {
    if (data.isForceUpdate) {
      // 显示强制更新对话框（无法关闭）
      showForceUpdateDialog({
        version: data.latestVersion,
        downloadUrl: data.downloadUrl,
        changelog: data.changelog,
      });
    } else {
      // 显示普通更新对话框（可以关闭）
      showUpdateDialog({
        version: data.latestVersion,
        downloadUrl: data.downloadUrl,
        changelog: data.changelog,
      });
    }
  }
}
```

**cURL 示例**:
```bash
curl -X GET "http://localhost:3005/api/v1/version/check?platform=android&versionCode=100"
```

---

## 6. 数据模型

### 6.1 AppVersion (应用版本)

```typescript
interface AppVersion {
  id: string;                 // UUID
  platform: 'android' | 'ios';// 平台
  versionCode: number;        // 版本号（整数）
  versionName: string;        // 版本名称（x.y.z）
  buildNumber: string;        // 构建号
  downloadUrl: string;        // 下载链接
  fileSize: number;           // 文件大小（字节）
  fileSha256: string;         // SHA256 哈希
  changelog: string;          // 更新日志
  isEnabled: boolean;         // 是否启用
  isForceUpdate: boolean;     // 是否强制更新
  createdBy: string;          // 创建者
  createdAt: string;          // 创建时间（ISO 8601）
  updatedBy: string;          // 更新者
  updatedAt: string;          // 更新时间（ISO 8601）
}
```

### 6.2 Platform (平台枚举)

```typescript
enum Platform {
  ANDROID = 'android',
  IOS = 'ios',
}
```

### 6.3 VersionCheckResult (版本检查结果)

```typescript
interface VersionCheckResult {
  hasUpdate: boolean;         // 是否有更新
  latestVersion?: string;     // 最新版本名称
  downloadUrl?: string;       // 下载链接
  isForceUpdate?: boolean;    // 是否强制更新
  changelog?: string;         // 更新日志
}
```

---

## 7. 使用示例

### 7.1 完整发版流程

#### 步骤 1: 创建 Android 新版本

```bash
curl -X POST http://localhost:3005/api/v1/version \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "android",
    "versionCode": 101,
    "versionName": "1.0.1",
    "buildNumber": "20250102001",
    "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.1.apk",
    "fileSize": 54525952,
    "fileSha256": "a3c5d7e9f1b2c4d6e8f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2",
    "changelog": "1. Fixed mining reward calculation bug\n2. Improved UI performance\n3. Added dark mode support",
    "isEnabled": true,
    "isForceUpdate": false,
    "createdBy": "admin"
  }'
```

#### 步骤 2: 验证版本已创建

```bash
curl -X GET "http://localhost:3005/api/v1/version?platform=android&isEnabled=true"
```

#### 步骤 3: 移动端检查更新

```bash
# 用户当前版本号 100
curl -X GET "http://localhost:3005/api/v1/version/check?platform=android&versionCode=100"

# 响应：
{
  "hasUpdate": true,
  "latestVersion": "1.0.1",
  "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.1.apk",
  "isForceUpdate": false,
  "changelog": "1. Fixed mining reward calculation bug\n2. Improved UI performance\n3. Added dark mode support"
}
```

#### 步骤 4: 发现问题，紧急禁用版本

```bash
curl -X PATCH http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440001/disable \
  -H "Content-Type: application/json" \
  -d '{"updatedBy": "admin"}'
```

#### 步骤 5: 创建修复版本

```bash
curl -X POST http://localhost:3005/api/v1/version \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "android",
    "versionCode": 102,
    "versionName": "1.0.2",
    "buildNumber": "20250102002",
    "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.2.apk",
    "fileSize": 54530048,
    "fileSha256": "b4d6e8f0a2c3d5e7f9a1b3c4d6e8f0a2b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1",
    "changelog": "Hotfix: Fixed critical security vulnerability",
    "isEnabled": true,
    "isForceUpdate": true,
    "createdBy": "admin"
  }'
```

### 7.2 iOS 版本发布

```bash
curl -X POST http://localhost:3005/api/v1/version \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "ios",
    "versionCode": 1,
    "versionName": "1.0.0",
    "buildNumber": "1",
    "downloadUrl": "https://apps.apple.com/app/rwa-durian/id123456789",
    "fileSize": 67108864,
    "fileSha256": "c5e7f9a1b3c4d6e8f0a2b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2",
    "changelog": "Initial iOS release",
    "isEnabled": true,
    "isForceUpdate": false,
    "createdBy": "admin"
  }'
```

### 7.3 Postman Collection (部分示例)

```json
{
  "info": {
    "name": "Admin Service API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Create Android Version",
      "request": {
        "method": "POST",
        "header": [{"key": "Content-Type", "value": "application/json"}],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"platform\": \"android\",\n  \"versionCode\": 100,\n  \"versionName\": \"1.0.0\",\n  \"buildNumber\": \"1\",\n  \"downloadUrl\": \"https://cdn.example.com/app-v1.0.0.apk\",\n  \"fileSize\": 52428800,\n  \"fileSha256\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n  \"changelog\": \"Initial release\",\n  \"isEnabled\": true,\n  \"isForceUpdate\": false,\n  \"createdBy\": \"admin\"\n}"
        },
        "url": {
          "raw": "http://localhost:3005/api/v1/version",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3005",
          "path": ["api", "v1", "version"]
        }
      }
    },
    {
      "name": "Check For Update",
      "request": {
        "method": "GET",
        "url": {
          "raw": "http://localhost:3005/api/v1/version/check?platform=android&versionCode=100",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3005",
          "path": ["api", "v1", "version", "check"],
          "query": [
            {"key": "platform", "value": "android"},
            {"key": "versionCode", "value": "100"}
          ]
        }
      }
    }
  ]
}
```

---

## 8. 版本控制策略

### 8.1 版本号规则

**VersionCode** (数字版本号):
- 每次发布递增 1
- Android: 从 1 开始
- iOS: 从 1 开始
- 用于版本比较 (机器识别)

**VersionName** (语义化版本):
- 格式: `MAJOR.MINOR.PATCH` (例如: `1.2.3`)
- 用于用户展示 (人类可读)

**BuildNumber** (构建号):
- 格式: 自定义 (建议: `YYYYMMDDXXX`)
- 例如: `20250102001` = 2025年1月2日第1次构建

### 8.2 更新策略

| 场景 | isForceUpdate | 说明 |
|-----|---------------|------|
| 功能更新 | `false` | 用户可选择更新时机 |
| Bug 修复 | `false` | 建议更新，但不强制 |
| 安全漏洞 | `true` | 必须更新才能继续使用 |
| API 破坏性变更 | `true` | 旧版本无法正常工作 |

---

## 9. 最佳实践

### 9.1 文件托管建议

1. **使用 CDN**: 加速全球用户下载
2. **HTTPS**: 确保传输安全
3. **文件命名**: `app-{platform}-v{versionName}.{ext}`
   - Android: `app-android-v1.0.0.apk`
   - iOS: `app-ios-v1.0.0.ipa`

### 9.2 SHA256 校验流程

**服务端计算** (发版时):
```bash
# Linux/macOS
sha256sum app-android-v1.0.0.apk

# Windows
certutil -hashfile app-android-v1.0.0.apk SHA256
```

**移动端校验** (下载后):
```dart
// Flutter 示例
import 'package:crypto/crypto.dart';
import 'dart:io';

Future<bool> verifyApkIntegrity(String filePath, String expectedSha256) async {
  final file = File(filePath);
  final bytes = await file.readAsBytes();
  final digest = sha256.convert(bytes);
  return digest.toString() == expectedSha256.toLowerCase();
}

// 使用
final isValid = await verifyApkIntegrity(
  '/storage/emulated/0/Download/app.apk',
  'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
);

if (!isValid) {
  throw Exception('File integrity check failed! Possible tampering detected.');
}
```

### 9.3 更新日志编写规范

**推荐格式**:
```
1. 新功能：添加暗黑模式支持
2. 优化：挖矿页面性能提升 30%
3. 修复：交易历史加载失败问题
4. 安全：修复账户导入漏洞
```

**避免**:
- ❌ "Bug fixes and improvements" (太笼统)
- ❌ 技术术语 (普通用户不理解)
- ✅ 简洁明了，面向用户

---

## 10. 常见问题

### Q1: 如何回滚版本？

**方案 1**: 禁用问题版本，启用旧版本
```bash
# 禁用 v1.0.1
curl -X PATCH http://localhost:3005/api/v1/version/{v1.0.1-id}/disable \
  -H "Content-Type: application/json" \
  -d '{"updatedBy": "admin"}'

# 启用 v1.0.0
curl -X PATCH http://localhost:3005/api/v1/version/{v1.0.0-id}/enable \
  -H "Content-Type: application/json" \
  -d '{"updatedBy": "admin"}'
```

**方案 2**: 创建新版本，使用更高的 versionCode
```bash
# 创建 v1.0.0-hotfix (versionCode = 103)
curl -X POST http://localhost:3005/api/v1/version \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "android",
    "versionCode": 103,
    "versionName": "1.0.0",
    "buildNumber": "20250102003",
    ...
  }'
```

### Q2: 如何处理多渠道包 (Google Play, 自建服务器)?

当前版本不支持，建议通过 `buildNumber` 区分：

```bash
# Google Play 渠道
{
  "versionCode": 100,
  "versionName": "1.0.0",
  "buildNumber": "100-gplay",
  "downloadUrl": "https://play.google.com/store/apps/details?id=com.rwa.durian",
  ...
}

# 自建渠道
{
  "versionCode": 100,
  "versionName": "1.0.0",
  "buildNumber": "100-self",
  "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.0.apk",
  ...
}
```

### Q3: 如何实现灰度发布？

当前版本不支持，未来可扩展：

```typescript
// 计划实现
interface AppVersion {
  ...
  releaseType: 'full' | 'gray'; // 发布类型
  grayRatio?: number;           // 灰度比例 (0-100)
  grayUserIds?: string[];       // 灰度用户列表
}
```

---

**最后更新**: 2025-12-03
**版本**: 1.0.0
**维护者**: RWA Durian Team
