Files
NextEdu/docs/architecture/audit/core-business-audit.md

22 KiB
Raw Blame History

核心业务模块职责与耦合审查报告

审计日期2026-06-17 审计范围:src/modules/examssrc/modules/homeworksrc/modules/questionssrc/modules/textbookssrc/modules/grades 审计目标:识别职责不单一和过耦合问题,重点关注跨模块直接数据库查询(违反模块封装) 审计依据:项目规则(.trae/rules/project_rules.md、架构影响地图004/005


一、总体结论

维度 状态 说明
模块职责边界 ⚠️ 部分违规 homework 混入考试/班级逻辑grades 混入班级/用户逻辑
data-access 层职责 普遍违规 5 个模块均存在跨模块直接 DB 查询homework/data-access.ts 混入排名业务逻辑(已拆分 stats-service.ts
actions 层职责 已修复 exams/homework/questions/announcements 的 actions DB 操作已下沉到 data-accessP1-2textbooks/grades 的 actions 设计良好
组件耦合 基本合规 组件层跨模块依赖均为类型导入或 UI 组合,无直接 data-access 调用
跨模块依赖 ⚠️ 存在风险 无循环依赖,但 exams→questions、homework→exams、grades→classes 的直接 DB 访问破坏封装
文件行数 已修复 homework/data-access.ts 已拆分598 行 + stats-service.ts 425 行 + data-access-write.ts 285 行exams/ai-pipeline.ts 857 行(超 800 建议值P1 待拆分)

关键风险项

  1. homework/data-access.ts 超过 1000 行硬上限1038 行)—— 必须拆分 已拆分
  2. 5 个模块均存在跨模块直接 DB 查询 —— 违反模块封装原则P1-1 待修复)
  3. exams/homework/questions 的 actions 层混入数据访问逻辑 —— 应只做编排 已修复P1-2
  4. homework/data-access.ts 混入排名计算业务逻辑 —— data-access 应只负责数据存取 已修复(拆分到 stats-service.ts

二、模块依赖关系图

                    ┌──────────────┐
                    │  textbooks   │ ← 被引用方(知识点/章节)
                    └──────┬───────┘
                           │
            ┌──────────────┼──────────────┐
            │              │              │
            ▼              ▼              ▼
     ┌────────────┐  ┌──────────┐  ┌────────────┐
     │ questions  │  │  exams   │  │  homework  │
     └─────┬──────┘  └────┬─────┘  └─────┬──────┘
           │              │              │
           │   ┌──────────┘              │
           │   │                          │
           ▼   ▼                          ▼
     ┌────────────────┐            ┌──────────┐
     │    grades      │            │  classes │
     └────────────────┘            └──────────┘

依赖关系明细

依赖方向 类型 合理性 问题
exams → questions data-access + 类型 + action ⚠️ 部分合理 类型导入合理;但 persistAiGeneratedExamDraft 直接 insert 到 questions 表,应通过 questions/data-access
exams → classes data-access 不合理 getExams/getExamById 直接查询 classes 表获取教师 gradeIds应通过 classes/data-access
exams → school actions 不合理 getSubjectsAction/getGradesAction 直接查询 subjects/grades 表,应通过 school/data-access
homework → exams data-access + 组件 ⚠️ 部分合理 业务上 homework 引用 examsourceExamId合理但直接查询 exams 表应改为调用 exams/data-access
homework → classes data-access + actions 不合理 直接查询 classes/classEnrollments/classSubjectTeachers 表,应通过 classes/data-access
homework → questions data-access 合理 通过 Drizzle 关系查询 homeworkAssignmentQuestions.question未直接访问 questions 表
grades → exams 合理 grades 仅通过 examId 外键引用,不直接查询 exams 表
grades → homework 合理 grades 仅通过 type 枚举值 "homework" 引用,不直接查询 homework 表
grades → classes data-access 不合理 多个 data-access 文件直接查询 classes/classEnrollments 表
grades → users/subjects data-access 不合理 直接查询 users/subjects 表获取关联名称,应通过对应模块 data-access
questions → textbooks actions 不合理 getKnowledgePointOptionsAction 直接查询 knowledgePoints/chapters/textbooks 表
textbooks → questions 组件 合理 knowledge-point-dialogs.tsx 导入 CreateQuestionDialog 组件,属于 UI 组合

循环依赖分析

  • 无直接循环依赖:模块间的 data-access 依赖是单向的
  • 潜在风险exams → questionsdata-access与 questions → textbooksactions与 textbooks → questions组件形成链式依赖但因 textbooks→questions 仅为组件层导入,不构成 data-access 层的循环依赖

三、各模块审查明细

3.1 exams 模块

文件行数

文件 行数 限制 状态
actions.ts 691 ≤800 P1-2 后从 832 降至 691
ai-pipeline.ts 857 ≤800 ⚠️ 超限P1 待拆分)
data-access.ts 471 ≤800 P1-2 后从 339 扩展到 471
types.ts 31 无限制
hooks/use-exam-preview.ts 295 ≤500

模块职责边界

  • 职责:考试全生命周期管理(创建/编辑/预览/发布/删除/复制)+ AI 辅助出题
  • 问题getSubjectsAction/getGradesAction 属于 school 模块职责,被放在 exams/actions.ts 中P1-1 待修复)

data-access 层问题

函数 问题 严重程度
getExams 直接查询 classes 表获取教师 gradeIds P1-1 待修复)
getExamById 直接查询 classes 表获取教师 gradeIds P1-1 待修复)
persistAiGeneratedExamDraft 直接 insert 到 questions P1-1 待修复)

actions 层问题 已修复P1-2

exams/actions.ts 中的 DB 操作已下沉到 data-access

已完成修复2026-06-17commit 84d6636

  • 新增 7 个 data-access 函数updateExam / deleteExam / duplicateExam / getExamPreview 等)
  • actions.ts 从 832 行降至 691 行
  • data-access.ts 从 339 行扩展到 471 行
  • actions 层不再有直接 db.insert/update/delete

组件耦合

组件 问题 严重程度
exam-assembly.tsx 调用 getQuestionsActionquestions 模块的 action
8 个组件 导入 Question 类型自 questions/types 低(类型导入合理)
ExamAssembly 10 个 propsexamId, title, subject, grade, difficulty, totalScore, durationMin, initialSelected, initialStructure, questionOptions
ExamPreviewQuestionEditor 10 个 props

ai-pipeline.ts 问题

  • 857 行,超过 800 行建议值(原 912 行,已部分优化)
  • 混合了 Zod schema、AI prompt、JSON 解析修复、题目详情解析、并发控制等多种职责
  • 建议拆分为:ai-schema.tsZod schemaai-prompts.tsprompt 常量)、ai-parser.tsJSON 解析修复)、ai-pipeline.ts核心生成逻辑P1 待处理)

3.2 homework 模块

文件行数

文件 行数 限制 状态
data-access.ts 598 ≤1000 硬上限 P0-2 后从 1038 降至 598
data-access-write.ts 285 ≤800 P1-2 新增10 个写函数)
stats-service.ts 425 ≤800 P0-2 新增,统计业务逻辑)
actions.ts 239 ≤800 P1-2 后从 387 降至 239
schema.ts 29 无限制
types.ts 186 无限制

模块职责边界

  • 职责:作业全生命周期(创建/发布/作答/批改/分析)
  • 问题getStudentDashboardGrades 包含班级排名计算逻辑(已迁移到 stats-service.ts

data-access 层问题(部分修复)

函数 问题 严重程度
getStudentDashboardGrades 150+ 行排名计算业务逻辑混入 data-access 已迁移到 stats-service.ts 已修复
getHomeworkAssignmentAnalytics 145+ 行错误率/错误答案统计业务逻辑混入 data-access 已迁移到 stats-service.ts 已修复
getHomeworkAssignments 直接查询 exams P1-1 待修复)
getHomeworkAssignmentReviewList 直接查询 exams P1-1 待修复)
getHomeworkSubmissions 直接查询 exams P1-1 待修复)
getHomeworkAssignmentById 直接查询 exams P1-1 待修复)
getStudentHomeworkAssignments 直接 join exams/subjects P1-1 待修复)
getDemoStudentUser 直接查询 users/roles/usersToRoles 表 + 使用 auth() 而非 auth-guard P1-1 待修复)
getStudentDashboardGrades 直接查询 classEnrollments/users P1-1 待修复)

actions 层问题 已修复P1-2

homework/actions.ts 中的 DB 操作已下沉到 data-access

已完成修复2026-06-17commit 84d6636

  • 新建 data-access-write.ts285 行10 个写函数)
  • actions.ts 从 387 行降至 239 行
  • createHomeworkAssignmentAction 等 Action 的 DB 操作全部下沉到 data-access-write.ts
  • actions 层不再有直接 db.insert/update/delete

拆分结果 已完成

data-access.ts(原 1038 行)已拆分为:

  • data-access.ts598 行):基础 CRUD + 查询
  • data-access-write.ts285 行写操作10 个写函数)
  • stats-service.ts425 行):统计业务逻辑(排名计算、错误率统计等)

3.3 questions 模块

文件行数

文件 行数 限制 状态
actions.ts 149 ≤800 P1-2 后从 294 降至 149
data-access.ts 260 ≤800 P1-2 后从 129 扩展到 260
schema.ts 18 无限制
types.ts 34 无限制

模块职责边界

  • 职责:题库管理(题目 CRUD、知识点关联、题型支持
  • 问题getKnowledgePointOptionsAction 查询 textbooks 模块的表,属于 textbooks 模块职责P1-1 待修复)

data-access 层问题 已修复P1-2

  • 仅访问 questionsquestionsToKnowledgePoints 表,无跨模块 DB 访问
  • 写操作函数已补全insertQuestionWithRelationsdeleteQuestionRecursive 等 data-access 函数已从 actions.ts 迁移到 data-access.tsdata-access.ts 从 129 行扩展到 260 行)

actions 层问题 已修复P1-2

questions/actions.ts 中的 DB 操作已下沉到 data-access

已完成修复2026-06-17commit 84d6636

  • 新增 4 个 data-access 函数insertQuestionWithRelations / deleteQuestionRecursive 等)
  • actions.ts 从 294 行降至 149 行
  • createNestedQuestion / updateQuestionAction / deleteQuestionAction 的 DB 操作全部下沉
  • actions 层不再有直接 db.transaction

剩余问题

  • getKnowledgePointOptionsAction 仍直接查询 knowledgePoints/chapters/textbooks 表 —— 跨模块 DB 访问P1-1 待修复)

组件耦合

  • 无跨模块依赖

3.4 textbooks 模块(标杆模块)

文件行数

文件 行数 限制 状态
actions.ts 276 ≤800
data-access.ts 428 ≤800
types.ts 79 无限制
hooks/use-knowledge-point-actions.ts 121 ≤500
hooks/use-text-selection.ts - ≤500

模块职责边界

  • 职责:教材与知识体系管理(教材/章节树形结构、知识点 CRUD、Markdown 内容编辑、知识图谱)
  • 职责单一,无越界

data-access 层评价

  • 仅访问 textbookschaptersknowledgePoints
  • 无跨模块 DB 访问
  • 无业务逻辑混入

actions 层评价

  • 标杆实现:所有 action 均遵循"权限校验 → 调用 data-access → revalidatePath → 返回"模式
  • 无直接 DB 访问
  • 无业务逻辑混入

组件耦合

  • knowledge-point-dialogs.tsx 导入 CreateQuestionDialog 自 questions 模块 —— 合理的 UI 组合

hooks 评价

  • useKnowledgePointActions 有 7 个参数textbookId, selectedChapterId, selectedChapterTextbookId, highlightedKpId, setHighlightedKpId, onKpCreated—— 在 8 个限制内

3.5 grades 模块

文件行数

文件 行数 限制 状态
actions.ts 312 ≤800
actions-analytics.ts 133 ≤800
data-access.ts 419 ≤800
data-access-analytics.ts 293 ≤800
data-access-ranking.ts 121 ≤800
export.ts 214 ≤800
schema.ts 52 无限制
types.ts - 无限制

模块职责边界

  • 职责:成绩分析(录入/查询/统计/导出/趋势对比分析)
  • 职责单一,未混入考试/作业逻辑
  • 通过 examId 外键引用考试,通过 type 枚举引用作业类型,未直接依赖 exams/homework 模块的 data-access

data-access 层问题

文件 函数 问题 严重程度
data-access.ts getGradeRecords 直接 join classes/subjects/users
data-access.ts getStudentGradeSummary 直接 join classes/subjects/users
data-access.ts getClassRanking 直接 join users
data-access.ts getClassStudentsForEntry 直接查询 classEnrollments/users 表 —— 应在 classes 模块
data-access.ts getClassGradeStatsWithMeta 直接查询 classes/classEnrollments
data-access.ts getClassGradeStats 统计计算业务逻辑average/median/stdDev/passRate/excellentRate混入 data-access
data-access-analytics.ts getGradeTrend 直接 join classes/subjects
data-access-analytics.ts getClassComparison 直接查询 classes 表 + 统计计算业务逻辑
data-access-analytics.ts getSubjectComparison 直接 join subjects 表 + 统计计算业务逻辑
data-access-analytics.ts getGradeDistribution 分桶统计业务逻辑混入 data-access
data-access-ranking.ts getRankingTrend 直接查询 classEnrollments/users 表 + 排名计算业务逻辑
export.ts exportClassGradeReportToExcel 直接查询 classes/subjects/users 表 + 排名计算业务逻辑

actions 层评价

  • 标杆实现actions.tsactions-analytics.ts 均遵循"权限校验 → 调用 data-access → 返回"模式
  • 无直接 DB 访问
  • 无业务逻辑混入

组件耦合

  • 无跨模块依赖

四、跨模块直接 DB 访问汇总

以下为违反模块封装原则的直接数据库查询,应改为通过对方模块的 data-access 函数调用。

4.1 按来源模块分类

来源模块 文件 被访问的表 应调用的模块
exams data-access.ts classes classes/data-access
exams data-access.ts questionsinsert questions/data-access
exams actions.ts subjects, grades school/data-access
homework actions.ts classes, classSubjectTeachers, exams, classEnrollments classes/data-access, exams/data-access
homework data-access.ts exams, classEnrollments, subjects, users, roles, usersToRoles exams/data-access, classes/data-access, school/data-access
questions actions.ts knowledgePoints, chapters, textbooks textbooks/data-access
grades data-access.ts classes, classEnrollments, subjects, users classes/data-access, school/data-access
grades data-access-analytics.ts classes, subjects classes/data-access, school/data-access
grades data-access-ranking.ts classEnrollments, users classes/data-access
grades export.ts classes, subjects, users classes/data-access, school/data-access

4.2 按被访问表分类(频次)

被访问表 访问次数 应归属模块
classes 8+ classes
classEnrollments 6+ classes
users 6+ users
subjects 6+ school
exams 5+ exams
grades(年级表) 1 school
classSubjectTeachers 1 classes
knowledgePoints 1 textbooks
chapters 1 textbooks
textbooks 1 textbooks
roles, usersToRoles 1 users
questionsinsert 1 questions

五、改进建议

5.1 高优先级P0

  1. 拆分 homework/data-access.ts1038 行 → 4 个文件) 已完成

    • 按职责拆分为 data-access.ts / data-access-student.ts / data-access-analytics.ts / data-access-grading.ts
    • 实际拆分为 data-access.ts598 行)+ data-access-write.ts285 行)+ stats-service.ts425 行)
  2. 消除跨模块直接 DB 访问P1-1 待修复)

    • 在 classes/data-access 暴露 getClassGradeIdsByClassIdsgetClassStudentsByClassIdgetActiveClassStudents 等函数
    • 在 exams/data-access 暴露 getExamForHomeworkCreation(含 questions 关联)
    • 在 school/data-access 暴露 getSubjectOptionsgetGradeOptions
    • 在 users/data-access 暴露 getUserNameByIdsgetStudentInfo
    • 在 textbooks/data-access 暴露 getKnowledgePointOptions
    • 在 questions/data-access 暴露 insertQuestionWithRelationsdeleteQuestionRecursive
  3. 将 exams/actions.ts 中的 DB 操作下沉到 data-access 已完成P1-2

    • updateExamActiondeleteExamActionduplicateExamActiongetExamPreviewAction 的 DB 操作移至 data-access
    • getSubjectsAction/getGradesAction 移至 school 模块或改为调用 school/data-accessP1-1 待修复)
  4. 将 homework/actions.ts 中的 DB 操作下沉到 data-access 已完成P1-2

    • createHomeworkAssignmentAction157 行拆分为data-access 函数 + action 编排
    • 其他 action 的 DB 操作全部移至 data-access
  5. 将 questions/actions.ts 中的 DB 操作下沉到 data-access 已完成P1-2

    • insertQuestionWithRelationsdeleteQuestionRecursive 移至 data-access
    • getKnowledgePointOptionsAction 改为调用 textbooks/data-accessP1-1 待修复)

5.2 中优先级P1

  1. 拆分 exams/ai-pipeline.ts857 行 → 4 个文件)

    • ai-schema.tsZod schema、ai-prompts.tsprompt 常量、ai-parser.tsJSON 解析修复、ai-pipeline.ts核心生成逻辑
  2. 将 homework/data-access.ts 中的业务逻辑提取到独立服务层 已完成

    • getStudentDashboardGrades 的排名计算逻辑提取到 services/ranking-service.ts → 实际提取到 stats-service.ts
    • getHomeworkAssignmentAnalytics 的错误率统计逻辑提取到 services/analytics-service.ts → 实际提取到 stats-service.ts
  3. 将 grades/data-access.ts 中的统计计算逻辑提取到独立服务层P1 待处理)

    • getClassGradeStats 的统计计算提取到 services/stats-service.ts
    • getGradeDistribution 的分桶逻辑提取到 services/distribution-service.ts
  4. 减少组件 props 数量P2 待处理)

    • ExamAssembly10 propsExamPreviewQuestionEditor10 props应考虑使用 Context 或组合模式减少 props

5.3 低优先级P2

  1. 统一 auth 调用方式P2 待处理)

    • homework/data-access.tsgetDemoStudentUser 使用 auth() 而非 auth-guard.getAuthContext(),应统一
  2. 补全 questions/data-access.ts 的写操作 已完成P1-2

    • 当前 data-access 仅有 getQuestions,所有写操作错放在 actions.ts → 写操作已下沉到 data-access

六、标杆模块推荐

模块 推荐参考点
textbooks actions 层编排模式(权限校验 → 调用 data-access → revalidatePath
textbooks data-access 层职责单一(仅访问本模块表,无业务逻辑)
grades actions 层拆分actions.ts + actions-analytics.ts 按职责分文件)
grades data-access 层拆分data-access.ts + data-access-analytics.ts + data-access-ranking.ts
grades 跨模块解耦(通过外键引用 exams/homework不直接访问其表

七、审查方法说明

  • 审查范围5 个核心业务模块的 actions/data-access/schema/types/components/hooks 全量文件
  • 审查工具:源码全量阅读 + Grep 跨模块依赖扫描 + PowerShell 行数统计
  • 审查依据:项目规则中"Server Action 必须使用 requirePermission()"、"单文件行数规范"、"模块职责单一"等规则
  • 未覆盖项:未运行 lint/typecheck本次为只读审查不修改代码未审查组件内部实现细节仅审查 props 数量和跨模块依赖)