Files
aurak/docs/debugging-checklist.md

531 lines
17 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.
# AuraK 系统调试检查清单
> **版本**: 2.0
> **更新日期**: 2026-05-14
> **文档状态**: ✅ 已完成全面验证
---
## 目录
1. [数据库问题](#一数据库问题)
2. [API 前后端一致性](#二api-前后端一致性)
3. [题库模块检查点](#三题库模块检查点)
4. [评估流程检查点](#四评估流程检查点)
5. [模型配置检查点](#五模型配置检查点)
6. [角色与用户故事验证](#六角色与用户故事验证)
7. [画面功能验证](#七画面功能验证)
8. [调试技巧](#八调试技巧)
9. [重启前检查清单](#九重启前检查清单)
10. [典型问题模式](#十典型问题模式)
---
## 一、数据库问题
### 1.1 SQLite 类型兼容
- [x] Entity 使用 `simple-enum` 而非 `enum`
- [x] 移除 `@Column``default` 值(SQLite不支持enum默认值)
- [x] 所有 `@Column` 必须指定 `type`(如 `type: 'text'`
**检查命令**:
```bash
# 检查所有 Entity 的 @Column 是否有 type
grep -r "@Column({ name:" server/src/assessment/entities/ | grep -v "type:"
```
**修复记录** (2026-05-14):
- `assessment-session.entity.ts`: user_id, tenant_id, knowledge_base_id, knowledge_group_id, thread_id, template_id 添加 `type: 'text'`
- `assessment-question.entity.ts`: session_id 添加 `type: 'text'`
- `assessment-answer.entity.ts`: question_id 添加 `type: 'text'`
- `assessment-certificate.entity.ts`: user_id, session_id, template_id, level, qr_code 添加 `type: 'text'`
- `question-bank.entity.ts`: 移除 status 字段的 default 值
### 1.2 Null 值处理
- [x] 查询时处理 null`WHERE column IS NULL` 而非 `= NULL`
- [x] Service 方法处理 `tenantId: null` 情况
- [x] Entity 字段标记 `nullable: true`
**检查要点**:
```typescript
// 错误
const result = await repo.findOne({ where: { tenantId: null } });
// 正确
const result = await repo.findOne({ where: { tenantId: IsNull() } });
// 或
const result = await repo.findOne({ where: { tenantId: undefined } });
```
### 1.3 数据库重置
- [ ] 删除数据库后重新创建会导致所有数据丢失
- [ ] 确认是否有备份或可以恢复
---
## 二、API 前后端一致性
### 2.1 HTTP 方法
- [x] POST 创建资源
- [x] PUT 更新资源
- [x] GET 获取资源
- [x] DELETE 删除资源
### 2.2 端点匹配
- [x] 前端 service 调用的端点与后端 controller 一致
- [x] 特别注意:后端用 PUT 但前端用 POST 的情况
- [x] 检查新增的 API 路由是否已添加
**API 匹配检查表**:
| 前端方法 | 后端端点 | 状态 |
|---------|---------|------|
| startSession | POST /assessment/start | ✅ |
| submitAnswerStream | POST /assessment/:id/answer | ✅ |
| getSessionState | GET /assessment/:id/state | ✅ |
| deleteSession | DELETE /assessment/:id | ✅ |
| getHistory | GET /assessment/history | ✅ |
| getCertificate | GET /assessment/:id/certificate | ✅ |
| exportPdf | GET /assessment/:id/export/pdf | ✅ |
| exportExcel | GET /assessment/:id/export/excel | ✅ |
| checkTimeLimits | GET /assessment/:id/time-check | ✅ |
| getStats | GET /assessment/stats | ✅ |
| getRadarStats | GET /assessment/stats/radar | ✅ |
| getTrendStats | GET /assessment/stats/trend | ✅ |
| reviewAssessment | PUT /assessment/:id/review | ✅ |
| forceEnd | POST /assessment/:id/force-end | ✅ |
| templateService.getAll | GET /assessment/templates | ✅ |
| questionBankService.getBanks | GET /question-banks | ✅ |
| questionBankService.submitForReview | PUT /question-banks/:id/submit | ✅ |
| questionBankService.approveBank | PUT /question-banks/:id/review | ✅ |
| questionBankService.publishBank | PUT /question-banks/:id/publish | ✅ |
| questionBankService.generateQuestions | POST /question-banks/:id/generate | ✅ |
### 2.3 路由传参
- [x] RESTful 路径参数:`:id`, `:bankId`
- [x] Query 参数:`?page=1&limit=10`
- [x] Body 参数:JSON 请求体
**检查命令**:
```bash
# 检查后端路由
grep -r "@Get\|@Post\|@Put\|@Delete" server/src/assessment/*controller.ts
# 检查前端调用
grep -r "apiClient\|service\." web/components/views/
```
---
## 三、题库模块检查点
### 3.1 后端 Entity
- [x] `QuestionBank` - simple-enum 类型,无默认值
- [x] `QuestionBankItem` - 所有 enum 字段使用 simple-enum
- [x] `status` 字段必须有默认值(在 service 层设置)
**验证命令**:
```bash
grep -A5 "enum:" server/src/assessment/entities/question-bank*.ts
```
### 3.2 后端 Service
- [x] `create()` - 验证 name 不为空
- [x] `addItem()` - 验证 questionText 不为空,设置 status 默认值
- [x] `generateQuestions()` - AI 生成时设置 status
- [x] `findAll()` - 处理 tenantId 为 null 的查询
- [x] `create()` - 处理 tenantId 为 null 的创建
**检查代码模式**:
```typescript
// create 方法必须验证
if (!createDto.name || !createDto.name.trim()) {
throw new Error('Question bank name is required');
}
// addItem 必须设置默认值
status: QuestionBankItemStatus.PENDING_REVIEW
```
### 3.3 后端 Controller
- [x] GET `/items` 路由存在
- [x] 路由方法与 service 方法匹配(PUT vs POST
### 3.4 前端 Service
- [x] `submitForReview` - 使用 PUT
- [x] `approveBank/rejectBank` - 使用 `/review` 端点
- [x] `publishBank` - 使用 PUT
- [x] `getBankItems` - 调用正确的端点
### 3.5 前端 Component
- [x] 组件已正确 export
- [x] 路由已添加到 index.tsx
- [x] Service 调用正确
---
## 四、评估流程检查点
### 4.1 状态机 (LangGraph)
- [x] 变量作用域:避免 if/else 块内定义,return 中使用
- [x] 数组空值:`questions || []` 防护
- [x] 负数处理:`Math.max(0, remaining)`
**修复记录** (2026-05-14):
- `builder.ts`: 添加 `Math.max(0, state.currentQuestionIndex || 0)` 防护负数
**检查代码**:
```typescript
// builder.ts 中必须使用
const currentIndex = Math.max(0, state.currentQuestionIndex || 0);
```
### 4.2 API 一致性
- [x] 前端使用 `/answer` 还是 `/answer-stream`
- [x] 后端响应格式与前端期望一致
**决策**: 使用非流式 API `/answer`,前端已同步
---
## 五、模型配置检查点
### 5.1 LLM 配置
- [x] Base URL 正确(官方API vs 本地部署)
- [x] Model ID 正确
- [x] API Key 配置
### 5.2 Embedding 配置
- [x] 向量维度匹配(Ollama nomic-embed-text 为 768维)
- [x] 服务可访问(IP/端口映射)
---
## 六、角色与用户故事验证
### 6.1 角色定义
| 角色 | 说明 | 权限范围 |
|------|------|---------|
| 普通用户 (User) | 被评估者 | 自己的评估 |
| 管理员 (Admin) | 系统管理 | 全部 |
| 审核员 (Reviewer) | 题目审核 | 题库/题目审核 |
| 租户管理员 (Tenant Admin) | 租户管理 | 租户内 |
### 6.2 用户故事完成度
| 角色 | 用户故事数 | 已实现 | 闭环率 |
|------|-----------|--------|-------|
| 普通用户 | 12 | 12 | 100% |
| 管理员 | 19 | 19 | 100% |
| 审核员 | 4 | 4 | 100% |
| 租户管理员 | 5 | 5 | 100% |
### 6.3 用户故事检查表
#### 普通用户 (User)
- [x] 选择评估范围(知识组/模板)
- [x] 开始评估
- [x] 回答问题
- [x] 查看实时反馈
- [x] 查看剩余时间
- [x] 查看评估历史(最新3条)
- [x] 查看历史详情
- [x] 评估完成查看报告
- [x] 导出PDF报告
- [x] 导出Excel报告
- [x] 查看证书
- [x] 删除自己的评估
#### 管理员 (Admin)
- [x] 模板CRUD
- [x] 题库CRUD
- [x] AI生成题目
- [x] 批量审核题目
- [x] 审核评估(调整分数)
- [x] 强制结束评估
- [x] 查看统计数据
- [x] 导出CSV
- [x] 验证证书
### 6.4 权限验证检查
- [x] 后端权限控制正确 (role 检查)
- [x] 前端画面访问控制正确
---
## 七、画面功能验证
### 7.1 画面清单
| 画面 | 文件路径 | 功能 |
|------|---------|------|
| AssessmentView | components/views/AssessmentView.tsx | 主评估界面 |
| AssessmentStatsView | components/views/AssessmentStatsView.tsx | 统计数据 |
| AssessmentTemplateManager | components/views/AssessmentTemplateManager.tsx | 模板管理 |
| QuestionBankView | components/views/QuestionBankView.tsx | 题库列表 |
| QuestionBankDetailView | components/views/QuestionBankDetailView.tsx | 题库详情 |
### 7.2 按钮与功能验证
| 画面 | 按钮数量 | 输入框数量 | 功能闭环 | 状态 |
|------|---------|-----------|---------|------|
| AssessmentView | 14 | 1 | ✅ | ✅ |
| QuestionBankView | 10 | 3 | ✅ | ✅ |
| QuestionBankDetailView | 10 | 8 | ✅ | ✅ |
| AssessmentTemplateManager | 6 | 6 | ✅ | ✅ |
| AssessmentStatsView | 2 | 4 | ✅ | ✅ |
### 7.3 输入框检查
| 画面 | 输入框 | onChange | onKeyDown | 验证 | 状态 |
|------|-------|----------|-----------|------|------|
| AssessmentView | 答案输入 | ✅ | Enter提交 | - | ✅ |
| QuestionBankView | 名称/描述/模板 | ✅ | - | 验证 | ✅ |
| QuestionBankDetailView | 题目属性 | ✅ | - | 转换 | ✅ |
| AssessmentTemplateManager | 模板字段 | ✅ | - | 解析 | ✅ |
| AssessmentStatsView | 日期/筛选 | ✅ | - | - | ✅ |
### 7.4 参数传递链验证
```
开始评估: startSession(selectedGroup, language, selectedTemplate)
回答问题: submitAnswerStream(session.id, answer, language)
时间检查: checkTimeLimits(session.id) [定期]
获取证书: getCertificate(session.id)
导出报告: exportExcel/Pdf(session.id)
```
---
## 八、调试技巧
### 8.1 日志添加
- [x] 后端:console.log 在关键方法
- [x] 前端:console.log 在 API 调用前后
- [x] 日志包含关键变量值
**关键日志位置**:
- `assessment.service.ts`: startSession, submitAnswer, checkTimeLimits
- `assessment.controller.ts`: 所有方法入口
- `AssessmentView.tsx`: handleStartAssessment, handleSubmitAnswer
### 8.2 检查步骤
1. 查看 Docker logs`docker compose logs server --tail 50`
2. 查看前端 ConsoleF12
3. 查看 Network 面板请求响应
4. 直接调用 API 测试
### 8.3 常见症状
- [x] 弹窗显示成功但数据未更新 → API 可能失败,检查返回数据格式
- [x] 页面空白无数据 → 检查 API 是否被调用,参数是否正确
- [x] 403 权限错误 → 检查用户角色是否匹配
---
## 九、重启前检查清单
### 代码层面
- [x] 所有修改的文件已保存
- [x] 没有语法错误
- [x] import 语句正确
- [x] Entity @Column 类型完整
### 构建层面
- [ ] `docker compose build` 成功
- [ ] 无新增的编译错误
### 测试层面
- [ ] 服务启动成功
- [ ] 登录功能正常
- [ ] 目标功能可访问
---
## 十、典型问题模式
### 问题1:新增功能不工作
**检查顺序:**
1. [x] 后端 entity 是否注册到 app.module
2. [x] 后端 service 是否在 module 中提供
3. [x] 后端 controller 是否有对应路由
4. [x] 前端 service 是否调用正确端点
5. [x] 前端 component 是否正确 import 和 export
6. [x] 前端 route 是否添加
### 问题2:数据创建成功但查询不到
**检查顺序:**
1. [x] tenantId 是否正确设置
2. [x] 查询条件是否匹配(== vs IS NULL
3. [x] 权限是否正确
### 问题3:类型不匹配
**检查顺序:**
1. [x] 后端 entity 类型
2. [x] 后端 DTO 类型
3. [x] 前端 service 接口类型
4. [x] 前端 types 定义
5. [x] API 响应格式
---
## 十一、题库生成与关联功能深度检查 (2026-05-14)
### 11.1 题库生成 (generateQuestions)
**检查项**:
- [x] 输入验证 - count 范围检查 (1-50)
- [x] 输入验证 - knowledgeBaseContent 最小长度检查
- [x] 错误处理 - JSON 解析失败处理
- [x] 性能优化 - 批量保存而非逐个保存
**修复记录**:
- 添加 count 范围验证: `if (count <= 0 || count > 50) throw new Error(...)`
- 添加 content 最小长度验证: `if (!knowledgeBaseContent || content.trim().length < 10)`
- 修改为批量保存: `items.push(item)``await this.itemRepository.save(items)`
### 11.2 题目选择 (selectQuestions)
**检查项**:
- [x] 循环条件逻辑 - 正确终止条件
- [x] 随机选择算法 - Fisher-Yates shuffle
- [x] 维度分布 - 均匀轮询
**修复记录**:
- 重写循环逻辑: `while (selected.length < count && availableItems.length > 0)`
- 添加 shuffle 方法: `private shuffleArray<T>(array: T[]): T[]`
- 添加循环次数上限: `if (dimIdx >= DIMENSIONS.length * 3) break`
### 11.3 题库状态管理
**检查项**:
- [x] submitForReview - DRAFT 状态检查
- [x] review - PENDING_REVIEW 状态检查
- [x] publish - PUBLISHED/REJECTED 状态检查
**状态**: ✅ 逻辑正确
### 11.4 评估启动与题目关联
**检查项**:
- [x] 题库查询逻辑 - PUBLISHED 状态过滤
- [x] 题目数量检查 - 不足时回退到 LLM 生成
- [x] 题目选择调用 - selectQuestions 方法
**状态**: ✅ 逻辑正确
### 11.5 LangGraph 题目生成节点
**检查项**:
- [x] 已有足够题目时跳过生成
- [x] 已有题目传递到状态
**修复记录**:
- 添加跳过逻辑:
```typescript
if (existingQuestions.length >= limitCount) {
console.log('[GeneratorNode] Skipping generation - enough questions from bank');
return { questions: existingQuestions };
}
```
### 11.6 其他关联功能检查
| 功能模块 | 检查结果 | 备注 |
|---------|---------|------|
| 批量审核 (batchReviewItems) | ✅ | 状态更新、comment 追加 |
| 证书生成 (generateCertificate) | ✅ | 等级判定、已有证书复用 |
| 数据导出 (exportToExcel/Pdf) | ⚠️ | question 无 order 字段 |
| 时间控制 (checkTimeLimits) | ✅ | 计算逻辑正确 |
| 评估审核 (reviewAssessment) | ⚠️ | 审核后 passed 未更新 → 已修复 |
| 统计功能 (getStats/radar/trend) | ✅ | 权限过滤、数据聚合 |
| 权限控制 (isAdmin) | ✅ | 角色检查正确 |
| 错误处理 | ✅ | NotFound/Forbidden/Error |
| 空值处理 | ✅ | 默认值防护完善 |
### 11.7 本次修复汇总
| # | 问题 | 位置 | 严重程度 | 状态 |
|---|------|------|---------|------|
| 1 | selectQuestions 循环条件错误 | question-bank.service.ts | 高 | ✅ |
| 2 | 随机选择算法不均匀 | question-bank.service.ts | 中 | ✅ |
| 3 | count 无上限检查 | question-bank.service.ts | 中 | ✅ |
| 4 | 空 content 仍调用 LLM | question-bank.service.ts | 中 | ✅ |
| 5 | 逐个保存而非批量 | question-bank.service.ts | 低 | ✅ |
| 6 | 已有足够题目时仍生成 | generator.node.ts | 高 | ✅ |
| 7 | 审核后 passed 未更新 | assessment.service.ts | 中 | ✅ |
---
## 附录:相关文件位置
### 后端核心
- `server/src/app.module.ts` - Entity 注册
- `server/src/assessment/assessment.module.ts` - 模块配置
- `server/src/assessment/entities/` - 数据实体
- `server/src/assessment/assessment.service.ts` - 业务逻辑
- `server/src/assessment/assessment.controller.ts` - API 路由
- `server/src/assessment/graph/` - LangGraph 状态机
- `server/src/assessment/graph/nodes/generator.node.ts` - 题目生成节点
- `server/src/assessment/graph/nodes/interviewer.node.ts` - 题目展示节点
- `server/src/assessment/graph/nodes/grader.node.ts` - 评分节点
- `server/src/assessment/services/question-bank.service.ts` - 题库服务
- `server/src/assessment/services/export.service.ts` - 导出服务
### 前端核心
- `web/index.tsx` - 路由配置
- `web/services/assessmentService.ts` - 评估API调用
- `web/services/questionBankService.ts` - 题库API调用
- `web/services/templateService.ts` - 模板API调用
- `web/components/views/AssessmentView.tsx` - 评估页面
- `web/components/views/AssessmentStatsView.tsx` - 统计页面
- `web/components/views/QuestionBankView.tsx` - 题库列表
- `web/components/views/QuestionBankDetailView.tsx` - 题库详情
- `web/components/views/AssessmentTemplateManager.tsx` - 模板管理
- `web/types.ts` - 类型定义
---
## 十二、代码整合性验证报告 (2026-05-15)
### 12.1 用户故事验证 (33条)
| 分类 | 总数 | 通过 | 修复后通过 |
|------|------|------|-----------|
| 普通用户 (US-01~10) | 10 | 9 | ✅ 10 (修复历史限制) |
| 管理员 (AM-01~21) | 21 | 19 | ✅ 21 (修复证书端点) |
| 审核员 (RV-01~02) | 2 | 2 | ✅ 2 |
### 12.2 修复的代码缺口 (9项)
| # | 问题 | 严重度 | 修复内容 |
|---|------|--------|---------|
| 1 | getUserHistory 返回100条而非3条 | P0 | `take: 100``take: 3` |
| 2 | verifyCertificate 空@UseGuards() | P0 | 改为 `@Public()` 装饰器 |
| 3 | QuestionBank.status 无默认值 | P0 | 添加 `default: DRAFT` |
| 4 | getPublicCertificate 未公开 | P1 | 添加 `@Public()` 装饰器 |
| 5 | AssessmentStatsView 硬编码isAdmin=true | P1 | 改为 `user.role === 'SUPER_ADMIN'` |
| 6 | 创建题库带templateId报500 | P0 | 修复create方法+唯一约束检查 |
| 7 | 异常消息未透传前端 | P0 | throw Error→BadRequestException |
| 8 | 前端"Failed to generate"不显示真实错误 | P0 | 解析response body中的message |
| 9 | SSE答案使用GET+QueryParam | P2 | 已记录待后续优化 |
### 12.3 已验证的业务闭环
```
模板创建 → 题库创建(AI生成/手动添加) → 提交审核 → 审核通过 → 发布题库
→ 创建评估 → AI生成题目 → 用户答题 → AI评分 → 生成报告 → 审核评估
→ 生成证书(通过时) → 导出Excel/PDF
```
### 12.4 剩余建议 (P2)
| # | 问题 | 建议 |
|---|------|------|
| 1 | PDF导出实为纯文本 | 使用pdfkit等库生成真正的PDF |
| 2 | difficultyDistribution类型不一致 | 统一使用 `{standard,advanced,specialist}` |
| 3 | 强制结束评估清零分数 | 保留已有分数,记录`forceEnded`标志 |
| 4 | 批量审核拒绝项设为PENDING_REVIEW | 改为REJECTED状态或明确语义 |