Files
NextEdu/docs/architecture/audit/exam-homework-audit-report-v2.md
SpecialX 682d385ee2 fix(dashboard): v3 审计修复 — 数据完整性、i18n、类型安全、死代码清理
P0 修复(严重):
- admin ContentRow 标签与值错配(stats.users→textbooks 等 6 处)
- admin/error.tsx 硬编码中文替换为 useTranslations
- UserGrowthChart 空数据时渲染 EmptyState(userGrowth/homeworkTrend 永远为空数组)

P1 修复(高):
- 新增 admin/dashboard 和 student/dashboard 的 loading.tsx + error.tsx
- 抽取 DashboardLoadingSkeleton 和 DashboardErrorFallback 共享组件,消除 5 套重复文件
- formatDate/formatLongDate 传入用户 locale(admin/teacher/student 共 6 个组件)
- 移除死代码:getCachedAdminDashboard、AvatarImage src={undefined}、TeacherStats isLoading prop
- filterTodaySchedule 改为泛型函数,消除 as 类型断言
- 辅助函数 getStatus/getDueUrgency 新增显式返回类型
- UserGrowthChart 新增 labelKey prop 区分用户增长/作业提交趋势标签

P2 修复(中):
- 4 个组件从客户端转为服务端组件(DashboardGreetingHeader、TeacherQuickActions、TeacherDashboardHeader、StudentDashboardHeader)
- Student dashboard 空状态新增 CTA(viewSchedule、viewAll)
- TeacherHomeworkCard 图标按钮新增 aria-label
- TeacherTodoCard 排序逻辑重写为可读的 if/return 模式

同步更新:
- docs/architecture/005_architecture_data.json 新增 DashboardLoadingSkeleton、DashboardErrorFallback 条目
- 新增 docs/architecture/audit/dashboard-audit-report-v3.md 审计报告
- dashboard.json 新增 6 个 i18n 键(textbooks/chapters/questions/exams/totalAssignments/totalSubmissions)
2026-06-22 18:36:46 +08:00

13 KiB
Raw Blame History

考试/作业模块审计报告 v2

基于 v1 审计报告(exam-homework-audit-report.md)的全量修复验证与二次审计 生成时间2026-06-22 审计范围:src/modules/exams/src/modules/homework/src/modules/proctoring/src/shared/(考试/作业相关共享层)


1. v1 修复项验证总览

1.1 修复项状态矩阵

编号 优先级 描述 v1 状态 v2 验证结果
P0-1 P0 题目内容解析纯函数抽取 已完成 question-content-utils.ts 14 个纯函数3 处调用方已统一
P0-2 P0 QuestionRenderer 组合式组件 已完成 支持 take/review/grade 三模式student-homework-review-view 已重构
P0-3 P0 ExamModeConfig 全链路集成 v2 完成 schema→form→actions→data-access→DB 全链路打通
P1-5 P1 exam-mode-config i18n 已完成 zh-CN/en 双语完整
P1-6 P1 类型断言清理as any/unknown v2 完成 5 个文件共 8 处断言已消除
P1-7 P1 ai-pipeline.ts 拆分 v2 完成 857 行拆为 4 文件parse/request/structure/index
P1-8 P1 相邻记录查询优化 v2 完成 O(n) 全表扫描优化为 O(1) LIMIT 1 双查询
P2-9 P2 学生答案自动保存+离线缓存 v2 完成 useDebouncedAutoSave hook 已集成
P2-12 P2 a11y 修复 v2 完成 难度色条 aria-label + 导航按钮 aria-pressed
P2-13 P2 配置驱动角色渲染 v2 完成 ExamHomeworkRoleConfig + useExamHomeworkFeatures
6.1 P3 ExamHomeworkServicePort v2 完成 接口定义 + ServiceProvider 单例注册器
6.5 P3 单测覆盖 v2 完成 63 个测试用例全部通过
6.7 P3 trackExamEvent 监控 v2 完成 17 个事件 + trackExamEvent 便捷函数

1.2 验证方法

  • TypeScript 类型检查npx tsc --noEmit 零新增错误7 个预存错误均非考试/作业模块)
  • ESLintnpm run lint 零新增错误、零新增警告
  • 单元测试npm run test:unit 63 个测试全部通过
  • 架构图同步005_architecture_data.json _meta.lastUpdate 已更新

2. v2 新增修复详情

2.1 P0-3: ExamModeConfig 全链路集成

问题考试模式配置homework/timed/proctored在 schema、表单、actions、data-access 各层未打通DB 已有字段但前端无法写入。

修复

  1. exam-form-types.tsformSchema 扩展 6 字段 + superRefine 校验proctored/timed 模式必须设置 durationMinutes
  2. exam-form.tsxonSubmit 追加 6 个 formData.append 调用
  3. actions.ts:新增 parseExamModeConfig(formData) 解析函数,createExamAction/createAiExamAction 传递 examModeConfig 参数
  4. data-access.tspersistExamDraft/persistAiGeneratedExamDraft 接受 examModeConfig?: ExamModeConfig 并写入 DB
  5. exam-mode-config.tsxExamModeConfigFieldValues.durationMinutes 改为可选(?)以匹配 Zod schema 的 .optional()

验证ExamModeConfig<ExamFormValues> 显式类型参数传递,类型检查通过。

2.2 P1-6: 类型断言清理

问题5 个文件共 8 处 as any/as unknown/as unknown as 断言绕过类型检查。

修复

文件 原断言 修复方式
exam-form.tsx zodResolver(formSchema) as any as Resolver<ExamFormValues>
exam-form.tsx defaultValues as unknown as ExamFormValues 直接使用 defaultValues
exam-form.tsx form.handleSubmit(onSubmit as any) ×2 移除断言
exam-actions.tsx as unknown as Question RawStructureNode 类型守卫 + hydrate 函数
homework-take-view.tsx as unknown[] 类型收窄 hasAnswer 局部变量
homework-grading-view.tsx as ChoiceOption[] / as string[] / as QuestionType getOptions() + filter 类型守卫
homework/data-access.ts as unknown 移除DB 返回类型已正确)

2.3 P1-7: ai-pipeline.ts 拆分

问题ai-pipeline.ts 857 行,超出单文件 800 行建议上限,职责混杂。

修复:拆分为 ai-pipeline/ 目录 4 文件:

  • parse.tsZod schemas、JSON 解析、纯转换函数、AI 提示词
  • request.tsAI 请求函数(requestAiExamDraft/requestAiExamStructureDraft/validateExamSourceText/parseQuestionDetail/regenerateAiQuestionByInstruction
  • structure.ts:结构生成(splitStructureItems/mapWithConcurrency/buildPreviewPayload/previewToDraft
  • index.ts:重新导出 + 高层编排(generateAiPreviewData/generateAiCreateDraftFromSource/generateAiExamDraft

依赖方向index.ts → request.ts + structure.ts → parse.ts(无循环依赖)

2.4 P1-8: 相邻记录查询优化

问题getHomeworkSubmissionDetails 获取上/下一条提交记录时使用全表扫描 + JS 过滤O(n) 复杂度。

修复:改为两个 LIMIT 1 查询并行执行:

const [prevSubmission, nextSubmission] = await Promise.all([
  db.query.homeworkSubmissions.findFirst({
    where: and(eq(..., assignmentId), gt(..., currentUpdatedAt)),
    orderBy: [asc(homeworkSubmissions.updatedAt)],
    columns: { id: true },
  }),
  db.query.homeworkSubmissions.findFirst({
    where: and(eq(..., assignmentId), lt(..., currentUpdatedAt)),
    orderBy: [desc(homeworkSubmissions.updatedAt)],
    columns: { id: true },
  }),
])

2.5 P2-9: 学生答案自动保存 + 离线缓存

问题:学生作答时仅靠手动点击"保存答案"按钮,网络中断或浏览器关闭会丢失答案。

修复

  1. 新增 use-debounced-auto-save.ts hook
    • 3 秒 debounce 自动保存到服务端
    • 每次变更同步写入 localStorage离线缓存
    • 网络异常标记 error窗口 focus 时自动重试
    • 组件卸载时 flush 未保存答案
    • 状态跟踪idle/saving/saved/error
  2. 集成到 homework-take-view.tsx
    • 挂载时从 localStorage 恢复未提交答案toast 提示)
    • 侧边栏显示自动保存状态指示器(图标+文字+颜色)
    • 提交前调用 autoSave.flush() 确保所有答案落库
    • 提交成功后清除离线缓存
  3. i18n新增 6 个翻译键autoSaveIdle/Saving/Saved/Error/Restored/CacheError

2.6 P2-12: a11y 修复

问题:难度颜色条仅靠颜色传达信息,题目导航按钮缺少状态标识。

修复

  1. exam-columns.tsx:难度色条容器添加 role="img" + aria-label(含 i18nexam.difficulty.ariaLabel
  2. homework-take-view.tsx:题目导航按钮添加 aria-pressed={hasAnswer} + title(已作答/未作答提示)
  3. i18n新增 exam.difficulty.ariaLabelhomework.take.answeredhomework.take.unanswered

2.7 P2-13: 配置驱动角色渲染

问题:角色权限判断分散在各组件中,缺少单一数据源。

修复

  1. shared/config/exam-homework-role-config.ts
    • ExamHomeworkRoleFeatures 接口11 个功能特性)
    • EXAM_HOMEWORK_ROLE_CONFIG6 角色 × 11 特性配置矩阵)
    • getExamHomeworkFeatures(roles) 并集合并函数
  2. shared/hooks/use-exam-homework-features.ts:客户端 Hook 封装

2.8 6.1: ExamHomeworkServicePort

问题app 层直接依赖 modules 的 data-access 函数,耦合度高,难以测试。

修复shared/services/exam-homework-port.ts

  • ExamHomeworkServicePort 接口(考试/作业/跨模块共 7 个方法)
  • ServiceProvider<T> 泛型单例注册器register/get/reset
  • registerExamHomeworkService(impl) 注册入口

2.9 6.5: 单元测试

新增测试文件

  1. question-content-utils.test.ts52 测试):
    • isRecord/getQuestionText/getOptions/getChoiceCorrectIds/getJudgmentCorrectAnswer/getTextCorrectAnswers
    • parseSavedAnswer/extractAnswerValue/normalizeText
    • isAutoGradable/computeIsCorrect(覆盖 4 种题型 × 正确/错误/无答案)
    • getCorrectnessState/applyAutoGrades/formatStudentAnswer
  2. exam-homework-role-config.test.ts11 测试):
    • 6 角色配置正确性
    • 空角色列表返回默认值
    • 多角色并集合并
    • 未知角色安全忽略

2.10 6.7: trackExamEvent 监控

修复shared/lib/track-event.ts

  • EventName 类型扩展 17 个考试/作业事件exam.created/updated/published/archived/deleted/duplicated/ai_generated/submitted/graded + homework.created/updated/published/archived/deleted/submitted/graded/auto_save_failed
  • 新增 trackExamEvent(event, params) 便捷函数,自动设置 targetType

3. v2 二次审计发现

3.1 已确认无问题项

  • 三层架构依赖app → modules → shared 单向依赖,无反向依赖
  • Server Action 权限校验:所有 action 均调用 requirePermission()
  • Zod 验证:表单输入均有 schema 验证
  • i18n 完整性zh-CN/en 双语键完整,无硬编码中文
  • DB 表结构exams/homeworkAssignments 表已包含 examMode 等 6 个字段

3.2 遗留项(非阻塞,建议后续迭代)

编号 描述 建议
L-1 ExamHomeworkServicePort 已定义但未注册实现 instrumentation.ts 中调用 registerExamHomeworkService() 注入真实实现
L-2 trackExamEvent 已定义但未在 actions 中调用 createExamAction/submitHomeworkAction 等关键 action 中添加 trackExamEvent() 调用
L-3 useExamHomeworkFeatures hook 已创建但未在页面中使用 在 teacher/student 页面中用 features.can* 替代直接权限判断
L-4 ai-pipeline/structure.ts 仍有 ~300 行 可进一步拆分 previewToDraft 到独立文件
L-5 预存 TypeScript 错误7 个) 均非考试/作业模块,建议其他模块迭代修复

3.3 代码质量指标

指标 v1 v2
as any 断言 8 处 0 处
as unknown 断言 3 处 0 处
单文件最大行数 857 行ai-pipeline.ts ~400 行ai-pipeline/structure.ts
单元测试用例 0 63
a11y aria-label 2 处缺失 0 处缺失
离线缓存支持 localStorage + 自动恢复

4. 修改文件清单

4.1 新增文件10 个)

文件 用途
src/modules/homework/lib/question-content-utils.ts 题目内容解析纯函数v1 创建)
src/modules/homework/lib/question-content-utils.test.ts 纯函数单测52 测试)
src/modules/homework/components/question-renderer.tsx 组合式题目渲染组件v1 创建)
src/modules/homework/hooks/use-debounced-auto-save.ts 自动保存+离线缓存 hook
src/modules/exams/ai-pipeline/parse.ts AI 管线:解析层
src/modules/exams/ai-pipeline/request.ts AI 管线:请求层
src/modules/exams/ai-pipeline/structure.ts AI 管线:结构层
src/modules/exams/ai-pipeline/index.ts AI 管线:入口+编排
src/shared/config/exam-homework-role-config.ts 角色功能配置
src/shared/config/exam-homework-role-config.test.ts 配置单测11 测试)
src/shared/services/exam-homework-port.ts 服务端口接口
src/shared/hooks/use-exam-homework-features.ts 角色特性客户端 hook

4.2 修改文件12 个)

文件 修改内容
src/modules/exams/components/exam-form.tsx P0-3 + P1-6ExamModeConfig 集成 + 类型断言清理
src/modules/exams/components/exam-form-types.ts P0-3schema 扩展 6 字段
src/modules/exams/components/exam-columns.tsx P2-12难度色条 aria-label
src/modules/exams/components/exam-actions.tsx P1-6类型守卫替代断言
src/modules/exams/data-access.ts P0-3ExamModeConfig 写入 DB
src/modules/exams/actions.ts P0-3parseExamModeConfig 解析
src/modules/homework/components/homework-take-view.tsx P2-9 + P2-12自动保存集成 + a11y
src/modules/homework/components/homework-grading-view.tsx P1-6类型断言清理
src/modules/homework/components/student-homework-review-view.tsx P0-2QuestionRenderer 重构v1
src/modules/homework/data-access.ts P1-6 + P1-8断言清理 + 查询优化
src/modules/proctoring/components/exam-mode-config.tsx P0-3durationMinutes 可选 + i18nv1
src/shared/lib/track-event.ts 6.7exam/homework 事件扩展
src/shared/i18n/messages/zh-CN/exam-homework.json i18n 键扩展
src/shared/i18n/messages/en/exam-homework.json i18n 键扩展
docs/architecture/005_architecture_data.json 架构图同步

4.3 删除文件1 个)

文件 原因
src/modules/exams/ai-pipeline.ts P1-7拆分为 ai-pipeline/ 目录

5. 结论

v1 审计报告中的全部 13 个修复项P0-3、P1-5~P1-8、P2-9、P2-12、P2-13、6.1、6.5、6.7 及 v1 已完成项)已在 v2 中全量完成验证。

代码质量:零新增类型错误、零新增 lint 警告、63 个单测全部通过。

架构健康度:三层依赖清晰、类型安全(零 as any、单文件行数达标、a11y 合规、i18n 完整、离线容错已覆盖。

后续建议:处理 §3.2 中的 5 个遗留项(非阻塞),优先级 L-1 > L-2 > L-3 > L-4 > L-5。