duoqi-api/CLAUDE.md
Wang Zhuoxuan b2e5b8f789 docs: 补充 POST /v1/auth/link 接口文档与 CLAUDE.md 项目约定
- 新增 /auth/link 游客账号关联接口的完整 API 文档
  (认证表、请求/响应格式、场景说明、幂等保证、错误码 CONFLICT)
- CLAUDE.md 补充相关项目引用和编码行为约定
2026-05-24 00:41:39 +08:00

171 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md — duoqi-api
> 多奇服务端 API基于 Fastify + TypeScript + Drizzle ORM + MySQL 8.0+
> 包管理器:**bun**(禁止使用 npm
## 项目概述
多奇Duoqi是游戏化知识闯关学习平台。duoqi-api 是三端HarmonyOS / Flutter / Web共享的后端服务从 Phase 1 起即为 HarmonyOS 客户端提供 API 支持。
## 相关项目
- **duoqi-flutter**: `../duoqi-flutter/`, Flutter 客户端代码库.
## 技术栈
| 层面 | 选型 | 说明 |
|------|------|------|
| 后端框架 | **Fastify 5** | 高性能,内置 JSON Schema 验证TypeScript 友好 |
| ORM | **Drizzle ORM** | 轻量、类型安全,`src/db/schema.ts` 为唯一真相源 |
| 数据库 | MySQL 8.0+ | 阿里云 RDS |
| 认证 | @fastify/jwt | 自建 JWT华为 ID Kit + 游客模式) |
| 校验 | Zod | 环境变量 + 请求体校验(所有路由已接入 Zod |
| 测试 | Vitest | 单元测试框架19 个测试全部通过 |
| 运行时 | Node.js (ESM) | `"type": "module"`import 使用 `.js` 后缀 |
## Quick Start
```bash
bun install # 安装依赖
cp .env.example .env # 复制环境变量模板,填入实际值
bun run dev # 启动开发服务器,默认端口 3000
```
必填环境变量:`DATABASE_URL`, `JWT_SECRET`, `ADMIN_TOKEN`
## 开发命令
```bash
bun run dev # 启动开发服务器tsx watch 热重载)
bun run typecheck # 类型检查tsc --noEmit
bun run build # 编译到 dist/
bun run test # 运行测试vitest run
bun run db:push # 推送 schema 到数据库(开发用)
bun run db:generate # 生成迁移文件
bun run db:migrate # 执行迁移
bun run db:seed # 导入种子数据(分类 → 技能树 → 题目 → 成就)
bun run db:studio # Drizzle Studio数据库可视化浏览器
bun run lint # ESLint 检查
```
## 项目结构
```
src/
├── index.ts # 入口Fastify 实例 + 插件注册 + 路由挂载
├── db/
│ ├── client.ts # 数据库连接mysql2 pool + drizzle
│ └── schema.ts # 全部 15 张表定义(唯一真相源)
├── types/ # TypeScript 类型auth, quiz, user, api
├── utils/
│ ├── config.ts # 环境变量Zod 校验,启动时 fail-fast
│ └── errors.ts # AppError 层级 + 统一错误处理器
├── middleware/
│ ├── auth.ts # JWT 认证(排除公开路径和 admin 路径)
│ ├── admin-auth.ts # Admin token 认证(/v1/admin/* 路径)
│ ├── audit-log.ts # Admin 操作审计日志
│ └── request-logger.ts # 请求耗时日志
├── services/ # 业务逻辑(按领域分目录)
│ ├── auth/ # jwt, guest, huawei-id-kit, phone
│ ├── quiz/ # quiz-service出题引擎 + 答题验证)
│ ├── progress/ # progress, streak, xp, hearts
│ ├── gamification/ # leaderboard, achievement
│ ├── payment/ # huawei-iap, subscription-service
│ └── admin/ # 7 个管理端 CRUD 服务
│ └── question, category, knowledge-card, skill-tree,
│ user, stats, feedback
├── routes/ # 路由(薄层,调 service + Zod 校验)
│ ├── health.ts, auth.ts, quiz.ts, progress.ts
│ ├── gamification.ts, payment.ts
│ └── admin/ # 管理端路由duoqi-admin 调用)
│ └── index, auth, questions, categories, knowledge-cards,
│ skill-tree, users, stats, feedback
└── __tests__/ # 测试Vitest + DB mock
├── setup.ts, smoke.test.ts
├── helpers/db-mock.ts
└── services/ # 单元测试auth, quiz, progress
content/ # 种子数据JSON
├── categories.json, skill-tree.json, achievements.json
├── history.json, drama.json, crosstalk.json
db/seeds/index.ts # 幂等种子导入脚本
```
## 编码约定
- **路由只做参数提取和响应格式化**,业务逻辑在 `services/`
- **响应格式统一**`{ success: boolean, data: T | null, error: { code, message } | null }`
- **分页响应**:额外包含 `pagination: { total, page, limit }`
- **不可变数据**`Object.freeze()` 或返回新对象,不修改入参
- **错误处理**:抛出 `AppError` 子类(`NotFoundError`, `ValidationError` 等),由 `errorHandler` 统一捕获
- **环境变量**:所有配置通过 `src/utils/config.ts` 读取Zod 校验),禁止直接读 `process.env`
- **导入后缀**ESM 项目,本地导入必须带 `.js` 后缀(`import { x } from './foo.js'`
## API 约定
- Base URL: `/v1`
- 认证:`Authorization: Bearer <jwt>`(公开端点:`/v1/auth/*`, `/v1/health`
- Admin 认证:`Authorization: Bearer <admin_token>``/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.