Files
NextEdu/docs/architecture/audit/new-and-other-modules-audit.md
SpecialX f8dfd1dddd docs: 全项目架构审查与文档体系重写
- 全项目逐文件审查: 4 份审计报告(shared/core-business/management/new-modules)
- 重写 004 架构影响地图: 图优先 + 模块依赖图 + 数据流 + 调用链 + 问题分级
- 更新 005 结构化数据: 新增 architectureOverview/moduleDependencyGraph/knownIssues/dbTables 节点
- 更新 006 功能清单: 143 项功能标注实现状态, P0 覆盖率 80%->92%
- 更新 007 差距审计: v2->v3, P0 完成 69%->84%, 新增架构技术债章节
- 更新 001 项目概览: 6 角色/54 权限/26 模块/54 表
- 新增 docs/README.md 文档索引
- 归档 11 份过时文档(002x2/003/designx8) 标注
- 更新 work_log
2026-06-17 21:51:32 +08:00

605 lines
27 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类型系统不一致
2. **dashboard/data-access.ts 直查 11 张跨模块表** — 违反模块封装原则
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-mode-config.tsx` 集成到 `exam-form.tsx`,或迁移到 exams 模块
#### 严重问题 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 边界分析"。
#### 中等问题 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 边界分析(重点)
### 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 模块不拥有任何数据,全部依赖 messaging 模块。这违背了"模块应拥有自己的数据"原则。
#### 问题 2messaging 绕过 notifications 直接写通知
`messaging/actions.ts` 第 66-72 行:
```typescript
// Notify the receiver about the new message
await createNotification({
userId: input.receiverId,
type: "message",
title: input.subject ? `New message: ${input.subject}` : "New message",
content: input.content.slice(0, 200),
link: `/messages/${id}`,
})
```
这直接调用 `messaging/data-access.ts``createNotification`**完全绕过 notifications 模块的 dispatcher**,导致:
- 用户设置的 SMS/Email 偏好被忽略
- 新消息不会触发邮件/短信提醒
- notifications 模块的多渠道能力形同虚设
#### 问题 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)`,虽然不会报错,但语义混乱。
#### 问题 4notification-preferences 归属不清
- `notificationPreferences` 表的 data-access 在 messaging 模块
- 但 notifications 模块的 dispatcher 依赖此偏好决定渠道
- settings 模块的 `notification-preferences-form.tsx` 调用 `messaging/actions.ts``updateNotificationPreferencesAction`
- 三个模块都在操作同一份数据,职责归属不清
### 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` 函数直接查询以下表:
| 表名 | 所属模块 | 查询内容 |
|------|---------|---------|
| `sessions` | auth | 活跃会话数 |
| `users` | users | 用户总数 + 最近注册用户 |
| `usersToRoles` | users | 用户角色统计 |
| `roles` | users | 角色名 |
| `classes` | classes | 班级总数 |
| `textbooks` | textbooks | 教材总数 |
| `chapters` | textbooks | 章节总数 |
| `questions` | questions | 题目总数 |
| `exams` | exams | 考试总数(含 scope 过滤) |
| `homeworkAssignments` | homework | 作业总数 + 已发布数 |
| `homeworkSubmissions` | homework | 提交数 + 待批改数 |
**问题分析**
- 违反模块封装原则dashboard 直接依赖其他模块的 DB schema
- 任何模块的表结构变更都需要同步修改 dashboard
- 无法复用其他模块的 scope 过滤逻辑dashboard 自己实现了 exam/homework 的 scope 过滤,第 31-73 行)
### 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 | 小 | 用户通知偏好失效,多渠道通知无效 |
| 2 | proctoring/exam-mode-config.tsx 未集成 | proctoring | 小 | 监考功能无法启用,组件为死代码 |
| 3 | proctoring 事件上报双通道重复 | proctoring | 小 | 代码重复,维护成本 |
| 4 | notifications 反向依赖 messaging | notifications | 中 | 架构耦合,难以独立演进 |
### P1中等问题下个迭代修复
| 序号 | 问题 | 模块 | 工作量 |
|------|------|------|--------|
| 5 | dashboard 直查 11 张跨模块表 | dashboard | 大 |
| 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 边界模糊、反向依赖
### 重点问题回答
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 边界是否清晰?**
不清晰。存在双向依赖、类型不一致、职责重叠三个问题,建议按方案 A 合并
5. **dashboard 是否直查其他模块的表?**
是。`getAdminDashboardData` 直查 11 张跨模块表,是本次审查最严重的封装违规
6. **settings 是否混入太多职责?**
混合了 5 类职责,但作为"设置"聚合点尚可接受。AI Provider 管理可考虑独立
7. **navigation.ts 是否有幽灵路由?**
无。007 报告中的 13 个幽灵路由已全部修复