startup-plan/技术设计/api-server/已完成/[已完成]-当前状态与决策清单.md
WangDL fe608da385 docs: 重构技术设计目录结构 + 更新待完成清单
- 文档从扁平结构迁移至分类目录 (api-server/ios-projects/web-projects/长期规划)
- 更新总待完成清单 (B1-B6 全部完成, I1-I7 全部完成)
- 新增后端实现状态、已实现功能汇总等已完成文档
- 新增 iOS 功能需求清单、架构设计、差距分析等文档
- 清理旧版未维护文档

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 19:08:59 +08:00

361 lines
12 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.

# 知习后端:当前状态 & 需要你处理的决策和任务
> 基于代码审计生成。**2026-05-16 已确认所有决策,执行中。**
---
# 一、当前代码状态总览
## 已完成(真实可用的)
| 模块 | 状态 | 说明 |
|------|------|------|
| Auth 控制器 + 服务 | 真实 | dev-login / apple / refresh / logout 全部写好了 |
| TokenService | 真实 | JWT accessToken + crypto refreshToken + hash 入库 |
| JwtAuthGuard | 真实 | 可正常验证 Bearer token |
| CurrentUser 装饰器 | 真实 | 从 request.user 提取当前用户 |
| AppleAuthService | 真实+兜底 | BUNDLE_ID 有值就走真实 JWKS 验证,没值走 mock |
| UsersRepository | 真实 | **唯一接 Prisma 的 repository** |
| PrismaService | 真实 | 连接 MySQL |
| Prisma Schema | 完整 | 所有表都定义了User, KnowledgeBase, KnowledgeItem, 等 30+ 个 model |
| AppModule | 完整 | 所有模块都注册了 |
| 基础设施骨架 | 有 | Redis/Storage/Logger/Queue 模块都创建了 |
| 全局异常过滤器 | 有 | |
| 统一响应拦截器 | 有 | |
| DTO 校验管道 | 有 | |
| Apple 登录配置 | 有 | 但缺 `APPLE_BUNDLE_ID` |
## 仍在使用内存 Map没有接数据库
| 模块 | 存储方式 | 严重程度 |
|------|----------|----------|
| KnowledgeBaseRepository | `new Map()` | 高 |
| KnowledgeItemsRepository | `new Map()` | 高 |
| ActiveRecallRepository | `new Map()` × 2 | 高 |
| AiAnalysisRepository | `new Map()` × 2 | 高 |
| FocusItemsRepository | `new Map()` | 高 |
| ReviewRepository | `new Map()` × 2 | 高 |
| LearningSessionRepository | `new Map()` | 高 |
| LearningActivityRepository | `new Map()` | 中 |
| DocumentImportRepository | `new Map()` | 中 |
| QueueService | `new Map()` | 中 |
## AI 模块 ✅ 已升级为三层架构
| 组件 | 状态 |
|------|------|
| AiProvider 接口 | ✅ 统一 generate() + signal |
| MockAiProvider | ✅ 永久保留 |
| DeepSeekProvider | ✅ OpenAI 兼容协议 |
| MiniMaxProvider | ✅ OpenAI 兼容协议Coding Plan |
| ModelRouter | ✅ cheap / primary / strong 三档 |
| AiGatewayService | ✅ 统一入口 + JSON容错 + 超时重试 |
| PromptTemplateService | ✅ key + version 注册 |
| ActiveRecallAnalysisWorkflow | ✅ 第一个 Workflow |
| AiUsageLog + CostCalculator | ✅ 已加入 schema |
| 旧 infrastructure/ai | ❌ 已删除 |
| 新 AiModule | ✅ `src/modules/ai/` 14 个文件 |
详见 `startup-plan/技术设计/api-server/[已完成]-AI架构决策清单.md`
---
# 二、需要你决策的事项
这些都是我无法替你决定的问题,每一个都会影响后续开发方向。
## 决策 1MySQL 数据库 —— 当前什么状态?
`.env` 里配置了:
```
DATABASE_URL="mysql://zhixi_user:Zhixi@2026!App@localhost:3306/zhixi"
```
需要确认:
- [ ] MySQL 服务是否在运行?
- [ ] 数据库 `zhixi` 是否已创建?
- [ ] 数据库里是否已有数据?(如果之前跑过可能会有旧表)
- [ ] Prisma schema 和实际数据库是否一致?
**为什么重要**Prisma schema 已定义 30+ 张表,但没有 migrations 目录。第一次 `prisma migrate dev` 会生成初始 migration。如果数据库已有表结构非 Prisma 迁移创建的),需要额外处理。
**建议方案**
- 如果是空库 → 直接 `prisma migrate dev` 生成初始迁移
- 如果已有 Prisma 创建的表 → 先 `prisma db pull` 拉取现有结构,再 `prisma migrate dev`
- 如果 MySQL 没启动 → 先解决 MySQL 启动问题
---
## 决策 2BigInt ID 问题 —— 现在不改,后面全是雷
Prisma schema 所有主键都是 `BigInt @default(autoincrement())`
但是:
- JavaScript/JSON 不支持 64 位整数
- Auth 模块里已经出现大量 `BigInt(userId)` / `String(user.id)` 的转换
- KnowledgeBase 的 in-memory 版本用的是 `string` ID
- JWT payload 里的 `sub``String(user.id)`
- 这意味着:**内存版本和数据库版本的 ID 类型不统一**
**问题场景**
```
数据库返回: user.id = 9007199254740993n (BigInt, 超出 JS 安全范围)
JSON.stringify → "9007199254740992" (精度丢失!)
```
**选项**
- A) 换 `String @id @default(cuid())` —— 最安全,推荐,但需要改 schema 和所有关联代码
- B) 换 `Int @default(autoincrement())` —— 简单但有上限21 亿),够用但不够好看
- C) 保持 `BigInt` —— 不改,但要全局统一序列化(`JSON.stringify` 不能直接用),所有 repository 都要转 string
---
## 决策 3AI Provider —— 第一个接哪个?
目前 AI 是纯 mock返回固定 JSON。
**选项**
- A) **DeepSeek** —— 便宜,中文强,适合预算有限的独立开发者
- B) **OpenAI (GPT-4o)** —— 贵但生态好SDK 成熟
- C) **Anthropic Claude** —— 长上下文优秀,适合大段知识分析
- D) **MiniMax / 豆包 / 通义千问** —— 国内合规,需要 ICP 备案才能用
**连锁影响**
- 决定了 AIGateway 第一个 provider 实现
- 决定了 Prompt 模板的调试环境
- 决定了成本(需要 API key 和充值)
---
## 决策 4Redis 状态 —— 需要现在启动吗?
`.env` 里配置了 Redis 连接,`AiAnalysisService` 里用了 Redis限流、任务状态、锁
但是这些功能**不启动 Redis 也能绕过去**——限流可以先去掉,任务状态可以先放内存。
**建议**:先不管 Redis集中精力把数据库层搞定。限流等功能后面补。
---
## 决策 5Prisma Schema 需要调整吗?
现在 schema 非常完整30+ 张表),但很多是远期才用的表:
| 近期需要的表 | 远期才用的表 |
|-------------|-------------|
| users | UserProfile |
| auth_accounts | UserPreference |
| refresh_tokens | UserConsent |
| knowledge_bases | KnowledgeItemRelation |
| knowledge_items | Tag (如果第一版不做标签) |
| active_recall_questions | KnowledgeItemTag |
| active_recall_answers | UploadedFile |
| ai_analysis_jobs | DocumentImport |
| ai_analysis_results | LearningRecord |
| focus_items | ReviewPlan |
| review_cards | AppChangelog |
| review_logs | DailyLearningActivity |
| learning_sessions | Notification |
| feedback | ... |
**选项**
- A) 保持全部 schema一次迁移创建所有表简单但有大量空表
- B) 先只迁移近期需要的表(干净但需要改 schema 文件)
---
## 决策 6Apple 登录什么时候接?
代码已写好AppleAuthService 带了 mock 兜底。
问题:
- `APPLE_BUNDLE_ID` 为空 → Apple 登录走 mock
- 真正的 Apple ID token 验证需要 Apple Developer 账号
- 这取决于你的 Apple Developer 审核进度
**当前行为**:即使 APPLE_BUNDLE_ID 为空Apple 登录接口也能用,只是不走真实验证。这对开发阶段来说够了。
---
# 三、当前无法处理的事情
这些事情需要外部条件满足才能推进:
| 阻塞项 | 原因 | 谁来解决 | 预计时间 |
|--------|------|----------|----------|
| 11 个 Repository 接 Prisma | 待逐一迁移 | 开发 | — |
| AiUsageLog 表建到服务器 | SSH 隧道未连通 | 你 | — |
| Apple 登录真实验证 | 需要 APPLE_BUNDLE_ID | Apple 审核 | 不确定 |
| BullMQ 队列 | 需要 Redis | 可推迟 | — |
| 文件上传 (COS/S3) | 需要选存储服务 | 可推迟 | — |
| iOS Keychain / AppSession | 前端配合 | iOS 开发时 | — |
## ✅ 已解决的阻塞项
| 阻塞项 | 状态 |
|--------|------|
| Prisma 首次迁移 | ✅ db push 完成,所有表已建 |
| 真实 AI 分析 | ✅ 三层架构已落地Mock/DeepSeek/MiniMax 三 Provider |
| BigInt ID 方案 | ✅ 全部改为 String cuid() |
---
# 四、分阶段可执行任务清单
## 阶段 1地基打通现在就要做
这些是最紧迫的,必须在写新功能之前完成。
### 任务 1.1:确认数据库连接 + 跑通首次迁移
**前置条件**:决策 1
```text
1. 确认 MySQL 服务已启动
2. 确认 zhixi 数据库已创建(不存在则 CREATE DATABASE zhixi
3. 根据决策 2 调整 Prisma schema 的 ID 类型
4. 运行 prisma migrate dev --name init
5. 验证生成的 migration SQL 无误
6. 运行 prisma generate
7. 启动服务,调 dev-login 验证 auth 模块正常工作
```
### 任务 1.2:解决 BigInt ID 方案
**前置条件**:决策 2
如果是方案 Acuid需要改
- `schema.prisma` 所有 `BigInt @default(autoincrement())``String @id @default(cuid())`
- `AuthService` 里的 `BigInt(userId)` 转换去掉
- `UsersRepository` 里的 `BigInt(userId)` 转换去掉
- `JwtAuthGuard``request.user` 类型
### 任务 1.3:把所有 Repository 从 Map 迁到 Prisma
**前置条件**:任务 1.1 + 1.2
按优先级迁:
```text
第一批(核心业务):
KnowledgeBaseRepository → prisma
KnowledgeItemsRepository → prisma
ActiveRecallRepository → prisma
第二批(学习闭环):
LearningSessionRepository → prisma
AiAnalysisRepository → prisma
FocusItemsRepository → prisma
ReviewRepository → prisma
第三批(辅助):
LearningActivityRepository → prisma
DocumentImportRepository → prisma
```
每个 repository 改造模板:
```text
1. 注入 PrismaService
2. create → prisma.xxx.create()
3. findById → prisma.xxx.findUnique()
4. findAllByUserId → prisma.xxx.findMany({ where: { userId } })
5. update → prisma.xxx.update()
6. softDelete → prisma.xxx.update({ data: { deletedAt: new Date() } })
7. 删除 Map 相关代码
```
### 任务 1.4:给所有 Controller 统一加 JwtAuthGuard
当前问题:
- `KnowledgeBaseController``@CurrentUser()` 标记了 `| undefined`,实际允许未登录访问
- 部分 Controller 根本没加 guard
```text
1. KnowledgeBaseController 加 @UseGuards(JwtAuthGuard)
2. KnowledgeItemsController 加 @UseGuards(JwtAuthGuard)
3. ActiveRecallController 加 @UseGuards(JwtAuthGuard)
4. AiAnalysisController 加 @UseGuards(JwtAuthGuard)
5. FocusItemsController 加 @UseGuards(JwtAuthGuard)
6. ReviewController 加 @UseGuards(JwtAuthGuard)
7. LearningSessionController 加 @UseGuards(JwtAuthGuard)
8. LearningActivityController 加 @UseGuards(JwtAuthGuard)
```
---
## 阶段 2第一个真实 AI Provider
### 任务 2.1:选 provider + 获取 API Key
**前置条件**:决策 3
### 任务 2.2:实现第一个真实 AI Provider
```text
1. 创建 DeepSeekProvider或你选的 provider
2. 实现 AiProvider 接口
3. 对接真实 API
4. 处理超时、重试、JSON 解析
5. 更新 AiModule 根据配置切换 provider
```
### 任务 2.3:实现第一个真实 Prompt 模板
硬编码在 MockAiProvider 里的静态 JSON 不能用了,需要:
```text
1. 编写主动回忆分析的 System Prompt
2. 设计输出 JSON Schema
3. 处理 AI 返回格式不稳定的情况JSON 解析错误兜底)
```
---
## 阶段 3学习闭环联调
### 任务 3.1:验证端到端流程
```text
用户登录
→ 创建知识库
→ 创建知识点
→ 开始学习会话
→ 提交主动回忆
→ AI 分析
→ 生成 FocusItem
→ 生成复习卡
→ 完成复习
```
---
# 五、决策汇总表(已确认)
| 编号 | 问题 | 决策 | 状态 |
|------|------|------|------|
| 决策 1 | MySQL 数据库当前状态? | URL-encode 密码 `@→%40, !→%21`,确认连接后 migrate | 已修复 DATABASE_URL |
| 决策 2 | BigInt vs cuid vs Int用哪个 ID 方案? | **全部 String cuid()**,不用 BigInt | 已完成 |
| 决策 3 | 第一个 AI Provider 选谁? | DeepSeek但先不接等核心闭环跑通 | 已决策 |
| 决策 4 | Redis 现在启动还是先绕过? | 先绕过,不阻塞主线 | 已决策 |
| 决策 5 | Prisma Schema 全部迁移还是分批? | 保留完整 schema一次迁移 | 已决策 |
| 决策 6 | Apple 登录什么时候接? | **现在接**BUNDLE_ID=cloud.longde.AIStudyApp | 已配置 |
## 已完成的改动
- [x] `schema.prisma`:全部 27 个 model 的 BigInt → String cuid()
- [x] `auth.service.ts`:删除 BigInt() 转换、bigint 类型 → string
- [x] `token.service.ts`bigint → string删除 String(user.id) 转换
- [x] `users.repository.ts`:删除所有 BigInt() 转换
- [x] `security.util.ts`number|bigint → string
- [x] `.env`DATABASE_URL 密码 URL-encode补 APPLE_BUNDLE_ID
- [x] `.env.example`:同步更新
## 待完成(需要 MySQL 环境)
- [ ] `prisma migrate dev --name init`
- [ ] `prisma generate`
- [ ] 启动服务,验证 dev-login、refresh、logout、users/me
- [ ] KnowledgeBaseRepository 接 Prisma第一个业务 repository 迁移)
- [ ] KnowledgeItemsRepository 接 Prisma
- [ ] ActiveRecallRepository 接 Prisma
- [ ] 所有 Controller 加 JwtAuthGuard