1186 lines
26 KiB
Markdown
1186 lines
26 KiB
Markdown
---
|
||
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
|
||
```
|
||
|
||
这样就够开始开发。
|
||
|
||
|