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

601 lines
28 KiB
Markdown
Raw 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.
# 新增模块与其他模块架构审查报告
> 审查范围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 边界模糊、双向依赖** — 两个模块都写入 `messageNotifications` 表notifications 反向依赖 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.ts``data-access-selections.ts` 重复定义了 `mapCourseRow``buildCourseSelect` 两个函数(共约 60 行重复代码)
- `data-access.ts` 第 47-108 行
- `data-access-selections.ts` 第 28-88 行
- 两份代码完全相同,维护时易产生不一致
**建议**
- 抽取共享的 `mapCourseRow` / `buildCourseSelect``data-access.ts` 并导出,`data-access-selections.ts` 复用
- 或合并 `data-access-selections.ts``data-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.ts``runLottery` 使用 `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 个严重问题**
#### 严重问题 1`exam-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 行:`recordProctoringEventAction`Server 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 `examSubmissions``users`
**建议**:可接受(监考本质是考试模块的扩展),但应在架构图中标注依赖关系
#### 其他发现
-`recordProctoringEventAction` 使用 `requireAuth()` 而非 `requirePermission`,符合"学生上报自己事件"场景
-`getProctoringDashboardAction` 使用 `EXAM_PROCTOR` 权限
- ✅ 异常阈值 `ABNORMAL_EVENT_THRESHOLD = 3` 提取为常量,便于调整
- ⚠️ `actions.ts` 第 11-13 行直接 import `db``examSubmissions`,应在 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` 关键字
#### 中等问题 1`data-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 模块的更新接口(事件驱动)
#### 轻微问题 2`data-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` schema`studentId` 改为可空,或增加 `classId` 字段
#### 权限校验
✅ 全部 Action 使用 `DIAGNOSTIC_MANAGE``DIAGNOSTIC_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/dispatcher`P0-5
- notifications/channels/in-app-channel.ts 将静态 import 改为动态 `await import("@/modules/messaging/data-access")`打破模块级静态反向依赖P1-6
- 依赖方向已统一messaging → notifications单向
#### 中等问题 2`sendClassNotificationAction` 跨模块直查
- `actions.ts` 第 83-96 行:直接查询 `classes``classEnrollments`
- 应通过 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 行:~~
```typescript
// ~~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.type``varchar(128)`虽然不会报错但语义混乱。P2 待统一)
#### 问题 4notification-preferences 归属不清(保留)
- `notificationPreferences` 表的 data-access 在 messaging 模块
- 但 notifications 模块的 dispatcher 依赖此偏好决定渠道
- settings 模块的 `notification-preferences-form.tsx` 调用 `messaging/actions.ts``updateNotificationPreferencesAction`
- 三个模块都在操作同一份数据职责归属不清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.ts` 的 `getAdminDashboardData` 函数直接查询以下表~~
**已完成修复**2026-06-17P0-4dashboard/data-access.ts 从大文件降至 42 行,改为并行调用 6 个模块的 stats 函数:
```typescript
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-access``getStudentClasses` / `getStudentSchedule`
- ✅ 调用 `homework/data-access``getStudentDashboardGrades` / `getStudentHomeworkAssignments`
- ✅ 不直接查询任何表
**教师仪表盘**`app/(dashboard)/teacher/dashboard/page.tsx`
- ✅ 调用 `classes/data-access``getClassSchedule` / `getTeacherClasses`
- ✅ 调用 `homework/data-access``getHomeworkAssignments` / `getHomeworkSubmissions` / `getTeacherGradeTrends`
- ⚠️ 第 18-21 行直接查询 `users` 表获取教师姓名:`db.query.users.findFirst(...)` — 应使用 users 模块的 data-access
### 4.3 建议方案
**方案 A理想聚合 API 模式**
为每个模块添加 `getModuleStats(scope?)` 函数dashboard 聚合调用:
```typescript
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-access``getStudentClasses` / `getStudentSchedule`
- 调用 `homework/data-access``getStudentDashboardGrades` / `getStudentHomeworkAssignments`
- 调用 `grades/data-access``getStudentGradeSummary`
- ✅ 不直接查询业务表(仅查询 `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.ts``app/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.tsx``app/(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.ts``data-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 个幽灵路由已全部修复