From b2e5b8f78931506d3523899f0c72f23aad506447 Mon Sep 17 00:00:00 2001 From: Wang Zhuoxuan Date: Sun, 24 May 2026 00:41:39 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=20POST=20/v1/auth/li?= =?UTF-8?q?nk=20=E6=8E=A5=E5=8F=A3=E6=96=87=E6=A1=A3=E4=B8=8E=20CLAUDE.md?= =?UTF-8?q?=20=E9=A1=B9=E7=9B=AE=E7=BA=A6=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 /auth/link 游客账号关联接口的完整 API 文档 (认证表、请求/响应格式、场景说明、幂等保证、错误码 CONFLICT) - CLAUDE.md 补充相关项目引用和编码行为约定 --- CLAUDE.md | 66 +++++++++++++++++++++++++++++ docs/api-reference.md | 98 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 56dc124..48665f3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,6 +7,10 @@ 多奇(Duoqi)是游戏化知识闯关学习平台。duoqi-api 是三端(HarmonyOS / Flutter / Web)共享的后端服务,从 Phase 1 起即为 HarmonyOS 客户端提供 API 支持。 +## 相关项目 + +- **duoqi-flutter**: `../duoqi-flutter/`, Flutter 客户端代码库. + ## 技术栈 | 层面 | 选型 | 说明 | @@ -102,3 +106,65 @@ db/seeds/index.ts # 幂等种子导入脚本 - 认证:`Authorization: Bearer `(公开端点:`/v1/auth/*`, `/v1/health`) - Admin 认证:`Authorization: Bearer `(`/v1/admin/*`) - JWT 有效期:access_token 1h, refresh_token 30d + +## 其他约定 + +Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed. + +**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment. + +### 1. Think Before Coding + +**Don't assume. Don't hide confusion. Surface tradeoffs.** + +Before implementing: +- State your assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them - don't pick silently. +- If a simpler approach exists, say so. Push back when warranted. +- If something is unclear, stop. Name what's confusing. Ask. + +### 2. Simplicity First + +**Minimum code that solves the problem. Nothing speculative.** + +- No features beyond what was asked. +- No abstractions for single-use code. +- No "flexibility" or "configurability" that wasn't requested. +- No error handling for impossible scenarios. +- If you write 200 lines and it could be 50, rewrite it. + +Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. + +### 3. Surgical Changes + +**Touch only what you must. Clean up only your own mess.** + +When editing existing code: +- Don't "improve" adjacent code, comments, or formatting. +- Don't refactor things that aren't broken. +- Match existing style, even if you'd do it differently. +- If you notice unrelated dead code, mention it - don't delete it. + +When your changes create orphans: +- Remove imports/variables/functions that YOUR changes made unused. +- Don't remove pre-existing dead code unless asked. + +The test: Every changed line should trace directly to the user's request. + +### 4. Goal-Driven Execution + +**Define success criteria. Loop until verified.** + +Transform tasks into verifiable goals: +- "Add validation" → "Write tests for invalid inputs, then make them pass" +- "Fix the bug" → "Write a test that reproduces it, then make it pass" +- "Refactor X" → "Ensure tests pass before and after" + +For multi-step tasks, state a brief plan: +``` +1. [Step] → verify: [check] +2. [Step] → verify: [check] +3. [Step] → verify: [check] +``` + +Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification. diff --git a/docs/api-reference.md b/docs/api-reference.md index 8abadf9..b213bde 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -20,6 +20,7 @@ | 类型 | Header | 适用路径 | |------|--------|----------| | 无需认证 | - | `/health`, `/v1/auth/guest`, `/v1/auth/huawei`, `/v1/auth/refresh`, `/v1/admin/login` | +| JWT(游客) | `Authorization: Bearer ` | `/v1/auth/link` | | JWT | `Authorization: Bearer ` | 大多数客户端 API | | Admin JWT | `Authorization: Bearer ` | `/v1/admin/*` | @@ -154,6 +155,102 @@ } ``` +#### POST /auth/link + +认证:JWT(游客 Token) +限流:10 次/分钟 + +用途:将当前登录的游客账号关联到第三方正式账号(当前支持 Apple Sign In)。支持两种场景: + +- **场景 A(新用户)**:该 Apple ID 未注册过,游客行原地升级为 Apple 账号,无需数据迁移。 +- **场景 B(老用户)**:该 Apple ID 已有正式账号,在事务内将游客的答题记录、奖励流水等数据合并到正式账号,不覆盖老账号的订阅、余额、库存、连续学习等核心资产。 + +请求: + +```json +{ + "provider": "apple", + "credential": { + "identityToken": "apple-identity-token", + "authorizationCode": "optional-authorization-code" + }, + "mergePolicy": "server_account_first", + "clientMigrationId": "client-generated-uuid" +} +``` + +- `provider`:当前仅支持 `apple`。 +- `credential.identityToken`:Apple Sign In 返回的 identity token(必填)。 +- `credential.authorizationCode`:Apple 授权码(可选)。 +- `mergePolicy`:当前固定为 `server_account_first`,以服务端已有数据为主。 +- `clientMigrationId`:客户端生成的唯一 ID,用于幂等保证,防止网络重试导致重复合并。 + +成功响应: + +```json +{ + "success": true, + "data": { + "session": { + "user": { + "id": "uuid", + "nickname": null, + "avatarUrl": null, + "tier": "free" + }, + "tokens": { + "accessToken": "jwt", + "refreshToken": "jwt" + } + }, + "migrationSummary": { + "policy": "server_account_first", + "imported": { + "challengeAttempts": 5 + }, + "skipped": { + "subscriptions": 1 + }, + "conflicts": [] + }, + "bootstrap": null + }, + "error": null +} +``` + +- `session.tokens`:关联成功后返回正式账号的新 JWT,客户端应替换本地存储的 token。 +- `migrationSummary.imported`:从游客账号导入的数据类型和数量。 +- `migrationSummary.skipped`:因合并策略跳过的数据(不覆盖老账号已有的数据)。 +- `migrationSummary.conflicts`:合并过程中发现的冲突项列表,通常为空。 +- `bootstrap`:当前固定为 `null`,客户端需调用 `GET /app/bootstrap` 获取最新状态。 + +错误响应: + +```json +{ + "success": false, + "data": null, + "error": { + "code": "CONFLICT", + "message": "Migration already completed" + } +} +``` + +```json +{ + "success": false, + "data": null, + "error": { + "code": "VALIDATION_ERROR", + "message": "Invalid Apple identity token" + } +} +``` + +> 重复提交相同 `clientMigrationId` 时返回幂等结果,不会触发重复合并。游客账号只能关联一次,已关联后再次调用返回 `CONFLICT`。 + #### POST /auth/phone 认证:无 @@ -1397,6 +1494,7 @@ categoryId,contentType,difficulty,stemText,correctAnswer,distractor1,distractor2 | `UNAUTHORIZED` | 未认证或认证失败 | | `FORBIDDEN` | 权限不足 | | `NOT_FOUND` | 资源不存在 | +| `CONFLICT` | 资源冲突(如重复迁移、已关联账号) | | `INVALID_STATUS_TRANSITION` | 题目状态流转不合法 | | `INVALID_RECEIPT` | 支付收据验证失败 | | `UNSUPPORTED_PLATFORM` | 订阅平台暂不支持 |