startup-plan/技术设计/api-server/已完成/[已完成]-当前状态与决策清单.md

361 lines
12 KiB
Markdown
Raw Normal View History

# 知习后端:当前状态 & 需要你处理的决策和任务
> 基于代码审计生成。**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