From 4435e4a8ab5f7578c826ae834fd5c251eadcca26 Mon Sep 17 00:00:00 2001 From: WangDL Date: Sat, 9 May 2026 20:33:33 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E7=A7=BB=20AI=E5=9B=9E?= =?UTF-8?q?=E7=AD=94.md=20=E5=88=B0=20docs/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BACKEND-PLAN.md | 1185 -------------------------------------------- DATABASE-DESIGN.md | 814 ------------------------------ REDIS-DESIGN.md | 262 ---------- SECURITY.md | 169 ------- docs/AI回答.md | 885 +++++++++++++++++++++++++++++++++ 5 files changed, 885 insertions(+), 2430 deletions(-) delete mode 100644 BACKEND-PLAN.md delete mode 100644 DATABASE-DESIGN.md delete mode 100644 REDIS-DESIGN.md delete mode 100644 SECURITY.md create mode 100644 docs/AI回答.md diff --git a/BACKEND-PLAN.md b/BACKEND-PLAN.md deleted file mode 100644 index f14ba85..0000000 --- a/BACKEND-PLAN.md +++ /dev/null @@ -1,1185 +0,0 @@ ---- -source: startup-plan/个人开发者创业 v0.1 + 完全版 + AI回答.md 架构深化方案 -updated: 2026-05-09 ---- - -# 知习 api-server 后端架构规划 - -> 「知习」是一款 AI-first 的系统化学习 App。后端需要同时服务 iOS App 和 Web 官网。 -> 核心功能包括知识库、主动回忆、AI 学习分析、间隔复习、待巩固项、学习活跃记录、消息通知和反馈。 - ---- - -## 1. 架构总览:模块化单体 + Redis + Worker - -**不要微服务。** 当前最适合的是: - -> **模块化单体架构 Monolithic Modular Architecture** -> -> 一个后端项目,内部按业务模块拆清楚。 - -```text -iOS App -Web 官网 - ↓ -统一 API 后端(NestJS 模块化单体) - ↓ -数据库 / Redis / 文件存储 / AI 服务 - ↓ -Worker 异步任务 -``` - ---- - -## 2. 最终技术栈 - -```text -后端框架:NestJS + TypeScript -ORM:Prisma -数据库:PostgreSQL(推荐),MySQL 亦可 -缓存/队列:Redis -队列系统:BullMQ -接口文档:Swagger / OpenAPI -文件存储:本地开发先本地存,后期接对象存储 -AI:Provider 抽象 + 一个真实模型 + MockProvider -部署:Docker Compose -反向代理:Nginx -域名:api.longde.cloud -``` - -Docker Compose 项目服务规划: - -```text -api-server — NestJS 后端 -postgres — 主数据库 -redis — 缓存 + 队列 -worker — 异步任务处理 -nginx — 反向代理 + HTTPS -``` - ---- - -## 3. 为什么选这个技术栈 - -### NestJS - -项目会越来越模块化。NestJS 的模块结构适合长期维护: - -```text -用户 / 知识库 / 学习记录 / AI 分析 / 复习计划 / 待巩固项 / 通知 / 反馈 / 订阅 -``` - -Express 也能做,但后期容易自己手写一堆规范,最后变乱。 - -### Prisma - -- 类型安全的 ORM,自动生成 TypeScript 类型 -- 迁移管理清晰 -- 与 NestJS 集成良好 -- AI Agent 按 schema 生成代码能力好 - -### PostgreSQL(优于 MySQL) - -- 更适合 JSON 数据(AI 分析结果) -- 支持全文检索 -- 后续可扩展 pgvector 做向量检索 -- 如果更熟悉 MySQL,也可以先用 MySQL - -### Redis + BullMQ - -Redis 不只是缓存,在知习系统里做四件事: - -```text -缓存 → 短期数据加速 -队列 → AI 分析 / 资料导入 / 通知任务 -限流 → AI 调用频控 / 用户请求限流 -临时状态 → 任务处理中状态 / 防重复提交锁 -``` - ---- - -## 4. 前后端职责分离 - -| 端 | 职责 | -|---|------| -| iOS 客户端 | 页面展示、用户交互、本地状态、登录入口、学习流程体验 | -| 后端 API | 用户身份、AI API 代理、学习记录、AI 分析、学习画像、复习计划、待巩固项、通知、反馈 | -| Worker | AI 分析任务异步处理、资料导入异步处理、通知分发 | -| AI 模型 | 分析用户输入、生成学习反馈、识别薄弱点、生成复习建议、辅助学习对话 | -| 官网 | 产品介绍、SEO、隐私政策、用户协议、支持页面、等待名单 | - ---- - -## 5. 数据库和 Redis 的分工 - -``` -PostgreSQL / MySQL:长期真实数据 -Redis:短期状态、缓存、队列、限流 -文件存储:PDF、图片、附件 -AI 服务:分析、总结、生成复习题 -``` - -一句话: - -> **数据库存事实,Redis 管状态。** - -### Redis 适合做 - -- AI 分析任务队列 -- 资料导入任务队列 -- 通知任务队列 -- 用户请求限流 -- AI 调用次数计数 -- 任务处理中状态 -- 防重复提交锁 -- 短期缓存 - -### Redis 不适合做主数据 - -这些必须进数据库: - -- 用户资料 -- 知识库 -- 学习记录 -- AI 分析结果 -- 待巩固项 -- 复习计划 -- 学习活跃记录 -- 通知记录 - ---- - -## 6. 后端目录结构 - -```text -api-server/ -├── src/ -│ ├── main.ts -│ ├── app.module.ts -│ │ -│ ├── config/ -│ │ ├── app.config.ts -│ │ ├── database.config.ts -│ │ ├── redis.config.ts -│ │ ├── jwt.config.ts -│ │ ├── ai.config.ts -│ │ └── storage.config.ts -│ │ -│ ├── common/ -│ │ ├── constants/ -│ │ ├── decorators/ -│ │ ├── guards/ -│ │ ├── interceptors/ -│ │ ├── filters/ -│ │ ├── pipes/ -│ │ ├── dto/ -│ │ ├── types/ -│ │ └── utils/ -│ │ -│ ├── infrastructure/ -│ │ ├── database/ -│ │ ├── redis/ -│ │ ├── queue/ -│ │ ├── ai/ -│ │ │ ├── prompts/ -│ │ │ └── providers/ -│ │ ├── storage/ -│ │ └── logger/ -│ │ -│ ├── modules/ -│ │ ├── auth/ -│ │ ├── users/ -│ │ ├── knowledge-base/ -│ │ ├── knowledge-items/ -│ │ ├── document-import/ -│ │ ├── learning-session/ -│ │ ├── active-recall/ -│ │ ├── ai-analysis/ -│ │ ├── review/ -│ │ ├── focus-items/ -│ │ ├── learning-activity/ -│ │ ├── notifications/ -│ │ ├── feedback/ -│ │ └── system/ -│ │ -│ └── workers/ -│ ├── ai-analysis.worker.ts -│ ├── document-import.worker.ts -│ └── notification.worker.ts -│ -├── prisma/ -│ ├── schema.prisma -│ └── migrations/ -│ -├── docker-compose.yml -├── Dockerfile -├── .env.example -└── package.json -``` - ---- - -## 7. 各模块职责 - -### 7.1 Auth 模块 - -负责 Apple 登录、JWT、刷新 Token、退出登录、账号注销。 - -App Store 上架要求 Sign in with Apple,这是必须做的。 - -### 7.2 Users 模块 - -负责用户资料、头像、昵称、学习身份、学习方向、学习偏好。 - -### 7.3 Knowledge Base 模块 - -负责知识库创建、列表、详情、编辑、删除、标签。 - -### 7.4 Knowledge Items 模块 - -负责具体知识点、章节、内容段落、关键概念、标签、关联关系。 - -### 7.5 Document Import 模块 - -负责上传文件、粘贴文本、链接导入、导入状态、解析进度、导入成功/失败。 - -这里非常适合用 Redis Queue 做异步处理。 - -### 7.6 Learning Session 模块 - -负责一次学习过程:开始学习、结束学习、学习时长、学习内容、学习模式、完成状态。 - -这是学习活跃图的数据来源之一。 - -### 7.7 Active Recall 模块 - -负责主动回忆:回忆问题、用户回答、语音回答、回答提交、回答历史。 - -### 7.8 AI Analysis 模块 - -负责提交分析任务、分析状态、AI 分析结果、掌握度、薄弱点、改进建议、下一步建议。 - -**必须走 Redis Queue 异步处理。** - -### 7.9 Focus Items 模块 - -「待巩固项」——类似 GitHub Issue,但在知习里叫待巩固项。 - -负责:AI 自动生成待巩固项、用户手动添加、状态(待处理/已加入复习/已完成)、关联知识点、关联学习记录。 - -### 7.10 Review 模块 - -负责复习卡片、到期复习、间隔复习计划、复习结果、掌握程度选择、下次复习时间。 - -### 7.11 Learning Activity 模块 - -负责学习活跃图:每日学习时长、主动回忆次数、复习次数、AI 分析次数、完成学习闭环次数、学习活跃度等级。 - -活跃图数据最终写入数据库,Redis 可做临时累计。 - -### 7.12 Notifications 模块 - -负责复习提醒、AI 分析完成提醒、学习建议、系统通知、已读/未读。 - -### 7.13 Feedback 模块 - -负责 Web 和 App 反馈:用户反馈、问题类型、邮箱、设备、处理状态。 - -### 7.14 System 模块 - -健康检查、应用状态、基础运维接口。 - ---- - -## 8. 模块优先级 - -### v0.1 必须实现 - -```text -auth -users -knowledge-base -knowledge-items -learning-session -active-recall -ai-analysis -focus-items -review -learning-activity -feedback -system -``` - -### v0.1 暂缓 - -```text -document-import — 先手动录入内容 -notifications — 先不做推送 -billing — 暂无付费 -subscription — 暂无订阅 -admin-dashboard — 暂无管理后台 -team — 单人使用 -``` - ---- - -## 9. API 路由规划 - -```text -GET /api/health - -POST /api/auth/apple -POST /api/auth/refresh -POST /api/auth/logout - -GET /api/users/me -PATCH /api/users/me -PATCH /api/users/me/preferences - -GET /api/knowledge-bases -POST /api/knowledge-bases -GET /api/knowledge-bases/:id -PATCH /api/knowledge-bases/:id -DELETE /api/knowledge-bases/:id -GET /api/knowledge-bases/:id/items - -GET /api/knowledge-items/:id -POST /api/knowledge-items - -POST /api/imports -GET /api/imports/:id/status - -POST /api/learning-sessions -POST /api/learning-sessions/:id/end - -GET /api/active-recalls -POST /api/active-recalls/:id/submit - -POST /api/ai-analysis -GET /api/ai-analysis/:id -GET /api/ai-analysis/jobs/:jobId/status - -GET /api/focus-items -POST /api/focus-items -PATCH /api/focus-items/:id -POST /api/focus-items/:id/complete - -GET /api/reviews/due -POST /api/reviews/:id/submit - -GET /api/activity/heatmap -GET /api/activity/summary - -GET /api/notifications -POST /api/notifications/:id/read - -POST /api/feedback -``` - ---- - -## 10. 关键请求流程 - -核心异步流程详见 [23. 异步模块额外文件 - AI 分析模块完整流程](#23-异步模块额外文件queue--processor)。 - ---- - -## 11. 核心 AI 接口 - -### POST /api/ai-analysis(提交异步任务) - -输入: -```json -{ - "sessionId": "session_001", - "lessonId": "lesson_001", - "userInput": "用户写下的答案或笔记", - "context": { - "lessonTitle": "材料阅读方法", - "objectives": ["理解材料结构", "提取关键要点"], - "keyPoints": ["问题", "原因", "影响", "对策"] - } -} -``` - -返回: -```json -{ - "jobId": "job_abc123", - "status": "pending" -} -``` - -### GET /api/ai-analysis/jobs/:jobId/status(查询状态) - -```json -{ - "jobId": "job_abc123", - "status": "completed", - "result": { - "masteryScore": 3, - "understandingLevel": "基本理解", - "summary": "用户能理解主要内容,但要点不完整。", - "strengths": ["表达清楚"], - "weakPoints": ["遗漏关键要点", "逻辑层次不足"], - "suggestions": ["补充第二个要点", "先概括再展开"], - "reviewNeeded": true, - "nextAction": "明天重新回答本节主动回忆问题。" - } -} -``` - ---- - -## 12. AI Provider 层设计 - -```text -AIService - ├── MiniMaxProvider - ├── DeepSeekProvider - ├── OpenAIProvider - └── MockProvider -``` - -### MockProvider - -v0.1 强烈建议做 MockProvider: -- 没有 API Key 时也能开发 -- AI 服务出问题时能测试流程 -- 降低开发成本 -- 方便录 Demo - -### 候选模型 - -MiniMax / DeepSeek / 通义千问 / OpenAI / Claude / Gemini - -### 模型选择原则 - -1. 中文能力好 -2. 成本可控 -3. API 稳定 -4. 支持结构化输出 -5. 速度可以接受 -6. 容易接入 -7. 可替换 - ---- - -## 13. 核心实体/数据模型 - -```text -User -├── id -├── appleUserId -├── displayName -├── email -├── preferredLanguage -├── learningDirection -├── createdAt -├── lastLoginAt -└── status - -KnowledgeBase -├── id -├── userId -├── title -├── description -├── language -├── tags -├── createdAt -└── updatedAt - -KnowledgeItem -├── id -├── knowledgeBaseId -├── parentId -├── title -├── content -├── type (chapter/section/concept) -├── objectives -├── keyPoints -├── recallQuestions -├── order -└── estimatedMinutes - -DocumentImport -├── id -├── userId -├── knowledgeBaseId -├── sourceType (file/text/link) -├── status (pending/processing/completed/failed) -├── result -├── createdAt -└── completedAt - -LearningSession -├── id -├── userId -├── knowledgeItemId -├── startedAt -├── endedAt -├── durationSeconds -├── mode (reading/recall/review) -└── completedAt - -ActiveRecall -├── id -├── sessionId -├── question -├── userAnswer -├── answerType (text/voice) -├── submittedAt - -AIAnalysis -├── id -├── jobId -├── userId -├── sessionId -├── inputText -├── outputJson -├── masteryScore -├── weakPoints -├── suggestions -├── modelName -├── costEstimate -├── status (pending/processing/completed/failed) -├── createdAt -└── completedAt - -FocusItem -├── id -├── userId -├── knowledgeItemId -├── aiAnalysisId -├── title -├── description -├── status (pending/in_review/completed) -├── createdAt -└── completedAt - -ReviewTask -├── id -├── userId -├── knowledgeItemId -├── focusItemId -├── reviewType -├── scheduledAt -├── completedAt -├── masteryChoice -├── nextReviewAt -└── status - -LearningActivity -├── id -├── userId -├── date -├── durationSeconds -├── recallCount -├── reviewCount -├── analysisCount -├── closedLoopCount -├── activityLevel -└── updatedAt - -Notification -├── id -├── userId -├── type -├── title -├── body -├── data (JSON) -├── isRead -└── createdAt - -Feedback -├── id -├── userId -├── type -├── content -├── email -├── device -├── status -└── createdAt -``` - ---- - -## 14. 掌握度评分(0-5分) - -```text -0 = 没有作答 / 无法判断 -1 = 基本没理解 -2 = 理解较弱 -3 = 基本理解 -4 = 理解较好 -5 = 掌握很好 -``` - -这不是考试分数,是产品内部用于安排复习和学习建议的参考值。 - ---- - -## 15. 账号体系 - -### 第一版登录方式 - -```text -Sign in with Apple -``` - -暂不做:微信登录、手机号登录、邮箱密码登录、Google 登录。 - -### 账号边界 - -第一版账号只解决:登录、识别用户、保存学习记录、保存 AI 分析结果、保存基础偏好。 - -暂不做:好友系统、用户主页、头像上传、多登录方式绑定、复杂权限系统。 - ---- - -## 16. 部署方案 - -### 当前服务器 - -- IP: 81.70.187.179 -- 配置: 4 核 4G,40G SSD -- 当前运行: Gitea(端口 3000)+ Nginx -- SSH: ubuntu 用户 + WangDL.pem 密钥 - -### 推荐部署方式 - -```text -Nginx — 反向代理,已有 -api-server (NestJS) — 端口 3001 -postgres / mysql — 端口 5432 / 3306 -redis — 端口 6379 -worker (BullMQ) — 同代码仓库,独立进程 -gitea — 端口 3000,继续保留 -``` - -建议新增 Nginx 配置 `api.longde.cloud` → 反向代理到 NestJS 端口。 - -### 资源评估 - -Gitea 当前资源占用很低(内存 ~500MB),剩余 ~3GB 内存、33GB 磁盘足够跑 api-server + PostgreSQL + Redis。 - ---- - -## 17. 域名与 Nginx 规划 - -```text -longde.cloud 官网首页 -api.longde.cloud 后端 API(需新增 Nginx 配置) -git.longde.cloud Gitea 代码仓库(已有) -``` - -### 待新增 Nginx 配置(api.longde.cloud) - -```nginx -server { - server_name api.longde.cloud; - location / { - proxy_pass http://127.0.0.1:3001; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - listen 443 ssl; - ssl_certificate /etc/letsencrypt/live/api.longde.cloud/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/api.longde.cloud/privkey.pem; -} -``` - ---- - -## 18. 技术里程碑 - -### 里程碑 1:最小后端 - -- NestJS 项目初始化 -- Prisma schema 定义 -- PostgreSQL/MySQL 连接 -- 用户表、知识库表 -- AI MockProvider -- Swagger 文档 - -### 里程碑 2:真实 AI 接入 - -- Redis + BullMQ 接入 -- AI Provider 抽象 -- 接入一个真实模型 -- AI 分析异步流程 -- Worker 处理 AI 任务 - -### 里程碑 3:TestFlight 前准备 - -- Sign in with Apple -- 后端用户身份记录 -- 基础错误处理 -- Docker Compose 一键部署 -- Nginx 反向代理配置 - ---- - -## 19. 商业化与支付(未来) - -### 支付流程 - -```text -用户在 iOS App 内付款 → Apple IAP 完成交易 → 后端记录用户权益 → 用户获得权益 -``` - -### 核心 - -不要让 Apple IAP 成为整个商业系统。真正核心的是: - -```text -用户系统 + 订单系统 + 权益系统 -``` - -### 当前暂缓 - -Apple IAP / 月订阅 / 年订阅 / 免费试用 / 订阅权益系统 / AI 成本精算 - ---- - -## 20. 当前技术不做清单 - -- 微服务 / Kubernetes / 多云部署 -- 完整后台管理系统 / CMS -- 完整 RAG / 向量数据库(第一版) -- 多模型自动路由 -- AI Agent 工具调用系统 -- 支付系统 -- 复杂数据分析平台 -- Android / Web 学习端 - ---- - -## 21. 四层代码分层原则 - -整体分四层,每一层有明确的职责边界: - -```text -Controller 层:接收请求,处理参数,返回响应 -Service 层:业务逻辑 -Repository 层:数据库读写 -Infrastructure 层:Redis、Queue、AI、Storage 等基础设施 -``` - -简单理解: - -```text -Controller 不写业务 -Service 不直接写复杂 SQL -Repository 不写业务判断 -Infrastructure 不知道具体业务,只提供能力 -``` - -一句话纪律: - -```text -Controller = 接口 Service = 业务 Repository = 数据库 -Infrastructure = 外部能力 Queue/Processor = 异步任务 DTO = 请求/响应结构 -``` - -第一版不要追求所有业务一次写完,但**架构模板必须先统一**。 - ---- - -## 22. 模块内部统一模板 - -每个业务模块都按这个结构来。以 `knowledge-base` 为例: - -```text -modules/knowledge-base/ -├── knowledge-base.module.ts -├── knowledge-base.controller.ts -├── knowledge-base.service.ts -├── knowledge-base.repository.ts -├── dto/ -│ ├── create-knowledge-base.dto.ts -│ ├── update-knowledge-base.dto.ts -│ ├── query-knowledge-base.dto.ts -│ └── knowledge-base-response.dto.ts -├── types/ -│ └── knowledge-base.types.ts -└── constants/ - └── knowledge-base.constants.ts -``` - -### 22.1 xxx.module.ts - -```text -作用: -- 注册 controller -- 注册 service -- 注册 repository -- 引入依赖模块 -- 导出给其他模块使用 -``` - -```ts -@Module({ - controllers: [KnowledgeBaseController], - providers: [KnowledgeBaseService, KnowledgeBaseRepository], - exports: [KnowledgeBaseService], -}) -export class KnowledgeBaseModule {} -``` - -### 22.2 xxx.controller.ts - -**只做这些事:** -1. 定义路由 -2. 接收参数 -3. 调用 service -4. 返回结果 - -**不要在 Controller 里写业务判断。** - -```ts -@Controller('knowledge-bases') -export class KnowledgeBaseController { - constructor(private readonly service: KnowledgeBaseService) {} - - @Post() - create(@Body() dto: CreateKnowledgeBaseDto, @CurrentUser() user: UserPayload) { - return this.service.create(user.id, dto); - } - - @Get() - findAll(@CurrentUser() user: UserPayload, @Query() query: QueryKnowledgeBaseDto) { - return this.service.findAll(user.id, query); - } - - @Get(':id') - findOne(@Param('id') id: string, @CurrentUser() user: UserPayload) { - return this.service.findOne(user.id, id); - } -} -``` - -### 22.3 xxx.service.ts - -**这里写:** -1. 权限判断 -2. 业务规则 -3. 调用 repository -4. 调用其他模块 service -5. 调用 queue / AI / Redis -6. 组织返回结果 - -```ts -@Injectable() -export class KnowledgeBaseService { - constructor( - private readonly repository: KnowledgeBaseRepository, - ) {} - - async create(userId: string, dto: CreateKnowledgeBaseDto) { - const count = await this.repository.countByUserId(userId); - if (count >= MAX_KNOWLEDGE_BASE_COUNT) { - throw new BadRequestException('知识库数量已达到上限'); - } - return this.repository.create(userId, dto); - } - - async findOne(userId: string, id: string) { - const knowledgeBase = await this.repository.findById(id); - if (!knowledgeBase || knowledgeBase.userId !== userId) { - throw new NotFoundException('知识库不存在'); - } - return knowledgeBase; - } -} -``` - -### 22.4 xxx.repository.ts - -**只写数据库操作,不写复杂业务。** - -```ts -@Injectable() -export class KnowledgeBaseRepository { - constructor(private readonly prisma: PrismaService) {} - - create(userId: string, dto: CreateKnowledgeBaseDto) { - return this.prisma.knowledgeBase.create({ - data: { userId, name: dto.name, description: dto.description }, - }); - } - - findById(id: string) { - return this.prisma.knowledgeBase.findUnique({ where: { id } }); - } - - countByUserId(userId: string) { - return this.prisma.knowledgeBase.count({ where: { userId } }); - } -} -``` - -### 22.5 dto/ - -DTO 就是接口输入输出的数据结构。 - -用途: -1. 校验请求参数 -2. 生成 Swagger 文档 -3. 让接口结构清楚 - -```ts -export class CreateKnowledgeBaseDto { - @ApiProperty({ example: '认知心理学' }) - @IsString() - @IsNotEmpty() - name: string; - - @ApiProperty({ example: '系统学习认知心理学基础概念', required: false }) - @IsOptional() - @IsString() - description?: string; -} -``` - -### 22.6 types/ - -放模块内部类型。如果是数据库模型,不放这里,放 Prisma。 - -```ts -export type KnowledgeBaseStatus = 'active' | 'archived'; - -export interface KnowledgeBaseStats { - itemCount: number; - completedCount: number; - reviewDueCount: number; -} -``` - -### 22.7 constants/ - -放模块常量。 - -```ts -export const MAX_KNOWLEDGE_BASE_COUNT = 20; -export const DEFAULT_KNOWLEDGE_BASE_COVER = 'default-blue'; -``` - ---- - -## 23. 异步模块额外文件(Queue + Processor) - -涉及异步任务的模块,需要在标准模板上加 `queue`、`processor`、`jobs`。 - -以 `ai-analysis` 为例: - -```text -modules/ai-analysis/ -├── ai-analysis.module.ts -├── ai-analysis.controller.ts -├── ai-analysis.service.ts -├── ai-analysis.repository.ts -├── ai-analysis.queue.ts ← 封装 BullMQ 队列 -├── ai-analysis.processor.ts ← 消费任务,调用大模型 -├── dto/ -│ ├── create-ai-analysis.dto.ts -│ ├── query-ai-analysis.dto.ts -│ └── ai-analysis-response.dto.ts -├── jobs/ -│ └── ai-analysis.job.ts ← 队列任务数据结构 -├── types/ -│ └── ai-analysis.types.ts -└── constants/ - └── ai-analysis.constants.ts -``` - -### 文件职责 - -| 文件 | 职责 | -|------|------| -| `controller` | 接收创建分析任务、查询分析结果的接口 | -| `service` | 创建任务、查询状态、组织业务流程 | -| `repository` | 读写 AI 分析任务和分析结果 | -| `queue` | 封装 BullMQ 队列添加任务 | -| `processor` | 真正消费任务,调用大模型 | -| `jobs/xxx.job.ts` | 定义队列任务的数据结构 | - -### AI 分析模块完整流程 - -```text -App 提交回答 - ↓ -Controller 接收请求 - ↓ -Service 创建分析任务 - ↓ -Repository 写入数据库 job 记录 - ↓ -Queue 加入 Redis 队列 - ↓ -Processor 后台消费任务 - ↓ -AI Service 调用大模型 - ↓ -Repository 写入分析结果 - ↓ -生成待巩固项 - ↓ -生成复习计划 - ↓ -通知用户 -``` - ---- - -## 24. AI 层设计:不允许业务模块直接调大模型 SDK - -### 原则 - -后面肯定会换模型、换供应商,所以 AI 不要写死在业务模块里。 - -**不推荐:** -```ts -// 不要直接在业务 service 里写 -await openai.chat.completions.create(...) -``` - -**应该:** -```text -业务模块 → AiService → 具体 Provider -``` - -```ts -@Injectable() -export class AiService { - constructor(private readonly provider: AiProvider) {} - - analyzeActiveRecall(input: ActiveRecallAnalysisInput) { - return this.provider.generateActiveRecallAnalysis(input); - } -} -``` - -这样从 OpenAI 换 DeepSeek、Gemini、Claude,都不用改业务代码。 - ---- - -## 25. Infrastructure 层详细拆解 - -`infrastructure` 是所有模块共用的底层能力。 - -```text -infrastructure/ -├── database/ -│ ├── prisma.module.ts -│ └── prisma.service.ts -│ -├── redis/ -│ ├── redis.module.ts -│ ├── redis.service.ts -│ └── redis.constants.ts -│ -├── queue/ -│ ├── queue.module.ts -│ ├── queue.constants.ts -│ └── queue.service.ts -│ -├── ai/ -│ ├── ai.module.ts -│ ├── ai.service.ts -│ ├── ai-provider.interface.ts -│ ├── providers/ -│ │ ├── openai.provider.ts -│ │ ├── deepseek.provider.ts -│ │ └── mock-ai.provider.ts -│ └── prompts/ -│ ├── active-recall-analysis.prompt.ts -│ └── focus-item-generation.prompt.ts -│ -├── storage/ -│ ├── storage.module.ts -│ ├── storage.service.ts -│ └── local-storage.provider.ts -│ -└── logger/ - ├── logger.module.ts - └── app-logger.service.ts -``` - ---- - -## 26. Common 层详细拆解 - -```text -common/ -├── decorators/ -│ └── current-user.decorator.ts -├── guards/ -│ ├── jwt-auth.guard.ts -│ └── optional-auth.guard.ts -├── interceptors/ -│ └── response.interceptor.ts -├── filters/ -│ └── http-exception.filter.ts -├── pipes/ -│ └── validation.pipe.ts -├── dto/ -│ ├── pagination.dto.ts -│ └── api-response.dto.ts -├── types/ -│ ├── user-payload.type.ts -│ └── pagination.type.ts -├── constants/ -│ └── app.constants.ts -└── utils/ - ├── date.util.ts - ├── hash.util.ts - └── id.util.ts -``` - ---- - -## 27. 模块复杂度分级 - -### 简单模块 - -结构 `module + controller + service + repository + dto` - -适用于:`feedback`、`system`、`notifications`(初版) - -### 中等模块 - -结构 `module + controller + service + repository + dto + types + constants` - -适用于:`users`、`knowledge-base`、`knowledge-items`、`learning-session`、`review`、`focus-items` - -### 复杂模块 - -结构 `module + controller + service + repository + queue + processor + jobs + dto + types + constants` - -适用于:`ai-analysis`、`document-import`、`notifications`(后期) - ---- - -## 28. 初始化顺序 - -第一版不要所有业务都写完。先搭基础设施骨架: - -```text - 1. infrastructure/database - 2. infrastructure/redis - 3. infrastructure/queue - 4. infrastructure/ai - 5. common - 6. system/health - 7. auth skeleton - 8. users skeleton - 9. knowledge-base skeleton -10. ai-analysis skeleton -``` - -这样就够开始开发。 - - diff --git a/DATABASE-DESIGN.md b/DATABASE-DESIGN.md deleted file mode 100644 index e1832f3..0000000 --- a/DATABASE-DESIGN.md +++ /dev/null @@ -1,814 +0,0 @@ ---- -source: AI回答.md -updated: 2026-05-09 ---- - -# 知习 MySQL 数据库表结构设计 - -> 共 27 张表,v0.1 先建 24 张核心表。 - ---- - -## 通用字段规范 - -每张核心表统一使用: - -```sql -id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, -created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -deleted_at DATETIME NULL -``` - -- `id`:内部主键 -- `created_at`:创建时间 -- `updated_at`:更新时间 -- `deleted_at`:软删除 - -状态字段统一用 `VARCHAR(32)`,不用 MySQL ENUM。 - ---- - -## 一、用户与认证表(5 张) - -### 1. users 用户表 - -```sql -users -- id BIGINT UNSIGNED PK -- email VARCHAR(255) NULL -- nickname VARCHAR(100) NULL -- avatar_url VARCHAR(500) NULL -- status VARCHAR(32) NOT NULL DEFAULT 'active' -- onboarding_completed TINYINT(1) NOT NULL DEFAULT 0 -- last_login_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -- deleted_at DATETIME NULL -``` - -索引: -```sql -INDEX idx_users_email (email) -INDEX idx_users_status (status) -``` - ---- - -### 2. auth_accounts 第三方登录账号表 - -```sql -auth_accounts -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- provider VARCHAR(32) NOT NULL -- apple -- provider_user_id VARCHAR(255) NOT NULL -- Apple userIdentifier / sub -- email VARCHAR(255) NULL -- raw_profile_json JSON NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -UNIQUE KEY uk_provider_user (provider, provider_user_id) -INDEX idx_auth_accounts_user_id (user_id) -``` - ---- - -### 3. refresh_tokens 刷新 Token 表 - -```sql -refresh_tokens -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- token_hash VARCHAR(255) NOT NULL -- device_id VARCHAR(255) NULL -- device_name VARCHAR(255) NULL -- expires_at DATETIME NOT NULL -- revoked_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_refresh_tokens_user_id (user_id) -INDEX idx_refresh_tokens_token_hash (token_hash) -``` - ---- - -### 4. user_profiles 用户资料扩展表 - -```sql -user_profiles -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- learning_identity VARCHAR(100) NULL -- 系统学习者 / 备考用户 / 知识工作者 -- learning_direction VARCHAR(255) NULL -- 认知科学 / AIGC / 产品设计 -- bio TEXT NULL -- current_goal VARCHAR(255) NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -UNIQUE KEY uk_user_profiles_user_id (user_id) -``` - ---- - -### 5. user_preferences 用户学习偏好表 - -```sql -user_preferences -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- preferred_methods JSON NULL - -- ["active_recall", "spaced_repetition", "feynman", "retrieval_practice"] -- default_focus_minutes INT NOT NULL DEFAULT 25 -- ai_suggestion_level VARCHAR(32) NOT NULL DEFAULT 'normal' - -- low / normal / high -- language VARCHAR(32) NOT NULL DEFAULT 'zh-CN' -- appearance VARCHAR(32) NOT NULL DEFAULT 'system' -- notification_enabled TINYINT(1) NOT NULL DEFAULT 1 -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -UNIQUE KEY uk_user_preferences_user_id (user_id) -``` - ---- - -## 二、知识库相关表(5 张) - -### 6. knowledge_bases 知识库表 - -```sql -knowledge_bases -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- title VARCHAR(255) NOT NULL -- description TEXT NULL -- cover_key VARCHAR(100) NULL -- status VARCHAR(32) NOT NULL DEFAULT 'active' - -- active / archived / deleted -- item_count INT NOT NULL DEFAULT 0 -- last_studied_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -- deleted_at DATETIME NULL -``` - -索引: -```sql -INDEX idx_knowledge_bases_user_id (user_id) -INDEX idx_knowledge_bases_status (status) -``` - ---- - -### 7. knowledge_items 知识点/内容表 - -```sql -knowledge_items -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- knowledge_base_id BIGINT UNSIGNED NOT NULL -- parent_id BIGINT UNSIGNED NULL -- item_type VARCHAR(32) NOT NULL - -- chapter / lesson / concept / note / imported_doc -- title VARCHAR(255) NOT NULL -- content LONGTEXT NULL -- summary TEXT NULL -- source_type VARCHAR(32) NULL - -- manual / file / url / ai_generated -- source_ref VARCHAR(500) NULL -- order_index INT NOT NULL DEFAULT 0 -- status VARCHAR(32) NOT NULL DEFAULT 'active' -- created_at DATETIME -- updated_at DATETIME -- deleted_at DATETIME NULL -``` - -索引: -```sql -INDEX idx_knowledge_items_user_id (user_id) -INDEX idx_knowledge_items_kb_id (knowledge_base_id) -INDEX idx_knowledge_items_parent_id (parent_id) -INDEX idx_knowledge_items_type (item_type) -``` - ---- - -### 8. knowledge_item_relations 知识点关联表 - -```sql -knowledge_item_relations -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- source_item_id BIGINT UNSIGNED NOT NULL -- target_item_id BIGINT UNSIGNED NOT NULL -- relation_type VARCHAR(32) NOT NULL - -- related / prerequisite / similar / conflict / extension -- confidence DECIMAL(5,2) NULL -- reason TEXT NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_relations_source (source_item_id) -INDEX idx_relations_target (target_item_id) -``` - ---- - -### 9. tags 标签表 - -```sql -tags -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- name VARCHAR(100) NOT NULL -- color VARCHAR(32) NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -UNIQUE KEY uk_user_tag_name (user_id, name) -``` - ---- - -### 10. knowledge_item_tags 知识点标签关联表 - -```sql -knowledge_item_tags -- id BIGINT UNSIGNED PK -- knowledge_item_id BIGINT UNSIGNED NOT NULL -- tag_id BIGINT UNSIGNED NOT NULL -- created_at DATETIME -``` - -索引: -```sql -UNIQUE KEY uk_item_tag (knowledge_item_id, tag_id) -``` - ---- - -## 三、资料导入相关表(2 张) - -### 11. uploaded_files 上传文件表 - -```sql -uploaded_files -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- filename VARCHAR(255) NOT NULL -- mime_type VARCHAR(100) NULL -- storage_path VARCHAR(500) NOT NULL -- size_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0 -- checksum VARCHAR(255) NULL -- created_at DATETIME -``` - -索引: -```sql -INDEX idx_uploaded_files_user_id (user_id) -``` - ---- - -### 12. document_imports 资料导入任务表 - -```sql -document_imports -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- knowledge_base_id BIGINT UNSIGNED NULL -- file_id BIGINT UNSIGNED NULL -- source_type VARCHAR(32) NOT NULL - -- file / text / url -- source_name VARCHAR(255) NULL -- source_url VARCHAR(500) NULL -- raw_text LONGTEXT NULL -- status VARCHAR(32) NOT NULL DEFAULT 'pending' - -- pending / processing / success / failed -- progress INT NOT NULL DEFAULT 0 -- error_message TEXT NULL -- result_json JSON NULL -- started_at DATETIME NULL -- completed_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_document_imports_user_id (user_id) -INDEX idx_document_imports_status (status) -``` - ---- - -## 四、学习过程相关表(2 张) - -### 13. learning_sessions 学习会话表 - -```sql -learning_sessions -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- knowledge_base_id BIGINT UNSIGNED NULL -- knowledge_item_id BIGINT UNSIGNED NULL -- mode VARCHAR(32) NOT NULL - -- reading / active_recall / review / feynman / free_learning -- status VARCHAR(32) NOT NULL DEFAULT 'active' - -- active / completed / cancelled -- started_at DATETIME NOT NULL -- ended_at DATETIME NULL -- duration_seconds INT NOT NULL DEFAULT 0 -- focus_minutes INT NULL -- metadata JSON NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_learning_sessions_user_id (user_id) -INDEX idx_learning_sessions_item_id (knowledge_item_id) -INDEX idx_learning_sessions_started_at (started_at) -``` - ---- - -### 14. learning_records 学习记录表 - -类似 GitHub commit log,语义是学习记录。 - -```sql -learning_records -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- session_id BIGINT UNSIGNED NULL -- record_type VARCHAR(32) NOT NULL - -- read / active_recall / review / ai_analysis / focus_item_completed -- title VARCHAR(255) NOT NULL -- description TEXT NULL -- duration_seconds INT NOT NULL DEFAULT 0 -- occurred_at DATETIME NOT NULL -- metadata JSON NULL -- created_at DATETIME -``` - -索引: -```sql -INDEX idx_learning_records_user_id (user_id) -INDEX idx_learning_records_occurred_at (occurred_at) -``` - ---- - -## 五、主动回忆相关表(2 张) - -### 15. active_recall_questions 主动回忆问题表 - -```sql -active_recall_questions -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- knowledge_item_id BIGINT UNSIGNED NULL -- question_text TEXT NOT NULL -- difficulty VARCHAR(32) NULL - -- easy / normal / hard -- created_by VARCHAR(32) NOT NULL DEFAULT 'ai' - -- ai / user / system -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_recall_questions_user_id (user_id) -INDEX idx_recall_questions_item_id (knowledge_item_id) -``` - ---- - -### 16. active_recall_answers 主动回忆回答表 - -```sql -active_recall_answers -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- question_id BIGINT UNSIGNED NULL -- session_id BIGINT UNSIGNED NULL -- answer_type VARCHAR(32) NOT NULL DEFAULT 'text' - -- text / voice -- answer_text LONGTEXT NULL -- audio_file_id BIGINT UNSIGNED NULL -- submitted_at DATETIME NOT NULL -- created_at DATETIME -``` - -索引: -```sql -INDEX idx_recall_answers_user_id (user_id) -INDEX idx_recall_answers_question_id (question_id) -INDEX idx_recall_answers_session_id (session_id) -``` - ---- - -## 六、AI 分析相关表(2 张) - -### 17. ai_analysis_jobs AI 分析任务表 - -```sql -ai_analysis_jobs -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- session_id BIGINT UNSIGNED NULL -- answer_id BIGINT UNSIGNED NULL -- job_type VARCHAR(32) NOT NULL - -- active_recall_analysis / weak_point_detection / review_generation -- status VARCHAR(32) NOT NULL DEFAULT 'pending' - -- pending / processing / success / failed -- progress INT NOT NULL DEFAULT 0 -- error_message TEXT NULL -- queued_at DATETIME NULL -- started_at DATETIME NULL -- completed_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_ai_jobs_user_id (user_id) -INDEX idx_ai_jobs_status (status) -INDEX idx_ai_jobs_session_id (session_id) -``` - ---- - -### 18. ai_analysis_results AI 分析结果表 - -```sql -ai_analysis_results -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- job_id BIGINT UNSIGNED NOT NULL -- session_id BIGINT UNSIGNED NULL -- answer_id BIGINT UNSIGNED NULL -- summary TEXT NULL -- mastery_score INT NULL -- 0-100 -- strengths JSON NULL -- weaknesses JSON NULL -- suggestions JSON NULL -- next_actions JSON NULL -- raw_result JSON NULL -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_ai_results_user_id (user_id) -INDEX idx_ai_results_job_id (job_id) -INDEX idx_ai_results_session_id (session_id) -``` - ---- - -## 七、待巩固项表(1 张) - -### 19. focus_items 待巩固项表 - -类似 GitHub issue,学习语义叫「待巩固项」。 - -```sql -focus_items -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- knowledge_base_id BIGINT UNSIGNED NULL -- knowledge_item_id BIGINT UNSIGNED NULL -- analysis_result_id BIGINT UNSIGNED NULL -- title VARCHAR(255) NOT NULL -- reason TEXT NULL -- suggestion TEXT NULL -- priority VARCHAR(32) NOT NULL DEFAULT 'normal' - -- low / normal / high -- status VARCHAR(32) NOT NULL DEFAULT 'open' - -- open / in_review / completed / ignored -- mastery_score INT NULL -- due_at DATETIME NULL -- completed_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -- deleted_at DATETIME NULL -``` - -索引: -```sql -INDEX idx_focus_items_user_id (user_id) -INDEX idx_focus_items_status (status) -INDEX idx_focus_items_due_at (due_at) -``` - ---- - -## 八、复习相关表(3 张) - -### 20. review_cards 复习卡片表 - -```sql -review_cards -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- knowledge_item_id BIGINT UNSIGNED NULL -- focus_item_id BIGINT UNSIGNED NULL -- front_text TEXT NOT NULL -- back_text TEXT NULL -- difficulty VARCHAR(32) NULL -- status VARCHAR(32) NOT NULL DEFAULT 'active' - -- active / suspended / completed -- next_review_at DATETIME NULL -- interval_days INT NOT NULL DEFAULT 1 -- ease_factor DECIMAL(4,2) NOT NULL DEFAULT 2.50 -- repetition_count INT NOT NULL DEFAULT 0 -- lapse_count INT NOT NULL DEFAULT 0 -- created_at DATETIME -- updated_at DATETIME -- deleted_at DATETIME NULL -``` - -索引: -```sql -INDEX idx_review_cards_user_id (user_id) -INDEX idx_review_cards_next_review_at (next_review_at) -INDEX idx_review_cards_focus_item_id (focus_item_id) -``` - ---- - -### 21. review_logs 复习记录表 - -```sql -review_logs -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- review_card_id BIGINT UNSIGNED NOT NULL -- session_id BIGINT UNSIGNED NULL -- rating VARCHAR(32) NOT NULL - -- again / hard / good / easy -- response_text TEXT NULL -- reviewed_at DATETIME NOT NULL -- next_review_at DATETIME NULL -- created_at DATETIME -``` - -索引: -```sql -INDEX idx_review_logs_user_id (user_id) -INDEX idx_review_logs_card_id (review_card_id) -INDEX idx_review_logs_reviewed_at (reviewed_at) -``` - ---- - -### 22. review_plans 复习计划表 - -```sql -review_plans -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- title VARCHAR(255) NOT NULL -- status VARCHAR(32) NOT NULL DEFAULT 'active' - -- active / completed / cancelled -- scheduled_at DATETIME NULL -- completed_at DATETIME NULL -- card_count INT NOT NULL DEFAULT 0 -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_review_plans_user_id (user_id) -INDEX idx_review_plans_scheduled_at (scheduled_at) -``` - ---- - -## 九、学习活跃记录表(1 张) - -### 23. daily_learning_activities 每日学习活跃表 - -用于个人中心的蓝色学习活跃图。 - -```sql -daily_learning_activities -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- activity_date DATE NOT NULL -- duration_seconds INT NOT NULL DEFAULT 0 -- sessions_count INT NOT NULL DEFAULT 0 -- active_recall_count INT NOT NULL DEFAULT 0 -- review_count INT NOT NULL DEFAULT 0 -- ai_analysis_count INT NOT NULL DEFAULT 0 -- completed_loop_count INT NOT NULL DEFAULT 0 -- activity_level INT NOT NULL DEFAULT 0 -- 0-4,颜色深浅 -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -UNIQUE KEY uk_user_activity_date (user_id, activity_date) -INDEX idx_daily_activity_user_id (user_id) -``` - ---- - -## 十、通知与反馈表(2 张) - -### 24. notifications 消息通知表 - -```sql -notifications -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- type VARCHAR(32) NOT NULL - -- review_due / ai_analysis_done / learning_suggestion / system -- title VARCHAR(255) NOT NULL -- content TEXT NULL -- data JSON NULL -- read_at DATETIME NULL -- created_at DATETIME -``` - -索引: -```sql -INDEX idx_notifications_user_id (user_id) -INDEX idx_notifications_read_at (read_at) -INDEX idx_notifications_type (type) -``` - ---- - -### 25. feedbacks 用户反馈表 - -```sql -feedbacks -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NULL -- email VARCHAR(255) NULL -- category VARCHAR(64) NOT NULL - -- feature / bug / experience / privacy / other -- content TEXT NOT NULL -- device_info JSON NULL -- status VARCHAR(32) NOT NULL DEFAULT 'open' - -- open / processing / resolved / ignored -- created_at DATETIME -- updated_at DATETIME -``` - -索引: -```sql -INDEX idx_feedbacks_user_id (user_id) -INDEX idx_feedbacks_status (status) -``` - ---- - -## 十一、合规与系统表(2 张) - -### 26. user_consents 用户协议同意记录表 - -```sql -user_consents -- id BIGINT UNSIGNED PK -- user_id BIGINT UNSIGNED NOT NULL -- consent_type VARCHAR(32) NOT NULL - -- privacy_policy / terms_of_service -- version VARCHAR(50) NOT NULL -- accepted_at DATETIME NOT NULL -- ip_address VARCHAR(100) NULL -- user_agent VARCHAR(500) NULL -- created_at DATETIME -``` - -索引: -```sql -INDEX idx_user_consents_user_id (user_id) -INDEX idx_user_consents_type (consent_type) -``` - ---- - -### 27. app_changelogs 更新记录表(可选) - -```sql -app_changelogs -- id BIGINT UNSIGNED PK -- version VARCHAR(50) NOT NULL -- title VARCHAR(255) NOT NULL -- content TEXT NOT NULL -- platform VARCHAR(32) NOT NULL DEFAULT 'ios' -- published_at DATETIME NULL -- created_at DATETIME -- updated_at DATETIME -``` - ---- - -## v0.1 建表优先级 - -### 第一批(24 张,必须) - -```text -users -auth_accounts -refresh_tokens -user_profiles -user_preferences - -knowledge_bases -knowledge_items -tags -knowledge_item_tags -document_imports -uploaded_files - -learning_sessions -learning_records -active_recall_questions -active_recall_answers - -ai_analysis_jobs -ai_analysis_results -focus_items - -review_cards -review_logs - -daily_learning_activities - -notifications -feedbacks -user_consents -``` - -### 第二批(3 张,可稍后) - -```text -knowledge_item_relations -review_plans -app_changelogs -``` - ---- - -## 模块与表对应关系 - -```text -auth → users, auth_accounts, refresh_tokens -users → user_profiles, user_preferences, user_consents -knowledge-base → knowledge_bases -knowledge-items → knowledge_items, knowledge_item_relations, tags, knowledge_item_tags -document-import → uploaded_files, document_imports -learning-session → learning_sessions, learning_records -active-recall → active_recall_questions, active_recall_answers -ai-analysis → ai_analysis_jobs, ai_analysis_results -focus-items → focus_items -review → review_cards, review_logs, review_plans -learning-activity → daily_learning_activities -notifications → notifications -feedback → feedbacks -system → app_changelogs -``` - ---- - -## Prisma 生成规范 - -```text -所有表使用 BIGINT UNSIGNED AUTO_INCREMENT 主键 -状态字段使用 VARCHAR,不使用 ENUM -JSON 字段用于存储 AI 分析结构化结果、用户偏好、元数据 -核心表添加 created_at、updated_at、deleted_at -为 user_id、status、created_at、外键字段添加合理索引 -``` diff --git a/REDIS-DESIGN.md b/REDIS-DESIGN.md deleted file mode 100644 index 149d8cb..0000000 --- a/REDIS-DESIGN.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -source: AI回答.md -updated: 2026-05-09 ---- - -# 知习 Redis 设计 - -> Redis 在知习里不是"另一个 MySQL",它是系统的**加速器和调度器**。MySQL 存结果,Redis 管过程。 - ---- - -## 1. Redis 定位 - -Redis 不作为主数据库,只负责: - -1. 缓存 -2. 限流 -3. 队列(BullMQ) -4. 临时任务状态 -5. 分布式锁 -6. 防重复提交 -7. AI 调用次数统计 -8. 短期 Token / 黑名单 -9. 通知任务调度 -10. 学习会话草稿 - ---- - -## 2. Key 命名规范 - -统一格式: - -```text -业务域:对象类型:对象ID:字段 -``` - -示例: - -```text -cache:user:123:profile -rate:user:123:ai:daily:2026-05-09 -lock:ai-analysis:session:987 -job:ai-analysis:abc123:status -``` - -规则: - -1. 全部小写 -2. 用冒号 `:` 分隔 -3. 从大范围到小范围 -4. userId、jobId、sessionId 明确写在 key 里 -5. 带日期的 key 用 `YYYY-MM-DD` -6. 所有临时 key 必须设置 TTL - ---- - -## 3. Key 总表 - -### 缓存类 - -| Key | 用途 | TTL | -|-----|------|-----| -| `cache:user:{userId}:profile` | 用户资料 | 5-10 分钟 | -| `cache:user:{userId}:preferences` | 用户偏好设置 | 10 分钟 | -| `cache:user:{userId}:knowledge-bases` | 用户知识库列表 | 3-5 分钟 | -| `cache:knowledge-base:{kbId}:summary` | 知识库摘要 | 5 分钟 | -| `cache:review:user:{userId}:due-count` | 到期复习数量 | 1-3 分钟 | - -### 限流类 - -| Key | 用途 | TTL | -|-----|------|-----| -| `rate:user:{userId}:ai:daily:{date}` | 用户每日 AI 调用次数 | 到当天结束或 24h | -| `rate:user:{userId}:feedback:hourly` | 用户每小时反馈次数 | 1 小时 | -| `rate:ip:{ip}:request:{minute}` | IP 每分钟请求频率 | 60-120 秒 | -| `rate:ip:{ip}:login:{date}` | IP 每日登录尝试 | 10-30 分钟 | - -### 分布式锁类 - -| Key | 用途 | TTL | -|-----|------|-----| -| `lock:ai-analysis:session:{sessionId}` | 防止重复提交 AI 分析 | 60-300 秒 | -| `lock:ai-analysis:answer:{answerId}` | 防止同回答重复分析 | 60-300 秒 | -| `lock:document-import:{importId}` | 防止重复处理导入 | 5-30 分钟 | -| `lock:review-plan:user:{userId}:item:{itemId}` | 防止重复生成复习计划 | 60-300 秒 | -| `lock:feedback:ip:{ip}` | 防止 IP 刷反馈 | 60-300 秒 | - -### 任务状态类 - -| Key | Value 示例 | TTL | -|-----|-----------|-----| -| `job:ai-analysis:{jobId}:status` | `pending / processing / completed / failed` | 24h | -| `job:ai-analysis:{jobId}:progress` | `0-100` | 24h | -| `job:ai-analysis:{jobId}:error` | 错误信息字符串 | 24h | -| `job:document-import:{importId}:status` | `pending / parsing / chunking / generating / completed / failed` | 24h | -| `job:document-import:{importId}:progress` | `0-100` | 24h | -| `job:document-import:{importId}:message` | `"正在提取关键知识点"` | 24h | -| `job:document-import:{importId}:error` | 错误信息字符串 | 24h | - -### 会话临时状态类 - -| Key | 用途 | TTL | -|-----|------|-----| -| `session:learning:{sessionId}:heartbeat` | 学习会话心跳 | 30 分钟 | -| `session:learning:{sessionId}:current-step` | 当前学习步骤 | 2 小时 | -| `session:active-recall:{sessionId}:draft` | 回答草稿暂存 | 1-24 小时 | - -### Token / 黑名单 - -| Key | 用途 | TTL | -|-----|------|-----| -| `auth:refresh-token:blacklist:{tokenId}` | 注销后刷新 Token 失效 | 到 token 过期 | -| `auth:access-token:blacklist:{jwtId}` | 注销后 JWT 失效 | 到 token 过期 | - -### Set 类(可选) - -| Key | 用途 | -|-----|------| -| `set:user:{userId}:reviewed-items:{date}` | 当天已复习项去重 | - ---- - -## 4. Redis 数据类型选择 - -| 类型 | 用途 | 示例 | -|------|------|------| -| **String** | 最常用:缓存 JSON、计数器、状态、锁 | `rate:user:123:ai:daily:2026-05-09 = 8` | -| **Hash** | 可选,任务多字段频繁更新的场景 | `job:ai-analysis:1001 → status=processing, progress=40` | -| **List/Stream** | 队列,BullMQ 自动管理,不需要手动操作 | - | -| **Set** | 去重,如当天已复习项集合 | `set:user:123:reviewed-items:2026-05-09` | -| **Sorted Set** | 后期按时间排序的复习调度,v0.1 先不做 | - | - ---- - -## 5. 核心流程中 Redis 与 MySQL 的配合 - -### 5.1 AI 分析流程 - -```text - 1. MySQL 创建 ai_analysis_jobs - 2. Redis 加入 ai-analysis 队列(BullMQ) - 3. Redis 存 job:xxx:status = processing - 4. Worker 调用 AI - 5. MySQL 写 ai_analysis_results - 6. MySQL 写 focus_items - 7. MySQL 写 review_cards - 8. Redis 存 job:xxx:status = completed - 9. MySQL 写 notifications -``` - -### 5.2 资料导入流程 - -```text - 1. MySQL 创建 document_imports - 2. Redis 加入 document-import 队列(BullMQ) - 3. Redis 存导入进度 - 4. Worker 解析文件 - 5. MySQL 写 knowledge_items - 6. MySQL 更新 document_imports 为 success - 7. Redis 存状态 completed -``` - -### 5.3 学习活跃图流程 - -```text - 1. 用户完成学习动作 - 2. MySQL 写 learning_records - 3. MySQL 更新 daily_learning_activities - 4. Redis 可短期缓存今日活跃统计 - 5. App 查询活跃图优先查 MySQL,必要时加缓存 -``` - ---- - -## 6. BullMQ 队列 - -BullMQ 自动管理 Redis key,不需要手动建。建议预留 3 个队列: - -| 队列名 | 任务数据 | 处理逻辑 | -|--------|---------|---------| -| `ai-analysis` | `{ jobId, userId, sessionId, answerId, jobType }` | 读取回答 → 调 AI → 写结果 → 生成待巩固项 → 生成复习卡片 → 发通知 | -| `document-import` | `{ importId, userId, knowledgeBaseId, sourceType }` | 解析文件 → 提取文本 → 分段 → 生成知识点 → 写 knowledge_items → 更新状态 | -| `notification` | `{ userId, type, title, data }` | 写 notifications 表,后续可扩展 APNs 推送 | - ---- - -## 7. 哪些绝对不能只放 Redis - -以下全部必须写 MySQL,Redis 只能做缓存,不是唯一来源: - -```text -用户资料 → users, user_profiles -知识库内容 → knowledge_bases -知识点内容 → knowledge_items -学习记录 → learning_records -主动回忆回答 → active_recall_answers -AI 分析结果 → ai_analysis_results -待巩固项 → focus_items -复习卡片 → review_cards -复习记录 → review_logs -学习活跃记录 → daily_learning_activities -通知记录 → notifications -用户设置 → user_preferences -协议同意记录 → user_consents -``` - ---- - -## 8. v0.1 Redis 最小落地范围 - -### 必须做 - -```text -1. Redis 连接 -2. /health 检查 Redis -3. RedisModule + RedisService(get/set/del/exists/expire/ttl/incr/setNx/lock/unlock) -4. AI 每日调用限流(rate:user:{userId}:ai:daily:{date}) -5. AI 分析队列(BullMQ ai-analysis) -6. AI 分析任务状态(job:ai-analysis:{jobId}:status/progress/error) -7. 防重复提交锁(lock:ai-analysis:session:{sessionId}) -8. document-import 队列预留(BullMQ document-import) -9. notification 队列预留(BullMQ notification) -``` - -### 暂时不做 - -```text -复杂缓存策略 -Sorted Set 复习调度 -复杂分布式任务调度 -全量通知推送(APNs) -复杂排行榜 -``` - ---- - -## 9. RedisService 方法清单 - -```text -get(key) — 读取 -set(key, value) — 写入 -del(key) — 删除 -exists(key) — 判断存在 -expire(key, ttl) — 设置过期 -ttl(key) — 查看剩余时间 -incr(key) — 自增(限流计数) -setNx(key, value) — 不存在才写入(锁) -lock(key, ttl) — 获取分布式锁,返回 token -unlock(key, token) — 释放锁,校验 token,防止误删 -``` - -锁的实现注意: - -- 锁必须设置 TTL -- 解锁时必须校验 value/token,不能误删别人的锁 -- 锁的 value 用随机 token,解锁时比对 - ---- - -## 10. 一句话总结 - -> **Redis 在知习里不是"另一个 MySQL",它是系统的加速器和调度器。MySQL 存结果,Redis 管过程。** diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index bc2e1ca..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,169 +0,0 @@ -# 知习 api-server 安全基线 - -> v0.1 安全设计文档。本后端存储用户资料、知识库、上传文件、主动回忆回答、AI 分析结果和学习记录,第一版必须建立基础安全边界。 - ---- - -## 1. 全局安全中间件 - -| 措施 | 实现 | 文件 | -|------|------|------| -| helmet | `app.use(helmet())` 设置安全 HTTP 头 | `src/main.ts` | -| CORS | 仅允许配置域名。生产环境仅允许 `longde.cloud` | `src/main.ts` | -| body size limit | JSON 请求体最大 10MB | `src/main.ts` | -| 异常过滤 | 生产环境不返回 stack trace | `src/common/filters/global-exception.filter.ts` | - ---- - -## 2. 认证与 Token - -### JWT - -- `accessToken`: JWT,1 小时过期 -- `refreshToken`: 128 位随机 hex,入库只存 SHA-256 hash -- logout 时 `revokedAt = now()` 撤销所有 refresh token -- `/users/me` 及其所有子路由强制 `@UseGuards(JwtAuthGuard)` - -``` -POST /auth/apple → 返回 accessToken + refreshToken -POST /auth/refresh → 消耗旧 refreshToken,发放新 token pair(rotation) -POST /auth/logout → 撤销该用户所有 refresh token -``` - -### 存储安全 - -``` -refresh_tokens.tokenHash = SHA-256(实际 token) -数据库中永远不存明文 refreshToken -``` - ---- - -## 3. 权限与越权防护 - -### 资源归属校验 - -所有用户资源操作必须校验 `userId` 归属: - -```ts -// src/common/utils/security.util.ts -export async function findByIdAndUserId(delegate, id, userId, resourceName) -export function ensureOwnership(record, userId, resourceName) -``` - -### 需校验的资源 - -| 资源 | 校验字段 | -|------|---------| -| KnowledgeBase | `userId` | -| KnowledgeItem | `userId` | -| LearningSession | `userId` | -| ActiveRecallAnswer | `userId` | -| AiAnalysisJob | `userId` | -| AiAnalysisResult | `userId` | -| FocusItem | `userId` | -| ReviewCard | `userId` | -| ReviewLog | `userId` | -| DocumentImport | `userId` | - ---- - -## 4. 参数校验 - -- 全局 `StrictValidationPipe`: - - `whitelist: true` — 自动剥离未声明字段 - - `forbidNonWhitelisted: true` — 未知字段返回 400 - - 字符串字段最大长度 5000 字符 -- 分页 DTO: page≥1, limit 1-100 - ---- - -## 5. 限流(Redis) - -| 场景 | Key | 限制 | -|------|-----|------| -| 登录 | `rate:ip:{ip}:login:{date}` | 20次/IP/天 | -| 反馈 | `rate:ip:{ip}:feedback:hourly` | 5次/IP/时 | -| AI 分析 | `rate:user:{userId}:ai:daily:{date}` | 50次/用户/天 | -| 文件上传 | `rate:user:{userId}:upload:hourly` | 10次/用户/时 | - -实现: `src/common/utils/rate-limit.service.ts` - ---- - -## 6. 文件上传安全 - -| 措施 | 说明 | -|------|------| -| 类型白名单 | PDF, Word, Excel, 纯文本, Markdown, CSV, PNG, JPEG, WebP | -| 大小限制 | 最大 20MB | -| 随机文件名 | `sanitizeFilename()` 生成随机 key,不信任用户原始文件名 | -| 默认私有 | 所有文件默认私有访问 | -| 路径隔离 | `users/{userId}/...` | - ---- - -## 7. Redis 安全使用 - -- 不存核心业务结果(用户资料/知识点/AI分析结果等必须在 MySQL) -- 队列任务只存 `jobId`/`userId` 等引用 ID -- 所有临时 key 必须设置 TTL -- 防重复提交锁必须有 TTL,解锁校验 token -- 不在 Redis 中存 token 明文 - ---- - -## 8. COS 安全使用 - -- Bucket 默认私有读写 -- 后端不向前端暴露 SecretId/SecretKey -- 下载私有文件通过签名 URL -- 上传路径按 `users/{userId}/{randomKey}` 组织 -- 预留临时上传 URL(STS)机制 - ---- - -## 9. Swagger 安全 - -- 开发环境默认开启 -- 生产环境默认关闭 -- 生产环境如需开启,必须配置 Basic Auth(`SWAGGER_USER`/`SWAGGER_PASSWORD`) -- 生产环境手动设置 `ENABLE_SWAGGER=true` - ---- - -## 10. 数据库安全 - -- 不使用 root 连接业务 -- 业务账号 `zhixi_user` 仅需 SELECT/INSERT/UPDATE/DELETE -- 迁移账号和业务账号分离(`prisma db push` 与运行时连接帐号可不同) -- 数据库自动备份建议: `mysqldump zhixi | gzip > backup-$(date +%Y%m%d).sql.gz` - -### 日志中禁止打印 - -``` -DATABASE_URL(含密码) -JWT_SECRET -AI_API_KEY -COS SecretKey -用户完整 refreshToken -用户上传文件的完整内容 -Authorization header -``` - ---- - -## 11. 安全检查清单 - -- [x] helmet 已启用 -- [x] CORS 仅允许白名单域名 -- [x] JWT + refresh token rotation + hash 存储 -- [x] logout 撤销 refresh token -- [x] 所有用户数据接口需要认证 -- [x] 资源所有权校验工具已就绪 -- [x] StrictValidationPipe 全局启用(whitelist + forbidNonWhitelisted) -- [x] Redis 限流已实现 -- [x] 文件类型/大小白名单 -- [x] 全局异常过滤器生产环境不暴露 stack trace -- [x] Swagger 生产环境默认关闭 -- [x] 敏感信息不在日志中打印原则已确立 diff --git a/docs/AI回答.md b/docs/AI回答.md new file mode 100644 index 0000000..81fcfc6 --- /dev/null +++ b/docs/AI回答.md @@ -0,0 +1,885 @@ +([Files][1])([Files][2])([Files][3])([Files][4])([Files][5]) + +可以。下面我把 **知习后端 Redis 设计** 单独整理一版。 + +你可以把它理解成: + +```text +MySQL:长期真实数据,必须可靠保存 +Redis:短期状态、缓存、队列、限流、锁、任务进度 +``` + +Redis **不需要建表**,需要设计的是: + +```text +1. Redis 用在哪些场景 +2. Key 怎么命名 +3. Value 存什么 +4. 过期时间多久 +5. 哪些数据绝对不能只放 Redis +``` + +--- + +# 一、Redis 在知习里的定位 + +Redis 不作为主数据库。 + +它主要负责: + +```text +1. 缓存 +2. 限流 +3. 队列 +4. 临时任务状态 +5. 分布式锁 +6. 防重复提交 +7. AI 调用次数统计 +8. 短期 token / 黑名单 +9. 通知任务调度 +``` + +核心业务数据仍然必须写入 MySQL: + +```text +用户 +知识库 +知识点 +学习记录 +主动回忆回答 +AI 分析结果 +待巩固项 +复习计划 +学习活跃记录 +通知记录 +用户设置 +``` + +--- + +# 二、Redis Key 命名规范 + +建议统一用这种格式: + +```text +业务域:对象类型:对象ID:字段 +``` + +例如: + +```text +cache:user:123:profile +rate:user:123:ai:daily:2026-05-09 +lock:ai-analysis:session:987 +job:ai-analysis:abc123:status +``` + +统一规则: + +```text +1. 全部小写 +2. 用冒号 : 分隔 +3. 从大范围到小范围 +4. userId、jobId、sessionId 明确写在 key 里 +5. 带日期的 key 用 YYYY-MM-DD +6. 所有临时 key 必须设置 TTL +``` + +--- + +# 三、Redis 主要使用场景 + +## 1. 缓存 Cache + +用于缓存高频读取的数据,减少 MySQL 压力。 + +### 用户资料缓存 + +```text +key: +cache:user:{userId}:profile + +value: +{ + "id": 123, + "nickname": "李明", + "avatarUrl": null, + "learningIdentity": "系统学习者", + "learningDirection": "认知科学" +} + +ttl: +5-10 分钟 +``` + +### 用户知识库列表缓存 + +```text +key: +cache:user:{userId}:knowledge-bases + +value: +[ + { + "id": 1, + "title": "认知心理学", + "itemCount": 42 + } +] + +ttl: +3-5 分钟 +``` + +### 当前用户设置缓存 + +```text +key: +cache:user:{userId}:preferences + +ttl: +10 分钟 +``` + +注意: + +```text +缓存可以丢 +MySQL 不能丢 +缓存更新不及时也没关系,但关键业务查询必须以 MySQL 为准 +``` + +--- + +## 2. 限流 Rate Limit + +用于控制请求频率和 AI 成本。 + +### 用户每日 AI 调用次数 + +```text +key: +rate:user:{userId}:ai:daily:{date} + +example: +rate:user:123:ai:daily:2026-05-09 + +value: +8 + +ttl: +到当天结束,或者 24 小时 +``` + +用途: + +```text +限制每天 AI 分析次数 +限制生成回忆测试次数 +限制找薄弱知识点次数 +``` + +--- + +### IP 请求频率限制 + +```text +key: +rate:ip:{ip}:request:{minute} + +example: +rate:ip:1.2.3.4:request:2026-05-09T10:35 + +value: +42 + +ttl: +60-120 秒 +``` + +用途: + +```text +防刷接口 +防反馈表单乱提交 +防登录接口暴力请求 +``` + +--- + +### 登录尝试次数 + +```text +key: +rate:login:{ip}:{date} + +ttl: +10-30 分钟 +``` + +Apple 登录一般问题不大,但后面如果有邮箱登录、验证码登录,这个会用到。 + +--- + +## 3. 分布式锁 Lock + +用于防止重复提交。 + +### 防止重复 AI 分析 + +```text +key: +lock:ai-analysis:session:{sessionId} + +example: +lock:ai-analysis:session:987 + +value: +randomToken + +ttl: +60-300 秒 +``` + +场景: + +```text +用户连续点两次“提交 AI 分析” +后端只允许创建一个分析任务 +``` + +--- + +### 防止重复导入资料 + +```text +key: +lock:document-import:{importId} + +ttl: +5-30 分钟 +``` + +--- + +### 防止重复生成复习计划 + +```text +key: +lock:review-plan:user:{userId}:item:{itemId} + +ttl: +60-300 秒 +``` + +注意: + +```text +锁一定要设置 TTL +解锁时要校验 value,不能误删别人的锁 +``` + +--- + +## 4. AI 分析任务状态 + +AI 分析建议用异步任务。 + +流程: + +```text +App 提交回答 +→ 后端创建 ai_analysis_jobs 记录 +→ 加入 Redis 队列 +→ 返回 jobId +→ Worker 调用 AI +→ 结果写入 MySQL +→ Redis 状态改为 completed +``` + +### 任务状态 key + +```text +key: +job:ai-analysis:{jobId}:status + +value: +pending / processing / completed / failed + +ttl: +24 小时 +``` + +### 任务进度 key + +```text +key: +job:ai-analysis:{jobId}:progress + +value: +0-100 + +ttl: +24 小时 +``` + +### 任务错误信息 + +```text +key: +job:ai-analysis:{jobId}:error + +value: +"AI provider timeout" + +ttl: +24 小时 +``` + +注意: + +```text +Redis 只存临时状态 +最终任务记录和分析结果必须写入 MySQL: +ai_analysis_jobs +ai_analysis_results +focus_items +review_cards +``` + +--- + +## 5. 资料导入任务状态 + +导入资料也建议异步。 + +场景: + +```text +上传 PDF +粘贴长文本 +导入链接 +AI 解析生成知识点 +``` + +### 导入任务状态 + +```text +key: +job:document-import:{importId}:status + +value: +pending / parsing / chunking / generating / completed / failed + +ttl: +24 小时 +``` + +### 导入进度 + +```text +key: +job:document-import:{importId}:progress + +value: +0-100 + +ttl: +24 小时 +``` + +### 导入处理中提示 + +```text +key: +job:document-import:{importId}:message + +value: +"正在提取关键知识点" + +ttl: +24 小时 +``` + +最终结果写入 MySQL: + +```text +document_imports +uploaded_files +knowledge_items +knowledge_item_relations +tags +``` + +--- + +## 6. BullMQ 队列 + +如果后端是 Node.js / NestJS,建议用 BullMQ。 + +队列由 BullMQ 自动管理 Redis key,不需要你自己建。 + +建议预留 3 个队列: + +```text +ai-analysis +document-import +notification +``` + +--- + +### ai-analysis 队列 + +任务数据: + +```json +{ + "jobId": 123, + "userId": 456, + "sessionId": 789, + "answerId": 1001, + "jobType": "active_recall_analysis" +} +``` + +处理逻辑: + +```text +读取用户回答 +调用 AI +生成分析结果 +写入 ai_analysis_results +生成 focus_items +生成 review_cards +发送通知 +``` + +--- + +### document-import 队列 + +任务数据: + +```json +{ + "importId": 123, + "userId": 456, + "knowledgeBaseId": 789, + "sourceType": "file" +} +``` + +处理逻辑: + +```text +解析文件 +提取文本 +分段 +生成知识点 +写入 knowledge_items +更新 document_imports 状态 +``` + +--- + +### notification 队列 + +任务数据: + +```json +{ + "userId": 456, + "type": "review_due", + "title": "8 张卡片今日到期复习", + "data": { + "reviewCount": 8 + } +} +``` + +处理逻辑: + +```text +写入 notifications 表 +后面可扩展推送 APNs +``` + +--- + +# 四、Redis Key 总表 + +## 缓存类 + +```text +cache:user:{userId}:profile +cache:user:{userId}:preferences +cache:user:{userId}:knowledge-bases +cache:knowledge-base:{knowledgeBaseId}:summary +cache:review:user:{userId}:due-count +``` + +--- + +## 限流类 + +```text +rate:user:{userId}:ai:daily:{date} +rate:user:{userId}:feedback:hourly +rate:ip:{ip}:request:{minute} +rate:ip:{ip}:login:{date} +``` + +--- + +## 锁类 + +```text +lock:ai-analysis:session:{sessionId} +lock:ai-analysis:answer:{answerId} +lock:document-import:{importId} +lock:review-plan:user:{userId}:item:{itemId} +lock:feedback:ip:{ip} +``` + +--- + +## 任务状态类 + +```text +job:ai-analysis:{jobId}:status +job:ai-analysis:{jobId}:progress +job:ai-analysis:{jobId}:error + +job:document-import:{importId}:status +job:document-import:{importId}:progress +job:document-import:{importId}:message +job:document-import:{importId}:error +``` + +--- + +## 会话临时状态 + +```text +session:learning:{sessionId}:heartbeat +session:learning:{sessionId}:current-step +session:active-recall:{sessionId}:draft +``` + +例如用户正在写回答,可以短期保存草稿: + +```text +key: +session:active-recall:{sessionId}:draft + +ttl: +1-24 小时 +``` + +最终提交后还是写 MySQL。 + +--- + +## Token / 黑名单 + +```text +auth:refresh-token:blacklist:{tokenId} +auth:access-token:blacklist:{jwtId} +``` + +退出登录或注销账号时可用。 + +--- + +# 五、TTL 建议 + +```text +用户资料缓存:5-10 分钟 +知识库列表缓存:3-5 分钟 +AI 每日限流:到当天结束或 24 小时 +IP 请求限流:60-120 秒 +登录尝试限流:10-30 分钟 +AI 分析任务状态:24 小时 +资料导入任务状态:24 小时 +分布式锁:60 秒到 30 分钟,按任务类型决定 +学习草稿:1-24 小时 +Token 黑名单:到 token 原本过期时间 +``` + +--- + +# 六、Redis 数据类型建议 + +## String + +最常用。 + +用于: + +```text +缓存 JSON +计数器 +状态 +锁 +``` + +示例: + +```text +rate:user:123:ai:daily:2026-05-09 = 8 +job:ai-analysis:1001:status = processing +``` + +--- + +## Hash + +可选,用于对象字段更新频繁的场景。 + +例如: + +```text +job:ai-analysis:1001 + status = processing + progress = 40 + message = 正在分析薄弱点 +``` + +v0.1 也可以先用 String 多 key,简单直接。 + +--- + +## List / Stream + +队列相关,但如果使用 BullMQ,不需要自己操作。 + +--- + +## Set + +可选。 + +比如记录某天处理过的学习项: + +```text +set:user:{userId}:reviewed-items:{date} +``` + +--- + +## Sorted Set + +后期可用于按时间排序的任务。 + +例如: + +```text +zset:review:due +``` + +但 v0.1 可以先不做,复习到期直接查 MySQL。 + +--- + +# 七、哪些不要放 Redis + +不要把这些只放 Redis: + +```text +用户资料 +知识库内容 +知识点内容 +学习记录 +主动回忆回答 +AI 分析结果 +待巩固项 +复习卡片 +复习记录 +学习活跃记录 +通知记录 +用户设置 +协议同意记录 +``` + +这些全部要写 MySQL。 + +Redis 可以缓存它们,但不是唯一来源。 + +--- + +# 八、Redis 和 MySQL 的典型组合流程 + +## AI 分析流程 + +```text +1. MySQL 创建 ai_analysis_jobs +2. Redis 加入 ai-analysis 队列 +3. Redis 存 job 状态 processing +4. Worker 调用 AI +5. MySQL 写 ai_analysis_results +6. MySQL 写 focus_items +7. MySQL 写 review_cards +8. Redis 存 job 状态 completed +9. MySQL 写 notifications +``` + +--- + +## 资料导入流程 + +```text +1. MySQL 创建 document_imports +2. Redis 加入 document-import 队列 +3. Redis 存导入进度 +4. Worker 解析文件 +5. MySQL 写 knowledge_items +6. MySQL 更新 document_imports 为 success +7. Redis 状态 completed +``` + +--- + +## 学习活跃图流程 + +```text +1. 用户完成学习动作 +2. MySQL 写 learning_records +3. MySQL 更新 daily_learning_activities +4. Redis 可短期缓存今日活跃统计 +5. App 查询活跃图时优先查 MySQL,必要时加缓存 +``` + +--- + +# 九、v0.1 Redis 最小落地范围 + +第一版不用把所有 Redis 场景都做完。 + +建议先做: + +```text +1. Redis 连接 +2. /health 检查 Redis +3. RedisService +4. AI 每日调用限流 +5. AI 分析队列 +6. AI 分析任务状态 +7. 防重复提交锁 +8. document-import 队列预留 +9. notification 队列预留 +``` + +暂时不做: + +```text +复杂缓存策略 +Sorted Set 复习调度 +复杂分布式任务调度 +全量通知推送 +复杂排行榜 +``` + +--- + +# 十、给 Trae 的提示词 + +```text +请为「知习」api-server 设计并接入 Redis。 + +注意: +Redis 不需要像 MySQL 一样建表。 +Redis 只用于缓存、限流、队列、临时状态、分布式锁、防重复提交和任务进度。 +核心业务数据必须写入 MySQL,不能只存在 Redis。 + +请完成以下内容: + +1. 基础接入 +- docker-compose 增加 redis:7-alpine +- 增加 RedisModule +- 增加 RedisService +- 支持 REDIS_HOST、REDIS_PORT、REDIS_PASSWORD、REDIS_DB、REDIS_URL +- /health 检查 Redis 是否可用 + +2. RedisService 方法 +- get +- set +- del +- exists +- expire +- ttl +- incr +- setNx +- lock +- unlock + +3. Key 命名规范 +请创建文档 docs/redis-key-design.md,包含以下 key 规范: + +缓存: +cache:user:{userId}:profile +cache:user:{userId}:preferences +cache:user:{userId}:knowledge-bases + +限流: +rate:user:{userId}:ai:daily:{date} +rate:ip:{ip}:request:{minute} +rate:user:{userId}:feedback:hourly + +锁: +lock:ai-analysis:session:{sessionId} +lock:ai-analysis:answer:{answerId} +lock:document-import:{importId} +lock:review-plan:user:{userId}:item:{itemId} + +任务状态: +job:ai-analysis:{jobId}:status +job:ai-analysis:{jobId}:progress +job:ai-analysis:{jobId}:error +job:document-import:{importId}:status +job:document-import:{importId}:progress +job:document-import:{importId}:message +job:document-import:{importId}:error + +4. BullMQ 队列 +请预留以下队列: +- ai-analysis +- document-import +- notification + +5. AI 分析任务 +请实现基础队列结构: +- 创建 AI 分析任务时写入 MySQL ai_analysis_jobs +- 添加任务到 Redis BullMQ 队列 +- Redis 记录任务 status/progress +- Worker 处理完成后更新 MySQL +- Redis 更新状态为 completed + +6. 限流 +请实现基础 AI 调用限流: +rate:user:{userId}:ai:daily:{date} +用于限制用户每日 AI 分析调用次数。 + +7. 分布式锁 +请实现 lock/unlock 工具,防止重复提交 AI 分析任务。 +锁必须有 TTL。 +解锁时要校验 token,不能误删其他请求的锁。 + +8. 注意事项 +- 不要把用户、知识库、学习记录、AI 分析结果、待巩固项、复习计划只存 Redis +- Redis 中所有临时状态必须设置 TTL +- BullMQ 自动创建的 Redis key 不需要手动管理 +- 代码要模块化,方便后续扩展 +``` + +--- + +一句话总结: + +**Redis 在知习里不是“另一个 MySQL”,它是系统的加速器和调度器。MySQL 存结果,Redis 管过程。** + +[1]: file://my_files/file_00000000e760722fbb391fe031a23b24 "personal_developer_startup_plan.md" +[2]: file://my_files/file_00000000cbe0722fb8f20caa41630738 "Pasted text.txt" +[3]: file://my_files/file_0000000013c071fdbc2b510f32da8546 "Pasted text.txt" +[4]: file://my_files/file_00000000ffd071fd9492b93fd9ebf5ba "Pasted text.txt" +[5]: file://my_files/file_0000000061e471f590475885fd76860c "REAL_MIGRATION_STATUS.md"