Files
tupingr e3f4af9c0c docs(arch): 旧架构合并 — 30项决策落地,5份文档升级至v0.4.0
- 总体架构:新增打印/图像预处理/双飞轮/三环境部署
- 技术选型:调整决策理由(Coze沙盒自动化测试),新增Sharp+PDFKit
- 数据模型:新增code/role/question_type+print_tasks+audit_logs,ID+code并存
- 模块设计:新增Image/Print模块,推荐两阶段匹配(关键词粗筛→AI精排)
- PRD:目标用户扩展为学生+家长,新增PDF打印,年级聚焦小初,图像预处理流程
- ADR-010:题库抽象层Adapter Pattern

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 12:00:52 +08:00

404 lines
14 KiB
Markdown
Raw Permalink 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.
# 模块设计
> 版本: v0.4.0 | 作者: Arch AI | 基于 PRD v0.4.0 + 旧架构合并
---
## 1. 模块总览
```
ErrLens
├── P01_errlens_app (小程序 + 后端)
│ ├── 小程序端 (Taro + React)
│ │ ├── pages/auth # 登录/注册
│ │ ├── pages/home # 首页(错题概览)
│ │ ├── pages/capture # 拍照录入
│ │ ├── pages/error-detail # 错题详情+分析
│ │ ├── pages/error-list # 错题列表
│ │ ├── pages/weak-points # 薄弱点分析
│ │ ├── pages/practice # 练习推荐 (P1)
│ │ ├── pages/print # PDF 输出 (P0)
│ │ └── pages/profile # 个人中心
│ │
│ └── 后端 (NestJS)
│ ├── modules/auth # 鉴权模块
│ ├── modules/user # 用户模块(含邀请链)
│ ├── modules/invitation # 邀请模块
│ ├── modules/error-item # 错题模块
│ ├── modules/ai # AI 分析模块
│ ├── modules/image # 图像预处理模块
│ ├── modules/subject # 学科模块
│ ├── modules/question-bank # 题库模块
│ ├── modules/recommend # 推荐模块 (P1)
│ ├── modules/print # 打印/PDF 输出模块 (P0)
│ └── modules/upload # 文件上传
├── P02_errlens_training (Phase 3)
│ └── AI 模型训练管线
└── P03_errlens_web (Phase 3)
└── Web 管理后台
```
## 2. 小程序页面路由
| 路由 | 页面 | 说明 | MVP |
|------|------|------|-----|
| `/pages/index/index` | 首页 | 错题统计概览 + 快捷入口 | ✅ |
| `/pages/auth/login` | 登录 | 微信授权登录 | ✅ |
| `/pages/capture/index` | 拍照录入 | 拍照 → AI 识别 → 确认 | ✅ |
| `/pages/error-list/index` | 错题列表 | 筛选 + 搜索 | ✅ |
| `/pages/error-detail/index` | 错题详情 | 题目 + AI 分析 | ✅ |
| `/pages/weak-points/index` | 薄弱点 | 知识点薄弱项汇总 | ✅ |
| `/pages/practice/index` | 练习推荐 | 智能组题 | P1 |
| `/pages/practice/result` | 练习结果 | 对错反馈 | P1 |
| `/pages/print/index` | 错题选择 | 选题→生成 PDF | ✅ |
| `/pages/print/preview` | 打印预览 | PDF 预览+下载 | ✅ |
| `/pages/profile/index` | 个人中心 | 资料 + 设置 | ✅ |
## 3. 后端模块设计
### 3.1 Auth 模块
```
modules/auth/
├── auth.module.ts
├── auth.controller.ts # POST /auth/login (微信 code → JWT)
├── auth.service.ts # 微信 code2session + JWT 签发
├── auth.guard.ts # JWT 鉴权守卫
└── dto/
└── login.dto.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /auth/login | 微信 code 换取 JWT token |
| POST | /auth/refresh | 刷新 token |
### 3.2 User 模块
```
modules/user/
├── user.module.ts
├── user.controller.ts # GET/PATCH /user/profile
├── user.service.ts
├── user.entity.ts # Drizzle schema
└── dto/
└── update-profile.dto.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /user/profile | 获取个人信息 |
| PATCH | /user/profile | 更新年级、学科 |
| GET | /user/invitation-code | 获取个人邀请码和二维码 |
| GET | /user/tree | 获取邀请树(直接下级列表) |
### 3.3 Invitation 模块
```
modules/invitation/
├── invitation.module.ts
├── invitation.controller.ts # POST /invitation/register
├── invitation.service.ts # 邀请码生成 + 邀请链管理
├── user-relation.entity.ts # Drizzle schema
└── dto/
├── register-by-invite.dto.ts
└── tree-query.dto.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /invitation/register | 通过邀请码注册(携带 inviter_code |
| GET | /invitation/tree | 获取当前用户的邀请树(一级+递归) |
| GET | /invitation/tree/:userId | 获取指定用户的邀请统计(子节点数、活跃用户数) |
**邀请码生成规则**:
- 用户注册时自动生成 6 位字母数字邀请码
- 格式: `[A-Z0-9]{6}`,排除易混淆字符 (0/O, 1/I/L)
- 唯一约束,冲突时重试生成
**注册流程**:
```
1. 老用户 A 分享小程序 → 携带邀请码参数 (pages/auth/login?invite=ABC123)
2. 新用户 B 打开 → 微信授权登录
3. 后端创建 B 用户 → 生成 B 的邀请码
4. 创建 user_relation (inviter=A, invitee=B)
5. B 进入首页 → 关系建立完成
```
### 3.4 ErrorItem 模块(核心)
```
modules/error-item/
├── error-item.module.ts
├── error-item.controller.ts # CRUD /error-items
├── error-item.service.ts # 错题业务逻辑 + 校验状态管理
├── error-item.entity.ts # Drizzle schema
├── correction-log.service.ts # 修正记录管理
└── dto/
├── create-error.dto.ts
├── update-error.dto.ts
├── query-error.dto.ts # 筛选参数(含 verification_status
└── batch-confirm.dto.ts # 批量确认
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /error-items | 创建错题(AI 识别结果,状态=raw) |
| GET | /error-items | 列表查询(分页+筛选,含 verification_status 筛选) |
| GET | /error-items/:id | 错题详情(含 AI 分析 + 置信度) |
| PATCH | /error-items/:id | 修正错题信息(字段修正时记录 CorrectionLog |
| POST | /error-items/batch-confirm | 批量确认(raw → reviewed |
| DELETE | /error-items/:id | 删除错题 |
**校验状态机**:
```
raw → (用户查看+确认) → reviewed → (用户修正字段) → corrected
stale (30天未确认,系统标记,可恢复为 raw)
```
**AnalysisReport 数据过滤**: 查询时加 `WHERE verification_status != 'raw'`,确保分析只使用已确认数据。
### 3.5 AI 模块
```
modules/ai/
├── ai.module.ts
├── ai.controller.ts # POST /ai/analyze
├── ai.service.ts # Coze SDK 调用封装
├── strategies/
│ ├── ocr.strategy.ts # OCR 识别策略
│ ├── classify.strategy.ts # 学科/知识点分类策略
│ └── diagnose.strategy.ts # 错误原因诊断策略
└── dto/
├── analyze-request.dto.ts
└── analyze-response.dto.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /ai/analyze | 分析错题图片 → 返回结构化结果 |
| GET | /ai/report | 获取薄弱点分析报告 |
**AI 分析流程**:
```
图片 URL → OCR 文字提取 ──→ question_text (confidence: 0.5-0.95)
├─ 学科分类 ──────────→ subject_id (confidence: 0.7-0.95)
├─ 知识点标注 ────────→ knowledge_points[] (confidence 各 0.5-0.9)
├─ 题目结构提取 ──────→ wrong_answer/correct_answer (confidence 各 0.5-0.9)
└─ 错误原因诊断 ──────→ error_type + diagnosis (confidence: 0.5-0.9)
→ 每个字段附带 confidence 分数
→ 低置信(<0.7)字段标记 requires_review=true,前端红色高亮
→ 汇总返回 { result, confidences, requires_review_fields[] }
```
### 3.6 Image 模块(图像预处理)
```
modules/image/
├── image.module.ts
├── image.service.ts # 图像预处理编排
├── pipelines/
│ ├── perspective.service.ts # 透视校正(手动框 4 角)
│ ├── enhance.service.ts # CLAHE + Gamma + 对比度增强
│ └── pen-removal.service.ts # 笔迹去除(红/蓝 HSV 自动,黑笔手动圈选)
├── sharp.config.ts # Sharp 图像处理参数配置
└── dto/
└── preprocess.dto.ts
```
**处理管线**:
```
原始图片 → 透视校正 → CLAHE 增强 → 笔迹去除 → 输出增强图片 URL
↓ ↓ ↓ ↓
原图保留 手动框角 光照归一化 红/蓝自动去除
黑笔可选手动圈选
```
**降级策略**: 任何模块失败不阻塞整体流程。校正失败 → 用原图;增强失败 → 跳过增强;笔迹去除失败 → 保留原图。始终保证图片能进入 AI 识别。
**Spike 验证结论**(来自旧架构,Coze 沙盒中重新调优):
- 自动透视校正不可用(整页裁成碎片),以手动框 4 角为主方案
- CLAHE 增强 10/10 达到清晰度标准
- 红笔批改可靠去除、蓝笔可用、黑笔无法自动去除(需用户圈选)
### 3.8 Subject 模块
```
modules/subject/
├── subject.module.ts
├── subject.controller.ts # GET /subjects
├── subject.service.ts
└── subject.entity.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /subjects | 获取学科列表 |
| GET | /subjects/:id/knowledge-points | 获取学科下知识点树 |
### 3.7 Print 模块(PDF 输出)[P0]
```
modules/print/
├── print.module.ts
├── print.controller.ts # POST /print/generate, GET /print/download/:id
├── print.service.ts # PDF 生成 + S3 存储 + 过期清理
├── pdf-layout.service.ts # PDFKit A4/300DPI 排版
└── dto/
├── generate-print.dto.ts
└── print-task.dto.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /print/generate | 提交错题 ID 列表,生成 PDF 任务 |
| GET | /print/task/:id | 查询生成进度 |
| GET | /print/download/:id | 下载 PDF 文件(24h 有效) |
**排版优先级**: 题库匹配的结构化内容 > 经图像预处理的增强图片 > 原始图片
**清理策略**: 定时任务每天清理 expires_at < NOW() 的临时文件。
### 3.9 Upload 模块
```
modules/upload/
├── upload.module.ts
├── upload.controller.ts # POST /upload/image
├── upload.service.ts # S3 上传 + 缩略图
└── upload.config.ts # S3/MinIO 配置
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /upload/image | 上传图片 → 返回 URL |
### 3.10 Recommend 模块 (P1)
```
modules/recommend/
├── recommend.module.ts
├── recommend.controller.ts # GET /recommend
├── recommend.service.ts # 推荐编排
└── strategies/
├── coarse-recall.strategy.ts # 粗筛:关键词搜索 + Jaccard 相似度(本地,免费)
├── ai-rerank.strategy.ts # 精排:AI 语义匹配(候选集不足时启用,付费)
├── weak-point.strategy.ts # 薄弱点权重排序
└── similar-difficulty.strategy.ts # 难度匹配
```
**两阶段推荐策略**:
1. **粗筛**(关键词 + Jaccard 相似度)→ 快速召回候选集,零成本、低延迟
2. **精排**(AI 语义匹配)→ 候选集为空或不满足阈值时启用,语义理解泛化
3. 排序: 薄弱点权重 > 难度匹配度 > 去重(已做过的不推)
### 3.11 QuestionBank 模块(题库抽象层)
```
modules/question-bank/
├── question-bank.module.ts
├── question-bank.controller.ts # CRUD /questions
├── question-bank.service.ts # 多源题库路由
├── adapters/
│ ├── base-adapter.ts # 题库适配器接口
│ ├── self-built.adapter.ts # 自有题库适配器
│ ├── zuoyebang.adapter.ts # 作业帮 API 适配器
│ └── adapter.factory.ts # 按 source 路由到对应适配器
├── pdf-import/
│ ├── pdf-parser.service.ts # PDF → 文本
│ ├── ai-extractor.service.ts # AI 结构化提取题目
│ └── import-review.service.ts # 人工审核流程
└── dto/
├── create-question.dto.ts
├── query-question.dto.ts
└── pdf-import.dto.ts
```
**API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /questions | 题目列表查询(分页+筛选) |
| GET | /questions/:id | 题目详情 |
| POST | /questions | 手动创建题目(自有题库录入) |
| POST | /questions/search | 跨源搜索(自有 + 作业帮,结果合并) |
| POST | /questions/pdf-import | 上传 PDF 启动导入任务 |
| GET | /questions/pdf-import/:taskId | 查询 PDF 导入进度 |
**适配器接口**:
```typescript
interface QuestionBankAdapter {
source: string;
search(params: SearchParams): Promise<Question[]>;
getById(id: string): Promise<Question>;
healthCheck(): Promise<boolean>;
}
```
**题库路由策略**: 请求时并行查询自有题库 + 作业帮 API,合并去重后返回。自有题库优先排序。
## 4. 前端状态管理 (Zustand)
```
stores/
├── auth.store.ts # 登录态、token、用户信息
├── error-item.store.ts # 错题列表、筛选条件、分页
├── capture.store.ts # 拍照流程状态机
└── ai-analysis.store.ts # AI 分析结果缓存
```
**capture 状态机**:
```
IDLE → CAMERA → PREVIEW → UPLOADING → ANALYZING → REVIEW → SAVING → DONE
↓ ↓ ↓
ERROR ERROR ERROR
```
## 5. MVP 开发顺序
```
Phase 2a (Week 1-2): 基础设施
- 数据库 Schema + 迁移
- Auth 模块(微信登录)
- User 模块
- Image 模块(图像预处理管线)
Phase 2b (Week 3-4): 核心闭环
- Upload 模块
- AI 模块(Coze SDK 集成)
- ErrorItem CRUD
- 拍照录入页 + 错题列表页
Phase 2c (Week 5-6): 分析+打印+打磨
- 错题详情 + AI 分析展示
- 薄弱点汇总
- Print 模块(PDF 输出)
- Subject 模块 + 筛选
- 交互打磨、异常处理
```
---
*关联: 总体架构.md → 技术选型.md → 数据模型.md*