# Duoqi API Reference > 多奇服务端 API 接口文档 > Base URL: `http://:3000/v1` ## 目录 - [通用约定](#通用约定) - [客户端 API](#客户端-api) - [健康检查](#健康检查) - [认证](#认证) - [答题](#答题) - [进度](#进度) - [游戏化](#游戏化) - [支付](#支付) - [管理端 API](#管理端-api) - [管理端认证](#管理端认证) - [管理员管理](#管理员管理) - [题目管理](#题目管理) - [分类管理](#分类管理) - [知识点卡片](#知识点卡片) - [技能树管理](#技能树管理) - [用户管理](#用户管理) - [统计数据](#统计数据) - [反馈管理](#反馈管理) --- ## 通用约定 ### 认证方式 | 类型 | Header | 适用路径 | |------|--------|----------| | 无需认证 | - | `/v1/health`, `/v1/auth/*` | | JWT | `Authorization: Bearer ` | 大多数客户端 API | | Admin JWT | `Authorization: Bearer ` | `/v1/admin/*` (推荐) | | Admin Token | `Authorization: Bearer ` | `/v1/admin/*` (向后兼容) | ### 统一响应格式 ```typescript // 成功响应 { "success": true, "data": , "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/login 管理员用户名密码登录。 **认证**: 无 **请求体**: ```json { "username": "string (必填)", "password": "string (必填, 最少8字符)" } ``` **响应**: ```json { "success": true, "data": { "accessToken": "jwt_token (1h有效)", "refreshToken": "jwt_token (30d有效)", "admin": { "id": "uuid", "username": "admin", "role": "super_admin" } }, "error": null } ``` **错误 (401)**: ```json { "success": false, "data": null, "error": { "code": "UNAUTHORIZED", "message": "Invalid username or password" } } ``` --- #### POST /admin/auth 管理端 Token 认证(向后兼容,推荐使用 `/admin/auth/login`)。 **认证**: 无 **请求体**: ```json { "token": "string (必填)" } ``` **响应**: ```json { "success": true, "data": { "authenticated": true }, "error": null } ``` **错误 (401)**: ```json { "success": false, "data": null, "error": { "code": "UNAUTHORIZED", "message": "Invalid admin token" } } ``` --- ### 管理员管理 > 仅 super_admin 角色可执行写操作(POST、PUT、DELETE),读操作(GET)所有管理员均可访问。 #### GET /admin/admins 获取管理员列表。 **认证**: Admin JWT **查询参数**: - `page`: 页码 (默认: 1, 必须 ≥ 1) - `limit`: 每页数量 (默认: 20, 范围: 1-50) - `role`: "admin" | "super_admin" (可选,按角色筛选) - `isActive`: 0 | 1 (可选,按状态筛选) **响应**: ```json { "success": true, "data": [ { "id": "uuid", "username": "admin", "role": "super_admin", "isActive": 1, "lastLoginAt": "2026-04-11T10:00:00.000Z", "createdAt": "2026-04-01T00:00:00.000Z", "updatedAt": "2026-04-11T10:00:00.000Z" } ], "pagination": { "total": 5, "page": 1, "limit": 20 }, "error": null } ``` --- #### GET /admin/admins/:id 获取管理员详情。 **认证**: Admin JWT **路径参数**: - `id`: 管理员 ID **响应**: ```json { "success": true, "data": { "id": "uuid", "username": "admin", "role": "super_admin", "isActive": 1, "lastLoginAt": "2026-04-11T10:00:00.000Z", "createdAt": "2026-04-01T00:00:00.000Z", "updatedAt": "2026-04-11T10:00:00.000Z" }, "error": null } ``` **错误 (404)**: ```json { "success": false, "data": null, "error": { "code": "NOT_FOUND", "message": "Admin user not found" } } ``` --- #### POST /admin/admins 创建新管理员(super_admin 专属)。 **认证**: Admin JWT (super_admin) **请求体**: ```json { "username": "string (必填, 3-50字符)", "password": "string (必填, 8-128字符)", "role": "admin | super_admin (必填)" } ``` **响应**: ```json { "success": true, "data": { "id": "uuid", "username": "newadmin", "role": "admin", "isActive": 1, "lastLoginAt": null, "createdAt": "2026-04-11T12:00:00.000Z", "updatedAt": "2026-04-11T12:00:00.000Z", "plainPassword": "随机生成的初始密码" }, "error": null } ``` **错误 (403)**: ```json { "success": false, "data": null, "error": { "code": "FORBIDDEN", "message": "Super admin privileges required" } } ``` **错误 (400)**: ```json { "success": false, "data": null, "error": { "code": "VALIDATION_ERROR", "message": "Username \"admin\" already exists" } } ``` --- #### PUT /admin/admins/:id 更新管理员信息(super_admin 专属)。 **认证**: Admin JWT (super_admin) **路径参数**: - `id`: 管理员 ID **请求体**: ```json { "username": "string (可选, 3-50字符)", "role": "admin | super_admin (可选)", "isActive": 0 | 1 (可选)" } ``` **响应**: ```json { "success": true, "data": { "id": "uuid", "username": "updated_username", "role": "admin", "isActive": 0, "lastLoginAt": "2026-04-11T10:00:00.000Z", "createdAt": "2026-04-01T00:00:00.000Z", "updatedAt": "2026-04-11T12:00:00.000Z" }, "error": null } ``` **安全规则**: - 禁止删除或降级最后一个 super_admin - 用户名必须唯一 --- #### DELETE /admin/admins/:id 软删除管理员(super_admin 专属)。 **认证**: Admin JWT (super_admin) **路径参数**: - `id`: 管理员 ID **响应**: ```json { "success": true, "data": { "id": "uuid", "username": "deleted_admin", "role": "admin", "isActive": 0, "lastLoginAt": "2026-04-11T10:00:00.000Z", "createdAt": "2026-04-01T00:00:00.000Z", "updatedAt": "2026-04-11T12:00:00.000Z" }, "error": null } ``` **说明**: - 软删除:将 `isActive` 设为 0,不删除记录 - 禁止删除最后一个 super_admin --- #### POST /admin/admins/:id/reset-password 重置管理员密码(super_admin 专属)。 **认证**: Admin JWT (super_admin) **路径参数**: - `id`: 管理员 ID **响应**: ```json { "success": true, "data": { "adminId": "uuid", "username": "admin", "plainPassword": "新随机生成的12位密码" }, "error": null } ``` **说明**: - 生成 12 位随机密码,包含大小写字母、数字、符号 - 明文密码仅在响应中返回一次,请妥善保存 - 密码使用 BCrypt 哈希后存储到数据库 --- ### 题目管理 #### 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 | 未认证或认证失败 | | FORBIDDEN | 权限不足(需要 super_admin) | | 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; // 题目内容(支持多语言) 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; // 通过阈值 } ```