Files
NextEdu/docs/architecture/audit/new-and-other-modules-audit.md

28 KiB
Raw Blame History

新增模块与其他模块架构审查报告

审查范围elective / proctoring / diagnostic / notifications / dashboard / messaging / parent / settings / files / auth / layout / student 审查日期2026-06-17 审查依据:源码全量扫描 + 架构影响地图(004/005) + 差距审计报告(007) 审查目标:识别职责不单一、过耦合、边界模糊、幽灵路由等问题


一、总体评估

维度 模块数 严重问题 中等问题 轻微问题 总体评价
新增模块 4 3 5 3 ⚠️ 职责基本清晰,但存在跨模块耦合与未集成代码
其他模块 8 1 4 3 ⚠️ dashboard 跨模块直查问题突出
合计 12 4 9 6 需重点修复 4 项严重问题

严重问题清单(必须修复)

  1. messaging 与 notifications 边界模糊、双向依赖 — 两个模块都写入 messageNotificationsnotifications 反向依赖 messaging类型系统不一致 已修复P0-5 + P1-6
  2. dashboard/data-access.ts 直查 11 张跨模块表 — 违反模块封装原则 已修复P0-4
  3. proctoring/exam-mode-config.tsx 未集成到考试表单 — DB schema 有 examMode 等字段但无 UI 录入入口,组件成为死代码 ⚠️ 用户决定保留
  4. proctoring 事件上报存在 Server Action 与 REST API 双通道重复 — 同一逻辑两份代码

二、新增模块审查

2.1 elective 模块(选课管理)

模块结构

文件 行数 职责
actions.ts 304 11 个 Server ActionCRUD + 选课 + 抽签 + 查询)
data-access.ts 242 课程 CRUD + 查询 + scope 过滤
data-access-operations.ts 217 选课操作select/drop/lottery
data-access-selections.ts 189 选课记录查询 + 学生可用课程查询
schema.ts 132 Zod 校验 schema
types.ts 108 类型定义 + 标签常量

拆分为 3 个 data-access 文件是否合理?

结论:⚠️ 拆分意图合理,但存在代码重复

  • 拆分意图合理operations写操作与 selections读查询职责分明符合"按职责划分"原则
  • 代码重复问题data-access.tsdata-access-selections.ts 重复定义了 mapCourseRowbuildCourseSelect 两个函数(共约 60 行重复代码)
    • data-access.ts 第 47-108 行
    • data-access-selections.ts 第 28-88 行
    • 两份代码完全相同,维护时易产生不一致

建议

  • 抽取共享的 mapCourseRow / buildCourseSelectdata-access.ts 并导出,data-access-selections.ts 复用
  • 或合并 data-access-selections.tsdata-access.ts(文件仅 189 行,合并后仍在 800 行上限内)

权限校验

全部 Server Action 均使用 requirePermission

  • 管理 Action 使用 ELECTIVE_MANAGE
  • 选课 Action 使用 ELECTIVE_SELECT
  • 查询 Action 使用 ELECTIVE_READ
  • 学生查看他人选课记录有额外 dataScope 校验actions.ts 第 283-288 行)

其他发现

  • schema.ts 使用 Zod transform 统一处理空字符串转 null规范
  • ⚠️ data-access-operations.tsrunLottery 使用 Math.random() 排序(第 40 行),结果不可复现,建议改用 DB 的 ORDER BY RAND() 或记录种子
  • ⚠️ selectCourse 在 FCFS 模式下先查后写(第 119-128 行),存在并发超卖风险,建议加事务或乐观锁

2.2 proctoring 模块(考试监考)

模块结构

文件 行数 职责
actions.ts 144 2 个 Server Action上报事件 + 获取面板)
data-access.ts 388 事件记录 + 查询 + 摘要统计 + 学生状态
types.ts 136 类型定义 + 标签常量 + 阈值常量
components/anti-cheat-monitor.tsx - 学生端防作弊监控
components/exam-mode-config.tsx - 考试模式配置表单(未集成
components/proctoring-dashboard.tsx - 教师监考面板

职责清晰度

结论:⚠️ 职责基本清晰,但存在 3 个严重问题

严重问题 1exam-mode-config.tsx 未集成到考试表单(死代码)⚠️ 用户决定保留

  • DB schema 已有 examMode / durationMinutes / shuffleQuestions / allowLateStart / antiCheatEnabled 字段schema.ts 第 457-462 行)
  • proctoring/components/exam-mode-config.tsx 提供了完整的配置 UI 组件
  • exams/components/exam-form.tsx 并未导入该组件grep 确认无 ExamModeConfig 引用)
  • exams/components/exam-mode-selector.tsx 是"手动组卷 vs AI 生成"的选择器,与考试模式homework/timed/proctored无关,命名易混淆
  • 结果创建考试时无法设置监考模式proctoring 模块的 getExamForProctoring 读取的 examMode 永远是默认值 "homework"

状态:用户决定保留该组件,暂不集成也不删除。后续如需启用监考功能,可再集成到 exam-form.tsx

严重问题 2事件上报存在 Server Action 与 REST API 双通道重复

  • proctoring/actions.ts 第 58-105 行:recordProctoringEventActionServer Action
  • app/api/proctoring/event/route.ts 第 27-90 行POST handlerREST API
  • 两者逻辑完全相同:都校验 submission 归属、调用 recordProctoringEvent
  • AntiCheatMonitor 组件使用 Server Action第 58 行REST API 路由无调用方

建议:删除未使用的 /api/proctoring/event 路由,或让组件改用 REST API适用于客户端轮询场景

中等问题 3跨模块读取 exams 表

  • data-access.ts 第 326-353 行:getExamForProctoring 直接查询 exams
  • 第 178-185 行:getExamProctoringSummary 直接查询 examSubmissions
  • 第 249-256 行:getStudentProctoringStatuses 直接 join examSubmissionsusers

建议:可接受(监考本质是考试模块的扩展),但应在架构图中标注依赖关系

其他发现

  • recordProctoringEventAction 使用 requireAuth() 而非 requirePermission,符合"学生上报自己事件"场景
  • getProctoringDashboardAction 使用 EXAM_PROCTOR 权限
  • 异常阈值 ABNORMAL_EVENT_THRESHOLD = 3 提取为常量,便于调整
  • ⚠️ actions.ts 第 11-13 行直接 import dbexamSubmissions,应在 data-access 层封装 submission 校验逻辑

2.3 diagnostic 模块(学情诊断)

模块结构

文件 行数 职责
actions.ts 148 6 个 Server Action生成/发布/删除/查询报告)
data-access.ts 254 知识点掌握度查询 + 从提交更新掌握度
data-access-reports.ts 202 诊断报告 CRUD
types.ts 97 类型定义
components/ 4 个 学生/班级诊断视图 + 雷达图 + 报告列表

与 grades 模块的边界

结论: 无职责重叠,但存在跨模块耦合

  • grades 模块:管理 gradeRecords 表(分数记录),维度是"学生-班级-科目-考试"
  • diagnostic 模块:管理 knowledgePointMastery 表(知识点掌握度),维度是"学生-知识点"
  • 两者数据来源不同grades 是教师录入的分数diagnostic 是从 submissionAnswers 推导的正确率
  • 无任何代码重叠grep 确认 grades 模块无 knowledgePoint / mastery / diagnostic 关键字

中等问题 1data-access.ts 跨模块直查 4 张表

  • 第 87-92 行:查询 examSubmissions 表(属 exams 模块)
  • 第 95-101 行:查询 submissionAnswers 表(属 exams/homework 模块)
  • 第 106-112 行:查询 questionsToKnowledgePoints 表(属 questions 模块)
  • 第 150-158 行:查询 classEnrollments + classes + users 表(属 classes 模块)

updateMasteryFromSubmission 函数(第 87-147 行)直接读取提交答案和题目-知识点关联,将 diagnostic 模块与 exams/homework/questions 模块紧耦合。

建议

  • 短期:在架构图中标注此依赖关系
  • 长期:由 exams/homework 模块在提交评分后主动调用 diagnostic 模块的更新接口(事件驱动)

轻微问题 2data-access-reports.ts 有未使用代码

  • 第 20 行定义 round2 函数
  • 第 201 行 void round2 仅为消除 lint 警告
  • 建议:删除未使用的 round2 函数

轻微问题 3班级报告字段复用不当

  • data-access-reports.ts 第 107 行:studentId: generatedBy — 班级报告将生成者 ID 存入 studentId 字段
  • 注释说明"schema 要求 NOT NULL",但这是 schema 设计缺陷的 workaround
  • 建议:修改 learningDiagnosticReports schemastudentId 改为可空,或增加 classId 字段

权限校验

全部 Action 使用 DIAGNOSTIC_MANAGEDIAGNOSTIC_READ 权限


2.4 notifications 模块(通知分发)

模块结构

文件 行数 职责
actions.ts 119 2 个 Server Action单发 + 班级群发)
data-access.ts 86 用户偏好 + 联系方式 + 日志
dispatcher.ts 152 渠道选择 + 并行分发
types.ts 70 通知负载 + 渠道配置类型
index.ts 38 对外导出入口
channels/ 5 个 SMS/Email/WeChat/InApp 渠道实现

严重问题 1与 messaging 模块双向依赖、边界模糊 已修复

详见下文"三、messaging vs notifications 边界分析"。

已完成修复2026-06-17P0-5 + P1-6

  • messaging/actions.ts 改用 sendNotification from @/modules/notifications/dispatcherP0-5
  • notifications/channels/in-app-channel.ts 将静态 import 改为动态 await import("@/modules/messaging/data-access")打破模块级静态反向依赖P1-6
  • 依赖方向已统一messaging → notifications单向

中等问题 2sendClassNotificationAction 跨模块直查

  • actions.ts 第 83-96 行:直接查询 classesclassEnrollments
  • 应通过 classes 模块的 data-access 获取班级学生列表

建议:调用 classes 模块的 data-access 函数获取学生 ID 列表

中等问题 3发送日志仅 console 输出

  • data-access.ts 第 71-77 行:logNotificationSend 使用 console.info
  • 代码注释承认"当前项目无 notification_logs 表"
  • 影响:无法查询历史发送记录、无法统计发送成功率、无法排查发送失败

建议:新增 notification_logs 表,记录 channel/userId/payload/success/error/sentAt

轻微问题 4复用 MESSAGE_SEND 权限

  • actions.ts 第 34、67 行:使用 Permissions.MESSAGE_SEND
  • 代码注释说明"项目无独立 NOTIFICATION_SEND 权限点"
  • 影响:无法单独控制"谁能发通知"vs"谁能发私信"

建议:新增 NOTIFICATION_SEND 权限点,或确认复用是设计意图

设计亮点

  • 渠道抽象优秀:NotificationChannelSender 接口 + 工厂函数,新增渠道只需实现接口
  • Mock 实现完善SMS/Email/WeChat 均有 Mock 实现,开发环境零配置可用
  • 动态 import 第三方 SDK阿里云/腾讯云/nodemailer避免增加构建体积
  • 渠道选择逻辑清晰dispatcher.ts 第 59-95 行)

三、messaging vs notifications 边界分析(重点) 已修复

状态:双向依赖与绕过 dispatcher 问题已于 2026-06-17 修复P0-5 + P1-6。以下为修复前的现状记录保留作为历史参考。

3.1 现状对比(修复前)

维度 messaging 模块 notifications 模块
核心职责 站内私信 + 站内通知列表 多渠道通知分发
管理的表 messages + messageNotifications + notificationPreferences 无独有表(借用 messaging 的表)
写入 messageNotifications 直接写(createNotification 通过 in-app 渠道写
通知类型枚举 NotificationType = "message" | "announcement" | "homework" | "grade" NotificationPayload.type = "info" | "warning" | "error" | "success"
UI 组件 message-list / message-detail / message-compose / notification-dropdown / notification-list 无 UI 组件
偏好管理 notification-preferences.ts 借用 messaging 的
渠道支持 仅站内 站内 + SMS + Email + WeChat

3.2 严重问题:双向依赖与职责重叠 已修复

问题 1notifications 反向依赖 messaging 已修复

notifications/data-access.ts ~~ → import { getNotificationPreferences } from "@/modules/messaging/notification-preferences"~~ ~~ → import type { NotificationPreferences } from "@/modules/messaging/types"~~

notifications/channels/in-app-channel.ts ~~ → import { createNotification } from "@/modules/messaging/data-access"~~

修复方案notifications/channels/in-app-channel.ts 将静态 import 改为动态 await import("@/modules/messaging/data-access"),打破模块级静态反向依赖。运行时调用链保持不变,但模块加载图无环。

问题 2messaging 绕过 notifications 直接写通知 已修复

messaging/actions.ts 第 66-72 行:

// ~~Notify the receiver about the new message~~
// ~~await createNotification({~~
// ~~  userId: input.receiverId,~~
// ~~  type: "message",~~
// ~~  ...~~
// ~~})~~

修复方案messaging/actions.ts 改用 sendNotification from @/modules/notifications/dispatcher,通知现在会经过 dispatcher 的渠道选择逻辑尊重用户偏好SMS/Email/WeChat/In-App

问题 3类型系统不一致保留

  • messaging/types.ts 第 23 行:NotificationType = "message" | "announcement" | "homework" | "grade"(按业务类别)
  • notifications/types.ts 第 20 行:type: "info" | "warning" | "error" | "success"(按严重级别)
  • in-app-channel.ts 第 49 行:type: payload.type as "message" | "announcement" | "homework" | "grade"强制类型转换,运行时可能写入非法值

DB schema 中 messageNotifications.typevarchar(128)虽然不会报错但语义混乱。P2 待统一)

问题 4notification-preferences 归属不清(保留)

  • notificationPreferences 表的 data-access 在 messaging 模块
  • 但 notifications 模块的 dispatcher 依赖此偏好决定渠道
  • settings 模块的 notification-preferences-form.tsx 调用 messaging/actions.tsupdateNotificationPreferencesAction
  • 三个模块都在操作同一份数据职责归属不清P2 待重构)

3.3 建议方案

方案 A推荐notifications 吞并 messaging 的通知部分

  1. messageNotifications 表和 notificationPreferences 表的所有权移交给 notifications 模块
  2. messaging 模块仅保留 messages 表(私信)
  3. messaging 的 sendMessageAction 改为调用 notifications.sendNotification
  4. messaging 的 UI 组件notification-dropdown / notification-list迁移到 notifications 模块
  5. 统一 NotificationType 枚举,支持业务类别 + 严重级别两个维度

方案 B保持现状明确依赖方向

  1. 在架构图中标注 notifications → messaging 的单向依赖
  2. messaging 不再直接调用 createNotification,改为调用 notifications.sendNotification
  3. 消除双向依赖,但 notifications 仍不拥有数据

四、dashboard 模块审查(重点)

4.1 严重问题:data-access.ts 直查 11 张跨模块表 已修复

dashboard/data-access.tsgetAdminDashboardData 函数直接查询以下表

已完成修复2026-06-17P0-4dashboard/data-access.ts 从大文件降至 42 行,改为并行调用 6 个模块的 stats 函数:

const [usersStats, classesStats, textbooksStats, questionsStats, examsStats, homeworkStats] = await Promise.all([
  getUsersDashboardStats(),
  getClassesDashboardStats(),
  getTextbooksDashboardStats(),
  getQuestionsDashboardStats(),
  getExamsDashboardStats(scope),
  getHomeworkDashboardStats(scope),
])

不再直接查询任何业务表,完全通过各模块 data-access 暴露的聚合查询函数获取数据。

4.2 学生/教师仪表盘的对比

学生仪表盘app/(dashboard)/student/dashboard/page.tsx

  • 正确做法:调用 classes/data-accessgetStudentClasses / getStudentSchedule
  • 调用 homework/data-accessgetStudentDashboardGrades / getStudentHomeworkAssignments
  • 不直接查询任何表

教师仪表盘app/(dashboard)/teacher/dashboard/page.tsx

  • 调用 classes/data-accessgetClassSchedule / getTeacherClasses
  • 调用 homework/data-accessgetHomeworkAssignments / getHomeworkSubmissions / getTeacherGradeTrends
  • ⚠️ 第 18-21 行直接查询 users 表获取教师姓名:db.query.users.findFirst(...) — 应使用 users 模块的 data-access

4.3 建议方案

方案 A理想聚合 API 模式

为每个模块添加 getModuleStats(scope?) 函数dashboard 聚合调用:

const [userStats, classStats, textbookStats, ...] = await Promise.all([
  getUsersStats(scope),
  getClassStats(scope),
  getTextbookStats(),
  ...
])

方案 B务实接受 dashboard 作为跨模块聚合层

  • 在架构图中明确标注 dashboard 对所有业务模块的依赖
  • 将 scope 过滤逻辑下沉到各模块的 getStats 函数
  • 至少消除 dashboard 中重复实现的 exam/homework scope 过滤(第 31-73 行)

五、其他模块审查

5.1 messaging 模块

模块结构

文件 行数 职责
actions.ts 245 9 个 Server Action私信 + 通知 + 偏好)
data-access.ts 252 私信 CRUD + 通知 CRUD + 收件人查询
notification-preferences.ts 166 通知偏好 CRUD
schema.ts 17 私信发送校验
types.ts 108 私信 + 通知 + 偏好类型

问题

  • 职责过多同时管理私信messages、站内通知messageNotifications、通知偏好notificationPreferences三类数据
  • 与 notifications 模块边界模糊:详见第三节
  • ⚠️ getRecipients 函数(第 227-251 行)根据 dataScope 查询收件人,逻辑较复杂,可考虑下沉到 users 模块

5.2 parent 模块

模块结构

文件 行数 职责
data-access.ts 234 子女关系 + 子女仪表盘数据聚合
types.ts 57 类型定义
components/ 7 个 子女卡片 + 详情 + 仪表盘

评价

  • 职责单一:仅负责家长视角的子女数据聚合与展示
  • 正确复用其他模块
    • 调用 classes/data-accessgetStudentClasses / getStudentSchedule
    • 调用 homework/data-accessgetStudentDashboardGrades / getStudentHomeworkAssignments
    • 调用 grades/data-accessgetStudentGradeSummary
  • 不直接查询业务表(仅查询 parentStudentRelations 自有表 + users/classes/classEnrollments/grades 用于基本信息)
  • ⚠️ getChildBasicInfo 第 74-105 行多次串行查询grade → class可优化为 join

5.3 settings 模块

模块结构

文件 行数 职责
actions.ts 205 AI Provider CRUD + 测试连通性
actions-password.ts 113 修改密码
components/ 8 个 通用设置 + AI 配置 + 密码 + 主题 + 通知偏好

问题:职责混杂但可接受

settings 模块混合了 5 类职责:

  1. AI Provider 管理(actions.ts + ai-provider-settings-card.tsx
  2. 密码修改(actions-password.ts + password-change-form.tsx
  3. 个人资料(profile-settings-form.tsx
  4. 主题偏好(theme-preferences-card.tsx
  5. 通知偏好表单(notification-preferences-form.tsx调用 messaging 模块的 Action

评价

  • ⚠️ AI Provider 管理与"用户设置"语义距离较远,可考虑独立为 ai-config 模块
  • ⚠️ notification-preferences-form.tsx 第 14 行 import updateNotificationPreferencesAction from @/modules/messaging/actions — 跨模块 UI 依赖
  • 密码修改有速率限制(actions-password.ts 第 33-37 行)
  • AI Provider 操作有 AI_CONFIGURE 权限校验
  • 密码修改仅要求 requireAuth()(自助操作),符合最小权限原则
  • ⚠️data-access.ts 文件,actions.ts 直接使用 db — 建议抽取 data-access 层

5.4 files 模块

模块结构

文件 行数 职责
data-access.ts 267 文件附件 CRUD + 批量删除 + 统计
types.ts - 类型定义
components/ 6 个 上传 + 列表 + 预览 + 管理

评价

  • 职责单一:仅管理 fileAttachments
  • 不跨模块查询
  • 批量删除有容错处理(第 152-177 行,失败时回退到逐条删除)
  • ⚠️ 所有函数都用 try-catch 吞掉错误返回空数组/null可能掩盖真实问题
  • ⚠️ 无 actions.ts 文件 — 文件上传通过 app/api/upload/route.tsapp/api/files/[id]/route.ts 实现data-access 被路由直接调用

5.5 auth 模块

模块结构

文件 职责
components/auth-layout.tsx 认证页面布局
components/login-form.tsx 登录表单
components/register-form.tsx 注册表单

评价

  • 纯 UI 模块:无 data-access / actions / types 文件
  • 认证逻辑由 NextAuth + shared/lib/auth-guard 统一处理
  • 职责清晰

5.6 layout 模块

模块结构

文件 职责
components/app-sidebar.tsx 侧边栏(根据权限渲染导航)
components/sidebar-provider.tsx 侧边栏状态 Context
components/site-header.tsx 顶部导航(含通知下拉)
config/navigation.ts 导航配置4 个角色)

navigation.ts 幽灵路由审查

结论: 无幽灵路由007 报告中提到的 13 个幽灵路由已全部修复)

逐一核对导航配置中的所有 href 与 src/app/ 下的实际页面:

角色 导航项数 全部存在 备注
admin 19 包括子菜单项
teacher 22 包括子菜单项
student 12 包括子菜单项
parent 5 包括子菜单项

存在但未纳入导航的页面

路由 说明 建议
/admin/attendance 管理员考勤页面 如需管理员查看全校考勤,应加入 admin 导航
/admin/files 管理员文件管理 应加入 admin 导航
/parent/children/[studentId] 子女详情页 通过仪表盘卡片跳转,可不加入导航
/settings/security 安全设置子页 通过 settings 页 Tab 切换,无需独立导航
/profile 个人主页 通过 header 头像菜单跳转,无需独立导航

其他发现

  • app-sidebar.tsx 第 36-43 行根据权限动态选择角色导航配置,符合 RBAC
  • ⚠️ 第 39 行判断学生逻辑:permissions.includes(Permissions.HOMEWORK_SUBMIT) && !permissions.includes(Permissions.EXAM_CREATE) — 用权限反推角色,不够直观,建议改用 hasRole("student")

5.7 student 模块

模块结构

文件 职责
components/student-courses-view.tsx 学生课程视图
components/student-schedule-filters.tsx 课表筛选器
components/student-schedule-view.tsx 学生课表视图

评价

  • 纯 UI 模块:无 data-access / actions / types
  • 数据由 app/(dashboard)/student/learning/courses/page.tsxapp/(dashboard)/student/schedule/page.tsx 通过 classes 模块的 data-access 获取
  • ⚠️ 与 classes 模块的 schedule-view.tsx / schedule-filters.tsx 可能存在功能重叠,建议核查

六、跨模块依赖关系图

dashboard ──直查──> users, classes, textbooks, questions, exams, homework (11 张表)
parent ──调用──> classes, homework, grades (data-access)
diagnostic ──直查──> examSubmissions, submissionAnswers, questionsToKnowledgePoints, classes
notifications ──依赖──> messaging (偏好 + in-app 渠道)
messaging ──绕过──> notifications (直接写 messageNotifications)
proctoring ──直查──> exams, examSubmissions, users
settings ──调用──> messaging (通知偏好 Action)

七、修复优先级

P0严重应立即修复

序号 问题 模块 工作量 影响 状态
1 messaging 绕过 notifications 直接写通知 messaging 用户通知偏好失效,多渠道通知无效 已修复P0-5
2 proctoring/exam-mode-config.tsx 未集成 proctoring 监考功能无法启用,组件为死代码 ⚠️ 用户决定保留
3 proctoring 事件上报双通道重复 proctoring 代码重复,维护成本 待修复
4 notifications 反向依赖 messaging notifications 架构耦合,难以独立演进 已修复P1-6

P1中等问题下个迭代修复

序号 问题 模块 工作量 状态
5 dashboard 直查 11 张跨模块表 dashboard 已修复P0-4
6 diagnostic 跨模块直查 4 张表 diagnostic 待修复
7 notifications 无 notification_logs 表 notifications 待修复
8 sendClassNotificationAction 直查 classes 表 notifications 待修复
9 elective 两个 data-access 文件代码重复 elective 待修复
10 settings/notification-preferences-form 跨模块依赖 settings 待修复

P2轻微问题机会修复

序号 问题 模块
11 diagnostic/data-access-reports.ts 有未使用代码 diagnostic
12 diagnostic 班级报告 studentId 字段复用 diagnostic
13 elective runLottery 使用 Math.random elective
14 teacher dashboard 直查 users 表 dashboard
15 files 模块 try-catch 吞错误 files
16 layout 用权限反推角色 layout

八、总结

新增模块质量

  • elective 质量较好,拆分合理但有代码重复
  • proctoring⚠️ 有死代码exam-mode-config 未集成,用户决定保留)和重复实现(双通道上报)
  • diagnostic 与 grades 无重叠,但跨模块耦合较重
  • notifications 渠道抽象优秀,与 messaging 的双向依赖已修复P0-5 + P1-6

重点问题回答

  1. elective 拆分为 3 个 data-access 文件是否合理? 合理,但需消除 data-access.tsdata-access-selections.ts 之间的代码重复

  2. proctoring 模块职责是否清晰? 基本清晰,但 exam-mode-config.tsx 应属于 exams 模块或集成到考试表单(用户决定保留)

  3. diagnostic 与 grades 是否有职责重叠? 无重叠。grades 管分数记录diagnostic 管知识点掌握度,数据来源和维度均不同

  4. notifications 与 messaging 边界是否清晰? 已修复。双向依赖通过动态 import 打破messaging 改用 notifications/dispatcher 发送通知,依赖方向统一为 messaging → notifications

  5. dashboard 是否直查其他模块的表? 已修复。getAdminDashboardData 改为并行调用各模块的 get[Module]DashboardStats() 函数,不再直接查询任何业务表

  6. settings 是否混入太多职责? 混合了 5 类职责,但作为"设置"聚合点尚可接受。AI Provider 管理可考虑独立

  7. navigation.ts 是否有幽灵路由? 无。007 报告中的 13 个幽灵路由已全部修复