e3f4af9c0c
- 总体架构:新增打印/图像预处理/双飞轮/三环境部署 - 技术选型:调整决策理由(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>
14 KiB
14 KiB
模块设计
版本: 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 # 难度匹配
两阶段推荐策略:
- 粗筛(关键词 + Jaccard 相似度)→ 快速召回候选集,零成本、低延迟
- 精排(AI 语义匹配)→ 候选集为空或不满足阈值时启用,语义理解泛化
- 排序: 薄弱点权重 > 难度匹配度 > 去重(已做过的不推)
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 导入进度 |
适配器接口:
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