duoqi-api/docs/api-reference.md
Wang Zhuoxuan 4c0419649b docs: update admin categories API with pagination parameters
- Add page/limit query parameters documentation
- Update response format to include pagination metadata
- Specify parameter constraints (page ≥ 1, limit 1-50)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 12:57:24 +08:00

1285 lines
17 KiB
Markdown

# Duoqi API Reference
> 多奇服务端 API 接口文档
> Base URL: `http://<host>:3000/v1`
## 目录
- [通用约定](#通用约定)
- [客户端 API](#客户端-api)
- [健康检查](#健康检查)
- [认证](#认证)
- [答题](#答题)
- [进度](#进度)
- [游戏化](#游戏化)
- [支付](#支付)
- [管理端 API](#管理端-api)
- [管理端认证](#管理端认证)
- [题目管理](#题目管理)
- [分类管理](#分类管理)
- [知识点卡片](#知识点卡片)
- [技能树管理](#技能树管理)
- [用户管理](#用户管理)
- [统计数据](#统计数据)
- [反馈管理](#反馈管理)
---
## 通用约定
### 认证方式
| 类型 | Header | 适用路径 |
|------|--------|----------|
| 无需认证 | - | `/v1/health`, `/v1/auth/*` |
| JWT | `Authorization: Bearer <jwt_token>` | 大多数客户端 API |
| Admin Token | `Authorization: Bearer <admin_token>` | `/v1/admin/*` |
### 统一响应格式
```typescript
// 成功响应
{
"success": true,
"data": <T>,
"error": null
}
// 错误响应
{
"success": false,
"data": null,
"error": {
"code": "ERROR_CODE",
"message": "错误描述"
}
}
// 分页响应(额外包含)
{
"success": true,
"data": [...],
"pagination": {
"total": 100,
"page": 1,
"limit": 20
},
"error": null
}
```
### 状态码
| 状态码 | 含义 |
|--------|------|
| 200 | 请求成功 |
| 400 | 请求参数验证失败 |
| 401 | 未认证 / 认证失败 |
| 404 | 资源不存在 |
| 501 | 功能未实现 |
---
## 客户端 API
### 健康检查
#### GET /health
健康检查端点,用于服务可用性探测。
**认证**: 无
**请求**: 无
**响应**:
```json
{
"success": true,
"data": {
"status": "ok",
"timestamp": "2026-04-10T12:00:00.000Z"
},
"error": null
}
```
---
### 认证
#### POST /auth/guest
游客登录,通过设备 ID 创建或获取用户账号。
**认证**: 无
**限流**: 10 次/分钟
**请求体**:
```json
{
"deviceId": "string (必填)"
}
```
**响应**:
```json
{
"success": true,
"data": {
"user": {
"id": "uuid",
"nickname": null,
"avatarUrl": null,
"tier": "free"
},
"tokens": {
"accessToken": "jwt_token",
"refreshToken": "jwt_token"
}
},
"error": null
}
```
---
#### POST /auth/huawei
华为账号登录。
**认证**: 无
**限流**: 10 次/分钟
**请求体**:
```json
{
"authorizationCode": "string (必填)"
}
```
**响应**:
```json
{
"success": true,
"data": {
"user": {
"id": "uuid",
"nickname": "用户昵称",
"avatarUrl": "头像URL",
"tier": "free"
},
"tokens": {
"accessToken": "jwt_token",
"refreshToken": "jwt_token"
}
},
"error": null
}
```
---
#### POST /auth/phone
手机号登录(未实现)。
**认证**: 无
**状态**: 501 Not Implemented
---
#### POST /auth/refresh
刷新访问令牌。
**认证**: 无
**限流**: 10 次/分钟
**请求体**:
```json
{
"refreshToken": "string (必填)"
}
```
**响应**:
```json
{
"success": true,
"data": {
"accessToken": "new_jwt_token",
"refreshToken": "new_refresh_token"
},
"error": null
}
```
---
#### GET /auth/me
获取当前用户信息。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"id": "uuid",
"nickname": "用户昵称",
"avatarUrl": "头像URL",
"tier": "free | pro | proplus",
"xpTotal": 150,
"streakDays": 3,
"heartsRemaining": 5,
"dailyXpEarned": 20,
"dailyXpGoal": 50
},
"error": null
}
```
---
### 答题
#### GET /quiz/categories
获取所有题目分类列表。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"name": "历史",
"slug": "history",
"parentId": null
}
],
"error": null
}
```
---
#### GET /quiz/categories/:id/chapters
获取指定分类下的章节列表。
**认证**: JWT
**路径参数**:
- `id`: 分类 ID
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"categoryId": "uuid",
"title": "第一章",
"parentId": null,
"sortOrder": 1
}
],
"error": null
}
```
---
#### GET /quiz/chapters/:id/questions
获取章节下的题目(包含用户答题状态)。
**认证**: JWT
**路径参数**:
- `id`: 章节 ID
**响应**:
```json
{
"success": true,
"data": {
"chapterId": "uuid",
"title": "第一章",
"questionsRequired": 5,
"passThreshold": 3,
"questions": [
{
"id": "uuid",
"stem": { "text": "题目内容" },
"contentType": "text",
"options": ["A", "B", "C", "D"],
"answered": false,
"isCorrect": null
}
]
},
"error": null
}
```
---
#### POST /quiz/answer
提交答案。
**认证**: JWT
**请求体**:
```json
{
"questionId": "uuid (必填)",
"selectedAnswer": "string (必填)",
"timeMs": 1500
}
```
**响应**:
```json
{
"success": true,
"data": {
"correct": true,
"correctAnswer": "B",
"xpEarned": 10,
"streakBonus": 0,
"chapterCompleted": false
},
"error": null
}
```
---
#### POST /quiz/rate
评价题目质量。
**认证**: JWT
**请求体**:
```json
{
"questionId": "uuid (必填)",
"rating": "good | bad"
}
```
**响应**:
```json
{
"success": true,
"data": null,
"error": null
}
```
---
### 进度
#### GET /progress/dashboard
获取用户进度概览。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"xpTotal": 150,
"streakDays": 3,
"heartsRemaining": 5,
"dailyXpEarned": 20,
"dailyXpGoal": 50,
"categoriesCompleted": 1,
"totalCategories": 5
},
"error": null
}
```
---
#### GET /progress/streak
获取连胜信息。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"currentStreak": 3,
"longestStreak": 7,
"lastActiveDate": "2026-04-10"
},
"error": null
}
```
---
#### GET /progress/hearts
获取红心信息。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"remaining": 5,
"max": 5,
"nextRestoreAt": "2026-04-10T13:00:00.000Z"
},
"error": null
}
```
---
#### POST /progress/hearts/restore
恢复红心。
**认证**: JWT
**请求体**:
```json
{
"method": "ad | wait | upgrade"
}
```
**响应**:
```json
{
"success": true,
"data": {
"remaining": 5,
"restored": 1
},
"error": null
}
```
---
#### GET /progress/chapters
获取所有章节进度。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": [
{
"chapterId": "uuid",
"title": "第一章",
"completedQuestions": 3,
"totalQuestions": 5,
"passed": false,
"passedAt": null
}
],
"error": null
}
```
---
#### POST /feedback
提交用户反馈。
**认证**: JWT
**请求体**:
```json
{
"content": "string (必填, 1-2000字符)",
"contact": "string (可选, 最多255字符)",
"pageContext": "string (可选, 最多200字符)"
}
```
**响应**:
```json
{
"success": true,
"data": null,
"error": null
}
```
---
### 游戏化
#### GET /leaderboard
获取排行榜。
**认证**: JWT
**查询参数**:
- `tier`: "free" | "pro" | "proplus" (可选)
- `page`: 页码 (默认: 1)
- `limit`: 每页数量 (默认: 20)
**响应**:
```json
{
"success": true,
"data": [
{
"rank": 1,
"userId": "uuid",
"nickname": "玩家昵称",
"avatarUrl": "头像URL",
"xpTotal": 5000
}
],
"pagination": {
"total": 100,
"page": 1,
"limit": 20
},
"error": null
}
```
---
#### GET /leaderboard/me
获取当前用户排名。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"rank": 15,
"xpTotal": 1500
},
"error": null
}
```
---
#### GET /achievements
获取成就列表。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"code": "first_win",
"name": "初出茅庐",
"description": "完成第一道题",
"iconUrl": "图标URL",
"unlocked": true,
"unlockedAt": "2026-04-10T10:00:00.000Z"
}
],
"error": null
}
```
---
#### POST /achievements/check
检查并解锁新成就。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"newlyUnlocked": [
{
"id": "uuid",
"code": "streak_7",
"name": "连胜达人",
"description": "连续7天活跃"
}
]
},
"error": null
}
```
---
### 支付
#### POST /payment/verify-huawei
验证华为 IAP 收据并激活订阅。
**认证**: JWT
**请求体**:
```json
{
"purchaseToken": "string (必填)",
"productId": "string (必填)",
"tier": "pro | proplus"
}
```
**响应**:
```json
{
"success": true,
"data": {
"tier": "pro",
"provider": "huawei",
"active": true,
"expiresAt": "2026-05-10T00:00:00.000Z"
},
"error": null
}
```
---
#### GET /payment/subscription
获取当前订阅状态。
**认证**: JWT
**响应**:
```json
{
"success": true,
"data": {
"tier": "pro",
"provider": "huawei",
"active": true,
"expiresAt": "2026-05-10T00:00:00.000Z",
"autoRenew": true
},
"error": null
}
```
---
## 管理端 API
### 管理端认证
#### POST /admin/auth
管理端认证。
**认证**: 无
**请求体**:
```json
{
"token": "string (必填)"
}
```
**响应**:
```json
{
"success": true,
"data": {
"authenticated": true
},
"error": null
}
```
**错误 (401)**:
```json
{
"success": false,
"data": null,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid admin token"
}
}
```
---
### 题目管理
#### GET /admin/questions
获取题目列表。
**认证**: Admin Token
**查询参数**:
- `page`: 页码 (默认: 1)
- `limit`: 每页数量 (默认: 20)
- `status`: draft | reviewing | published | archived (可选)
- `categoryId`: 分类 ID (可选)
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"stem": { "text": "题目内容" },
"contentType": "text",
"correctAnswer": "B",
"distractors": ["A", "C", "D"],
"categoryId": "uuid",
"difficulty": 3,
"status": "published"
}
],
"pagination": {
"total": 100,
"page": 1,
"limit": 20
},
"error": null
}
```
---
#### GET /admin/questions/:id
获取题目详情。
**认证**: Admin Token
**路径参数**:
- `id`: 题目 ID
**响应**:
```json
{
"success": true,
"data": {
"id": "uuid",
"stem": { "text": "题目内容" },
"contentType": "text",
"correctAnswer": "B",
"distractors": ["A", "C", "D"],
"categoryId": "uuid",
"difficulty": 3,
"status": "published",
"knowledgeCard": {
"id": "uuid",
"summary": "知识点摘要",
"deepDive": "深入解析",
"sourceRef": "来源引用"
}
},
"error": null
}
```
---
#### POST /admin/questions
创建新题目。
**认证**: Admin Token
**请求体**:
```json
{
"stem": { "text": "题目内容" },
"contentType": "text | image | video | audio",
"correctAnswer": "B (必填)",
"distractors": ["A", "C", "D"],
"categoryId": "uuid (必填)",
"difficulty": 3,
"knowledgeCard": {
"summary": "知识点摘要 (必填)",
"deepDive": "深入解析",
"sourceRef": "来源引用"
}
}
```
**响应**:
```json
{
"success": true,
"data": {
"id": "uuid",
"status": "draft"
},
"error": null
}
```
---
#### PUT /admin/questions/:id
更新题目。
**认证**: Admin Token
**路径参数**:
- `id`: 题目 ID
**请求体**:
```json
{
"stem": { "text": "题目内容" },
"contentType": "text | image | video | audio",
"correctAnswer": "B",
"distractors": ["A", "C", "D"],
"categoryId": "uuid",
"difficulty": 3,
"status": "draft | reviewing | published | archived"
}
```
---
#### DELETE /admin/questions/:id
归档题目。
**认证**: Admin Token
**路径参数**:
- `id`: 题目 ID
**响应**:
```json
{
"success": true,
"data": null,
"error": null
}
```
---
#### POST /admin/questions/batch-publish
批量发布题目。
**认证**: Admin Token
**请求体**:
```json
{
"ids": ["uuid1", "uuid2"]
}
```
**响应**:
```json
{
"success": true,
"data": null,
"error": null
}
```
---
### 分类管理
#### GET /admin/categories
获取分类列表。
**认证**: Admin Token
**查询参数**:
- `page`: 页码 (默认: 1, 必须 ≥ 1)
- `limit`: 每页数量 (默认: 20, 范围: 1-50)
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"name": "历史",
"slug": "history",
"parentId": null,
"sortOrder": 1,
"questionCount": 120,
"status": "active"
}
],
"pagination": {
"total": 45,
"page": 1,
"limit": 20
},
"error": null
}
```
---
#### POST /admin/categories
创建分类。
**认证**: Admin Token
**请求体**:
```json
{
"id": "uuid (必填)",
"name": "分类名称 (必填)",
"slug": "分类slug (必填)",
"parentId": "uuid",
"sortOrder": 1
}
```
---
#### PUT /admin/categories/:id
更新分类。
**认证**: Admin Token
**请求体**:
```json
{
"name": "分类名称",
"slug": "分类slug",
"parentId": "uuid | null",
"sortOrder": 1,
"status": "active | inactive"
}
```
---
#### DELETE /admin/categories/:id
归档分类。
**认证**: Admin Token
---
### 知识点卡片
#### GET /admin/knowledge-cards
获取知识点卡片列表。
**认证**: Admin Token
**查询参数**:
- `page`: 页码 (默认: 1)
- `limit`: 每页数量 (默认: 20)
---
#### GET /admin/knowledge-cards/by-question/:questionId
根据题目 ID 获取知识点卡片。
**认证**: Admin Token
---
#### PUT /admin/knowledge-cards/:id
更新知识点卡片。
**认证**: Admin Token
**请求体**:
```json
{
"summary": "摘要 (必填)",
"deepDive": "深入解析",
"sourceRef": "来源引用"
}
```
---
### 技能树管理
#### GET /admin/skill-tree
获取章节列表。
**认证**: Admin Token
**查询参数**:
- `categoryId`: 分类 ID (可选)
---
#### POST /admin/skill-tree
创建章节。
**认证**: Admin Token
**请求体**:
```json
{
"categoryId": "uuid (必填)",
"title": "章节标题 (必填)",
"parentId": "uuid",
"sortOrder": 1,
"questionsRequired": 5,
"passThreshold": 3
}
```
---
#### PUT /admin/skill-tree/:id
更新章节。
**认证**: Admin Token
**请求体**:
```json
{
"title": "章节标题",
"parentId": "uuid | null",
"sortOrder": 1,
"questionsRequired": 5,
"passThreshold": 3
}
```
---
#### DELETE /admin/skill-tree/:id
删除章节。
**认证**: Admin Token
---
### 用户管理
#### GET /admin/users
获取用户列表。
**认证**: Admin Token
**查询参数**:
- `page`: 页码 (默认: 1)
- `limit`: 每页数量 (默认: 20)
- `search`: 搜索关键词 (昵称/ID)
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"nickname": "玩家昵称",
"avatarUrl": "头像URL",
"tier": "free",
"xpTotal": 150,
"streakDays": 3,
"banned": false
}
],
"pagination": { ... },
"error": null
}
```
---
#### GET /admin/users/:id
获取用户详情。
**认证**: Admin Token
---
#### PUT /admin/users/:id/ban
封禁用户。
**认证**: Admin Token
---
#### PUT /admin/users/:id/unban
解封用户。
**认证**: Admin Token
---
### 统计数据
#### GET /admin/stats
获取仪表盘统计数据。
**认证**: Admin Token
**响应**:
```json
{
"success": true,
"data": {
"totalUsers": 1000,
"activeUsers": 150,
"totalQuestions": 500,
"publishedQuestions": 450,
"averageXp": 200
},
"error": null
}
```
---
### 反馈管理
#### GET /admin/feedback
获取用户反馈列表。
**认证**: Admin Token
**查询参数**:
- `page`: 页码 (默认: 1)
- `limit`: 每页数量 (默认: 20)
**响应**:
```json
{
"success": true,
"data": [
{
"id": "uuid",
"userId": "uuid",
"content": "反馈内容",
"contact": "联系方式",
"pageContext": "页面上下文",
"createdAt": "2026-04-10T10:00:00.000Z"
}
],
"pagination": { ... },
"error": null
}
```
---
## 附录
### 错误代码
| 代码 | 说明 |
|------|------|
| VALIDATION_ERROR | 请求参数验证失败 |
| UNAUTHORIZED | 未认证或认证失败 |
| NOT_FOUND | 资源不存在 |
| INVALID_RECEIPT | 支付收据验证失败 |
| NOT_IMPLEMENTED | 功能未实现 |
| INTERNAL_ERROR | 服务器内部错误 |
### 数据模型
#### User (用户)
```typescript
{
id: string; // UUID
nickname: string | null; // 昵称
avatarUrl: string | null; // 头像URL
tier: 'free' | 'pro' | 'proplus'; // 会员等级
xpTotal: number; // 总经验值
streakDays: number; // 连续天数
heartsRemaining: number; // 剩余红心
banned: boolean; // 是否封禁
}
```
#### Question (题目)
```typescript
{
id: string; // UUID
stem: Record<string, unknown>; // 题目内容(支持多语言)
contentType: 'text' | 'image' | 'video' | 'audio';
correctAnswer: string; // 正确答案
distractors: string[]; // 干扰项
categoryId: string; // 分类ID
difficulty: 1-5; // 难度等级
status: 'draft' | 'reviewing' | 'published' | 'archived';
}
```
#### Chapter (章节)
```typescript
{
id: string; // UUID
categoryId: string; // 分类ID
title: string; // 章节标题
parentId: string | null; // 父章节ID
sortOrder: number; // 排序
questionsRequired: number; // 需要答题数
passThreshold: number; // 通过阈值
}
```