Files
NextEdu/docs/architecture/004_architecture_impact_map.md

1551 lines
85 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.
# Next_Edu 架构影响地图
> 重写日期2026-06-17
> 目标:一次阅读即可直观理解整个项目架构
> 规则:源码修改后须同步更新本文档与 `005_architecture_data.json`
> 审查依据:`docs/architecture/audit/` 下 4 份审查报告
---
## 目录
- [第一部分:全局架构概览](#第一部分全局架构概览)
- [1.1 分层架构图](#11-分层架构图)
- [1.2 模块依赖关系图](#12-模块依赖关系图)
- [1.3 数据流向图(考试流程)](#13-数据流向图考试流程)
- [1.4 核心调用链路](#14-核心调用链路)
- [第二部分:模块清单](#第二部分模块清单)
- [第三部分:已知架构问题和技术债](#第三部分已知架构问题和技术债)
- [附录 A模块间依赖矩阵](#附录-a模块间依赖矩阵)
- [附录 B关键参数影响链](#附录-b关键参数影响链)
- [附录 C核心函数签名索引](#附录-c核心函数签名索引)
---
# 第一部分:全局架构概览
## 1.1 分层架构图
项目采用**严格三层架构**,依赖方向必须单向:`app → modules → shared`
```
┌─────────────────────────────────────────────────────────────────────┐
│ app/ (路由层) │
│ ───────────────────────────────────────────────────────────────── │
│ (auth)/ login / register / privacy / terms │
│ (dashboard)/ admin / teacher / student / parent / management │
│ api/ REST API (auth, ai, upload, files, search, ...) │
└──────────────────────────────┬──────────────────────────────────────┘
│ 调用 Server Actions / data-access
┌─────────────────────────────────────────────────────────────────────┐
│ modules/ (业务模块层) │
│ ───────────────────────────────────────────────────────────────── │
│ 核心教学: exams · homework · questions · textbooks · grades │
│ 教学管理: classes · school · scheduling · attendance · course-plans│
│ 用户与沟通users · messaging · notifications · parent · audit │
│ 扩展功能: elective · proctoring · diagnostic · dashboard │
│ 其他: announcements · files · settings · auth · layout · student│
│ │
│ 每个模块标准结构actions.ts (编排) → data-access.ts (DB) → schema.ts│
└──────────────────────────────┬──────────────────────────────────────┘
│ 依赖
┌─────────────────────────────────────────────────────────────────────┐
│ shared/ (基础设施层) │
│ ───────────────────────────────────────────────────────────────── │
│ db/ schema.ts (54 张表) + relations.ts + index.ts │
│ lib/ auth-guard · permissions · ai · audit-logger · │
│ change-logger · login-logger · password-policy · │
│ rate-limit · excel · file-storage · ... │
│ hooks/ use-permission · use-aria-live · ... │
│ components/ ui/ (shadcn) · a11y/ · onboarding-gate · ... │
│ types/ permissions · action-state │
└─────────────────────────────────────────────────────────────────────┘
│ 反向依赖(违规,见 1.2
┌──────────────────────────────┴──────────────────────────────────────┐
│ 根模块src/auth.ts (NextAuth 配置) · src/proxy.ts (中间件) │
│ ⚠️ shared/lib/{audit-logger, change-logger, auth-guard} 反向依赖 │
│ @/auth构成循环依赖详见第三部分 P0-2
└─────────────────────────────────────────────────────────────────────┘
```
**分层规则**
- `app/` 只能调用 `modules/` 的 Server Actions 和 data-access不直接访问 DB
- `modules/` 之间通过对方 data-access 通信,不直接查询对方表
- `shared/` 是被依赖方,不应反向依赖 `app/``modules/`
- `src/auth.ts``src/proxy.ts` 位于根目录,属于应用层
---
## 1.2 模块依赖关系图
下图展示模块间的实际依赖关系,**标注依赖类型与合规性**。
### 图例
- `───▶` 合理依赖(通过 data-access 或类型导入)
- `═══▶` 违规依赖(直接查询对方 DB 表)
- `⟳ ` 循环依赖
- `──▷` UI 组件组合(合理)
### 1.2.1 核心业务模块依赖
```
┌──────────────┐
│ textbooks │ ◀── 标杆模块(无跨模块 DB 访问)
└──────┬───────┘
│ ──▷ UI 组合knowledge-point-dialogs
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌────────────┐
│ questions │ │ exams │ │ homework │
└─────┬──────┘ └────┬─────┘ └─────┬──────┘
│ │ ═══ │ ═══
│ ═══ │ 直查 classes │ 直查 exams/classes/
│ 直查 │ 直查 questions │ classEnrollments/users
│ knowledgePoints │
│ chapters ┌─┴────────┐ │
│ textbooks │ grades │ │
└─────────────┤ (成绩) │◀────┘ 仅外键引用(合理)
└────┬─────┘
│ ═══
│ 直查 classes/users/subjects
┌──────────┐
│ classes │ ◀── 耦合最严重模块
└────┬─────┘ data-access.ts 已拆分为 5 文件 (✅ P0-1 已修复)
│ ═══ 混入 homework/scheduling/grades 逻辑
│ 直查 homeworkAssignments/exams
┌─────────┼─────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────┐ ┌──────────┐
│scheduling│ │school│ │ attendance│
└────┬─────┘ └──────┘ └──────────┘
│ ═══
│ classSchedule 表三处写入口
classes + scheduling/actions + scheduling/data-access
```
### 1.2.2 扩展模块依赖
```
┌─────────────┐ ═══ 直查 11 张跨模块表 ┌──────────────┐
│ dashboard │──────────────────────────────▶│ users/classes│
│ (聚合层) │ ⚠️ P0 严重违规 │ /exams/... │
└─────────────┘ └──────────────┘
┌─────────────┐ ─── 调用 data-access合理 ┌──────────────┐
│ parent │──────────────────────────────▶│ classes/ │
│ (聚合层) │ │ homework/grades│
└─────────────┘ └──────────────┘
┌─────────────┐ ═══ 直查 examSubmissions/ ┌──────────────┐
│ diagnostic │ submissionAnswers/ │ exams/questions│
│ │ questionsToKnowledgePoints │ /classes │
└─────────────┘──────────────────────────────▶└──────────────┘
┌─────────────┐ ═══ 直查 exams/examSubmissions ┌──────────────┐
│ proctoring │ /users │ exams/users │
└─────────────┘──────────────────────────────▶└──────────────┘
┌─────────────┐ ⟳ 双向依赖P0 严重违规) ┌──────────────┐
│ messaging │◀═══════════════════════════════▶│ notifications │
│ │ messaging 绕过 dispatcher │ (无独有表) │
│ │ notifications 反向依赖 messaging │ │
└─────────────┘ └──────────────┘
┌─────────────┐ ─── 调用 messaging Action ┌──────────────┐
│ settings │ (通知偏好表单) │ messaging │
└─────────────┘──────────────────────────────▶└──────────────┘
```
### 1.2.3 循环依赖详情
```
shared/lib/audit-logger.ts ──┐
shared/lib/change-logger.ts ──┼──▶ import { auth } from "@/auth"
shared/lib/auth-guard.ts ──┘
src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
──▶ import { ... } from "@/shared/lib/login-logger"
──▶ import { ... } from "@/shared/lib/password-policy"
──▶ import { ... } from "@/shared/lib/rate-limit"
──▶ import { ... } from "@/shared/lib/role-utils" # P1-3 拆出
──▶ import { ... } from "@/shared/lib/bcrypt-utils" # P1-3 拆出
──▶ import { ... } from "@/shared/lib/http-utils" # P1-3 拆出
──▶ import { ... } from "@/shared/lib/password-security-service" # P1-3 拆出
──▶ import { db, schema } from "@/shared/db"
⟳ 循环shared/lib/* → @/auth → shared/lib/*
影响shared 层无法独立测试/复用;架构上基础设施不应反向依赖应用层
```
---
## 1.3 数据流向图(考试流程)
以"考试流程"为例,展示数据从创建到成绩统计的完整流向。
```
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 1教师创建考试 │
│ ───────────────────────────────────────────────────────────────── │
│ teacher/exams/create/page.tsx │
│ └─▶ exams/actions.createExamAction │
│ ├─▶ requirePermission(EXAM_CREATE) [shared/auth-guard] │
│ ├─▶ persistExamDraft() [exams/data-access] │
│ │ └─▶ db.insert(exams) [shared/db] │
│ │ └─▶ db.insert(examQuestions) [shared/db] │
│ └─▶ revalidatePath("/teacher/exams") │
│ │
│ 数据写入exams 表 + examQuestions 表 │
│ ⚠️ 违规persistAiGeneratedExamDraft 直接 insert 到 questions 表 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 2学生作答作业化考试
│ ───────────────────────────────────────────────────────────────── │
│ student/learning/assignments/[assignmentId]/page.tsx │
│ └─▶ homework/actions.startHomeworkSubmissionAction │
│ ├─▶ requirePermission(HOMEWORK_SUBMIT) │
│ ├─▶ data-access-write.startHomeworkSubmission ✅ P1-2 已修复 │
│ │ └─▶ db.insert(homeworkSubmissions) [shared/db] │
│ └─▶ 返回 submissionId │
│ │
│ └─▶ homework/actions.saveHomeworkAnswerAction │
│ └─▶ data-access-write.saveHomeworkAnswer ✅ P1-2 已修复 │
│ └─▶ db.transaction(insert homeworkAnswers) [shared/db] │
│ │
│ └─▶ homework/actions.submitHomeworkAction │
│ └─▶ data-access-write.submitHomework ✅ P1-2 已修复 │
│ └─▶ db.update(homeworkSubmissions.status="submitted") │
│ │
│ 数据写入homeworkSubmissions 表 + homeworkAnswers 表 │
│ ✅ P1-2 已修复actions 层不再直接 DB 操作,已下沉到 data-access-write│
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 3教师批改 │
│ ───────────────────────────────────────────────────────────────── │
│ teacher/homework/submissions/[submissionId]/page.tsx │
│ └─▶ homework/actions.gradeHomeworkSubmissionAction │
│ ├─▶ requirePermission(HOMEWORK_GRADE) │
│ └─▶ data-access-write.gradeHomeworkSubmission ✅ P1-2 已修复│
│ └─▶ db.update(homeworkAnswers) 循环 [shared/db] │
│ │
│ 数据更新homeworkAnswers.isCorrect / score / feedback │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 4成绩统计与诊断 │
│ ───────────────────────────────────────────────────────────────── │
│ teacher/grades/page.tsx │
│ └─▶ grades/data-access.getGradeRecords │
│ └─▶ JOIN classes/subjects/users [⚠️ 跨模块直查] │
│ │
│ teacher/diagnostic/page.tsx │
│ └─▶ diagnostic/data-access.updateMasteryFromSubmission │
│ ├─▶ 查询 examSubmissions [⚠️ 跨模块直查] │
│ ├─▶ 查询 submissionAnswers [⚠️ 跨模块直查] │
│ └─▶ 更新 knowledgePointMastery │
│ │
│ 数据读取homeworkSubmissions → grades → knowledgePointMastery │
└─────────────────────────────────────────────────────────────────────┘
```
**关键观察**:考试流程横跨 4 个模块exams → homework → grades → diagnostic其中 3 处违规直查破坏了模块封装。
---
## 1.4 核心调用链路
### 1.4.1 调用链路:创建考试(含 AI 出题)
```
[Client] exam-form.tsx
│ FormData
[Route] POST /teacher/exams/create (Server Action)
[Action] exams/actions.createAiExamAction
├─▶ requirePermission(EXAM_CREATE)
│ └─▶ shared/lib/auth-guard.getAuthContext()
│ ├─▶ auth() [src/auth.ts]
│ ├─▶ db.query.usersToRoles [shared/db]
│ ├─▶ db.query.classSubjectTeachers
│ └─▶ 返回 { userId, roles, permissions, dataScope }
├─▶ generateAiCreateDraftFromSource()
│ └─▶ exams/ai-pipeline.ts (912 行)
│ ├─▶ shared/lib/ai.createAiChatCompletion()
│ │ └─▶ OpenAI SDK + db.query.aiProviders
│ └─▶ JSON 解析 + Zod 校验
├─▶ persistAiGeneratedExamDraft()
│ └─▶ exams/data-access.ts
│ ├─▶ db.insert(exams) ✅ 合理
│ ├─▶ db.insert(examQuestions) ✅ 合理
│ └─▶ db.insert(questions) ❌ 违规:应通过 questions/data-access
└─▶ revalidatePath("/teacher/exams")
```
### 1.4.2 调用链路:学生提交作业
```
[Client] homework-take-view.tsx
[Action] homework/actions.submitHomeworkAction
├─▶ requirePermission(HOMEWORK_SUBMIT)
├─▶ data-access-write.submitHomework ✅ P1-2 已修复
│ (校验 submission 归属 + 更新状态)
│ └─▶ db.update(homeworkSubmissions)
│ SET status = "submitted", submittedAt = now()
└─▶ 返回 ActionState<{ submissionId }>
```
### 1.4.3 调用链路:管理员仪表盘聚合
```
[Route] /admin/dashboard/page.tsx (Server Component)
[DataAccess] dashboard/data-access.getAdminDashboardData
├─▶ users/data-access.getUsersDashboardStats() ✅ 通过模块 data-access
│ ├─ userCount / activeSessionsCount / userRoleCounts
│ └─ recentUsers (含角色解析)
├─▶ classes/data-access.getClassesDashboardStats() ✅ 通过模块 data-access
│ └─ classCount
├─▶ textbooks/data-access.getTextbooksDashboardStats() ✅ 通过模块 data-access
│ └─ textbookCount / chapterCount
├─▶ questions/data-access.getQuestionsDashboardStats() ✅ 通过模块 data-access
│ └─ questionCount
├─▶ exams/data-access.getExamsDashboardStats(scope?) ✅ 通过模块 data-access
│ └─ examCount (含 scope 过滤)
└─▶ homework/stats-service.getHomeworkDashboardStats(scope?) ✅ 通过模块 data-access
├─ homeworkAssignmentCount / homeworkAssignmentPublishedCount
└─ homeworkSubmissionCount / homeworkSubmissionToGradeCount
✅ P0-4 已修复dashboard 改为并行调用各模块 dashboard stats 函数,不再直查跨模块表
```
---
# 第二部分:模块清单
> 每个模块包含:职责 · 导出函数 · 依赖关系 · 已知问题 · 文件清单
## 2.1 shared基础设施层
**职责**:提供全项目共享的 DB Schema、工具函数、权限系统、UI 基础组件、通用 Hooks。
**导出函数**(核心):
- `getAuthContext()` / `requirePermission(p)` / `requireAuth()` — 认证与权限
- `resolvePermissions(roles)` / `resolveDataScope(userId, roles)` — 权限解析
- `logAudit()` / `logLoginEvent()` / `logDataChange()` — 日志记录
- `createAiChatCompletion()` / `parseAiChatPayload()` — AI 调用
- `validatePassword()` / `isAccountLocked()` / `rateLimit()` — 安全策略
- `exportToExcel()` / `parseExcel()` / `generateTemplate()` — Excel 工具
- `cn()` / `formatDate()` / `formatFileSize()` — 通用工具
**依赖关系**
- 被依赖方:**所有模块**依赖 shared
- ⚠️ 反向依赖:`shared/lib/{audit-logger, change-logger, auth-guard}``@/auth`(循环依赖)
**已知问题**
- ❌ P0`shared/lib/*``@/auth` 循环依赖
- ⚠️ P1`schema.ts` 1111 行54 张表混合,超 1000 硬上限)
- ✅ P1~~`auth.ts` 293 行混合 5 类职责~~ 已拆分4 个辅助函数组迁移至 `shared/lib/{role-utils,bcrypt-utils,http-utils,password-security-service}`auth.ts 仅保留 NextAuth 配置)
- ✅ P2-2 已修复:~~`ai.ts` 218 行混合 5 类职责~~ 已拆分为 `ai/` 目录payload-parser.ts/api-key-crypto.ts/provider-config.ts/client.ts/errors.ts/index.ts`ai.ts` 保留为向后兼容的重导出文件9 行)
- ⚠️ P2`onboarding-gate.tsx` 业务逻辑泄漏到 shared
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `db/schema.ts` | 1111 | 54 张表定义(超硬上限) |
| `db/relations.ts` | - | 表关系定义 |
| `db/index.ts` | - | Drizzle 客户端 |
| `lib/auth-guard.ts` | - | 认证上下文 + 权限校验 + DataScope |
| `lib/permissions.ts` | - | 角色-权限映射 |
| `lib/ai.ts` | 9 | 向后兼容重导出P2-2 已拆分到 `ai/` 目录) |
| `lib/ai/payload-parser.ts` | 78 | 请求负载解析 |
| `lib/ai/api-key-crypto.ts` | 28 | API Key 加密/解密 |
| `lib/ai/provider-config.ts` | 61 | Provider 配置查询 |
| `lib/ai/client.ts` | 58 | AI 客户端创建与调用 |
| `lib/ai/errors.ts` | 8 | 错误格式化 |
| `lib/ai/index.ts` | 5 | 聚合导出 |
| `lib/audit-logger.ts` | - | 操作日志 |
| `lib/change-logger.ts` | - | 数据变更日志 |
| `lib/login-logger.ts` | - | 登录日志 |
| `lib/password-policy.ts` | - | 密码策略纯函数 |
| `lib/rate-limit.ts` | - | 内存滑动窗口限流 |
| `lib/role-utils.ts` | 31 | 角色规范化纯函数normalizeRole / resolvePrimaryRole |
| `lib/bcrypt-utils.ts` | 18 | bcrypt 哈希前缀规范化纯函数 |
| `lib/http-utils.ts` | 27 | 请求头解析resolveClientIpserver-only |
| `lib/password-security-service.ts` | 84 | 密码安全 DB 操作(账户锁定/失败登录追踪server-only |
| `lib/excel.ts` | - | Excel 导入导出 |
| `lib/file-storage.ts` | - | 文件存储抽象 |
| `hooks/use-permission.ts` | - | 客户端权限 Hook |
| `components/ui/*` | 34 文件 | shadcn/ui 标准组件 |
| `components/onboarding-gate.tsx` | 312 | 引导流程(业务泄漏) |
| `components/global-search.tsx` | 221 | 全局搜索(业务泄漏) |
| `types/permissions.ts` | 92 | 54 个权限点常量 |
---
## 2.2 exams考试模块
**职责**:考试全生命周期管理(创建/编辑/预览/发布/删除/复制)+ AI 辅助出题。
**导出函数**
- Actions`createExamAction` / `createAiExamAction` / `previewAiExamAction` / `regenerateAiQuestionAction` / `updateExamAction` / `deleteExamAction` / `duplicateExamAction` / `getExamPreviewAction` / `getSubjectsAction` / `getGradesAction`(✅ P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access
- Data-access`getExams` / `getExamById` / `persistExamDraft` / `persistAiGeneratedExamDraft` / `buildExamDescription` / `resolveSubjectGradeNames` / `getExamCreatorId` / `updateExamWithQuestions` / `deleteExamById` / `duplicateExam` / `getExamPreview` / `getExamSubjects` / `getExamGrades`(后 7 个为 P1-2 新增)
- AI Pipeline`generateAiCreateDraftFromSource` / `generateAiPreviewData` / `regenerateAiQuestionByInstruction`
**依赖关系**
- 依赖:`shared/*``@/auth``questions`(类型)、`classes`(❌ 直查)、`school`(❌ 直查 subjects/grades`questions`(❌ 直查 insert
- 被依赖:`homework`(通过 sourceExamId 外键,合理)、`dashboard`(通过 data-accessP0-4 已修复)、`proctoring`(❌ 直查)
**已知问题**
- ❌ P0`persistAiGeneratedExamDraft` 直接 insert 到 `questions`
- ❌ P0`getExams`/`getExamById` 直查 `classes`
- ❌ P1`getSubjectsAction`/`getGradesAction` 直查 `subjects`/`grades` 表(应属 school 模块)
- ✅ P1-2 已修复:~~`actions.ts` 832 行(超 800 建议),多处直接 DB 操作~~ DB 操作已下沉到 data-accessactions.ts 现 691 行
- ⚠️ P1`ai-pipeline.ts` 857 行(超 800 建议),混合 4 类职责
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 691 | 10 个 Server ActionP1-2 已修复,无直接 DB 操作) |
| `ai-pipeline.ts` | 857 | AI 出题管线(超限) |
| `data-access.ts` | 471 | 考试 CRUD含 P1-2 新增 7 个写/查询函数) |
| `types.ts` | 31 | 类型定义 |
| `hooks/use-exam-preview.ts` | 295 | 预览 Hook |
| `components/*` | 18 文件 | 考试表单/组卷/预览组件 |
---
## 2.3 homework作业模块
**职责**:作业全生命周期(创建/发布/作答/批改/分析)。
**导出函数**
- Actions`createHomeworkAssignmentAction` / `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction`(✅ P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access/data-access-write
- Data-access`getHomeworkAssignments` / `getHomeworkAssignmentById` / `getHomeworkSubmissions` / `getStudentHomeworkAssignments` / `getStudentHomeworkTakeData` / `getHomeworkAssignmentReviewList` / `getHomeworkSubmissionDetails` / `getDemoStudentUser` / `isRecord` / `toQuestionContent` / `getAssignmentMaxScoreById`(后三者供 stats-service 使用)
- Data-access-write10 个写操作函数P1-2 新增,从 actions 下沉)
- Stats-service`getTeacherGradeTrends` / `getHomeworkAssignmentAnalytics` / `getStudentDashboardGrades`(从 data-access.ts re-export 以保持向后兼容)
**依赖关系**
- 依赖:`shared/*``@/auth``exams`(❌ 直查 5 处)、`classes`(❌ 直查)、`school`(❌ 直查 subjects`users`(❌ 直查)
- 被依赖:`dashboard`(通过 data-access合理`parent`(通过 data-access合理`classes`(❌ classes 反向直查 homework 表)
**已知问题**
- ✅ P0 已解决:`data-access.ts` 已拆分至 598 行(原 1038 行超 1000 硬上限),统计函数迁移至 `stats-service.ts`
- ✅ P0 已解决:`getStudentDashboardGrades` 排名计算逻辑迁移至 `stats-service.ts`
- ✅ P0 已解决:`getHomeworkAssignmentAnalytics` 错误率统计逻辑迁移至 `stats-service.ts`
- ❌ P15 处直查 `exams`
- ✅ P1-2 已修复:~~`actions.ts` 多处直接 DB 操作(`createHomeworkAssignmentAction` 157 行)~~ DB 操作已下沉到 `data-access-write.ts`actions.ts 现 239 行
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 598 | 作业 CRUD + 学生视角 + 批改(含 re-export stats 函数) |
| `data-access-write.ts` | 285 | 作业写操作P1-2 新增10 个写函数从 actions 下沉) |
| `stats-service.ts` | 425 | 统计分析(教师趋势/作业分析/学生仪表盘成绩) |
| `actions.ts` | 239 | 5 个 Server ActionP1-2 已修复,无直接 DB 操作) |
| `types.ts` | 186 | 类型定义 |
| `schema.ts` | 29 | Zod 校验 |
---
## 2.4 questions题库模块
**职责**:题库管理(题目 CRUD、知识点关联、题型支持
**导出函数**
- Actions`getQuestionsAction` / `createQuestionAction` / `updateQuestionAction` / `deleteQuestionAction` / `getKnowledgePointOptionsAction`(✅ P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access
- Data-access`getQuestions` / `createQuestionWithRelations` / `updateQuestionById` / `deleteQuestionByIdRecursive` / `getKnowledgePointOptions`(后 4 个为 P1-2 新增/迁移)
**依赖关系**
- 依赖:`shared/*``@/auth``textbooks`(❌ actions 直查 knowledgePoints/chapters/textbooks
- 被依赖:`exams`(通过类型导入,合理)、`textbooks`UI 组合,合理)
**已知问题**
- ✅ P1-2 已修复:~~写操作函数错放在 `actions.ts``insertQuestionWithRelations` / `deleteQuestionRecursive`~~ 已下沉到 data-access`createQuestionWithRelations` / `updateQuestionById` / `deleteQuestionByIdRecursive` / `getKnowledgePointOptions`
- ❌ P1`getKnowledgePointOptionsAction` 直查 textbooks 模块表
- ✅ P2 已解决:~~`data-access.ts` 仅 129 行,写操作缺失~~ P1-2 后 data-access.ts 扩充至 260 行
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 149 | 5 个 Server ActionP1-2 已修复,无直接 DB 操作) |
| `data-access.ts` | 260 | 题目 CRUD + 知识点选项(含 P1-2 新增 4 个写/查询函数) |
| `schema.ts` | 18 | Zod 校验 |
| `types.ts` | 34 | 类型定义 |
---
## 2.5 textbooks教材模块— 标杆模块
**职责**:教材与知识体系管理(教材/章节树形结构、知识点 CRUD、Markdown 内容编辑、知识图谱)。
**导出函数**
- Actions`getTextbooksAction` / `getTextbookByIdAction` / `createTextbookAction` / `updateTextbookAction` / `deleteTextbookAction` / `getChaptersAction` / `createChapterAction` / `updateChapterAction` / `deleteChapterAction` / `getKnowledgePointsAction` / `createKnowledgePointAction` / `updateKnowledgePointAction` / `deleteKnowledgePointAction`
- Data-access与 actions 一一对应的 data-access 函数
**依赖关系**
- 依赖:`shared/*``@/auth`
- 被依赖:`questions`(❌ 直查)、`exams`(通过类型)、`dashboard`(通过 data-accessP0-4 已修复)
**已知问题**
- ✅ 无跨模块 DB 访问
- ✅ actions 层编排模式标杆(权限校验 → 调用 data-access → revalidatePath
- ✅ data-access 层职责单一
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 276 | 13 个 Server Action标杆 |
| `data-access.ts` | 428 | 教材/章节/知识点 CRUD |
| `types.ts` | 79 | 类型定义 |
| `hooks/use-knowledge-point-actions.ts` | 121 | 知识点操作 Hook |
| `components/*` | 12 文件 | 教材编辑/知识图谱组件 |
---
## 2.6 grades成绩模块— 标杆模块(拆分范例)
**职责**:成绩分析(录入/查询/统计/导出/趋势对比分析)。
**导出函数**
- Actions`getGradeRecordsAction` / `createGradeRecordAction` / `updateGradeRecordAction` / `deleteGradeRecordAction` / `exportGradesAction` / `getGradeTrendAction` / `getClassComparisonAction` / `getSubjectComparisonAction` / `getGradeDistributionAction` / `getClassRankingAction` / `getRankingTrendAction`
- Data-access`getGradeRecords` / `getStudentGradeSummary` / `getClassRanking` / `getClassStudentsForEntry` / `getClassGradeStats` / `getClassGradeStatsWithMeta` / `getGradeTrend` / `getClassComparison` / `getSubjectComparison` / `getGradeDistribution` / `getRankingTrend`
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(❌ 直查 classes/classEnrollments`school`(❌ 直查 subjects`users`(❌ 直查)
- 被依赖:`parent`(通过 data-access合理`dashboard`
**已知问题**
- ❌ P1多处直查 `classes`/`classEnrollments`/`subjects`/`users`
- ⚠️ P2统计计算业务逻辑混入 data-access`getClassGradeStats` / `getGradeDistribution`
- ✅ actions 层无直接 DB 访问(标杆)
- ✅ data-access 按职责拆分为 3 个文件(标杆)
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 312 | 6 个 Server Action |
| `actions-analytics.ts` | 133 | 5 个分析 Action |
| `data-access.ts` | 419 | 成绩 CRUD + 统计 |
| `data-access-analytics.ts` | 293 | 趋势/对比分析 |
| `data-access-ranking.ts` | 121 | 排名查询 |
| `export.ts` | 214 | Excel 导出 |
| `schema.ts` | 52 | Zod 校验 |
| `types.ts` | - | 类型定义 |
---
## 2.7 classes班级模块— 耦合最严重
**职责**:班级 CRUD + 学生/教师管理 + 邀请码注册。
**导出函数**
- Actions`createTeacherClassAction` / `updateTeacherClassAction` / `deleteTeacherClassAction` / `createAdminClassAction` / `updateAdminClassAction` / `deleteAdminClassAction` / `createGradeClassAction` / `updateGradeClassAction` / `deleteGradeClassAction`
- Data-access`getAdminClasses` / `getTeacherClasses` / `getGradeManagedClasses` / `getStudentClasses` / `getClassDetails` / `getClassStudents` / `getClassSchedule` / `getClassHomeworkInsights` / `getGradeHomeworkInsights` / `getStudentsSubjectScores` / `createClassScheduleItem` / `updateClassScheduleItem` / `deleteClassScheduleItem`
**依赖关系**
- 依赖:`shared/*``@/auth``school`(❌ actions 直查 grades 表)、`homework`(❌ data-access 直查 5 张 homework 表)、`exams`(❌ data-access 直查)
- 被依赖:`exams`/`homework`/`grades`/`attendance`/`scheduling`/`dashboard`(通过 data-accessP0-4 已修复)/`parent`/`course-plans`/`users`8+ 处直查 classes 表)
**已知问题**
- ✅ P0-1 已修复:`data-access.ts` 已拆分为 5 个文件data-access/data-access-stats/data-access-schedule/data-access-students/data-access-admin所有文件均 ≤800 行
- ❌ P0混入 homework 逻辑(`getClassHomeworkInsights` + `getGradeHomeworkInsights` = 532 行)
- ❌ P0混入 scheduling 逻辑(课表 CRUD与 scheduling 模块写同一张表)
- ❌ P0混入 grades 逻辑(`getStudentsSubjectScores`
- ❌ P0`classSchedule` 表三处写入口(数据完整性高风险)
- ❌ P1`actions.ts` 直查 `grades` 表做权限校验
- ❌ P1`getSessionTeacherId` 在 data-access 调用 `auth()`
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 548 | 核心班级 CRUD + 邀请码 + 教师班级管理(含 re-export 向后兼容) |
| `data-access-stats.ts` | 531 | 作业统计查询(班级/年级作业洞察) |
| `data-access-schedule.ts` | 194 | 课表查询(学生/班级课表 CRUD |
| `data-access-students.ts` | 244 | 学生相关查询(科目成绩、学生名单、学生班级) |
| `data-access-admin.ts` | 406 | 管理员班级管理(管理员班级 CRUD、年级管理班级查询 |
| `actions.ts` | 676 | 9 个 Server Action三组重复 |
| `types.ts` | 201 | 类型定义(含跨领域类型污染) |
---
## 2.8 school学校模块
**职责**:学校/学年/部门/年级的 CRUD。
**导出函数**
- Actions`getSchoolsAction` / `createSchoolAction` / `updateSchoolAction` / `deleteSchoolAction` / `getAcademicYearsAction` / `createAcademicYearAction` / `updateAcademicYearAction` / `deleteAcademicYearAction` / `getDepartmentsAction` / `createDepartmentAction` / `updateDepartmentAction` / `deleteDepartmentAction` / `getGradesAction` / `createGradeAction` / `updateGradeAction` / `deleteGradeAction` / `getStaffOptions`
- Data-access与 actions 对应的只读查询
**依赖关系**
- 依赖:`shared/*``@/auth``users`(⚠️ `getStaffOptions` 直查 users/roles可接受
- 被依赖:`exams`(❌ 直查 subjects/grades`homework`(❌ 直查 subjects`grades`(❌ 直查 subjects`questions`(❌ 直查)、`classes`(❌ actions 直查 grades 表)、`course-plans`(合理)
**已知问题**
- ⚠️ P2审计日志不一致仅 school 实体记录department/academicYear/grade 未记录)
- ⚠️ P2`getStaffOptions`/`getGrades` 直查 users/roles展示用可接受
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 325 | 17 个 Server Action |
| `data-access.ts` | 186 | 只读查询 |
| `schema.ts` | 51 | Zod 校验 |
| `types.ts` | 42 | 类型定义 |
---
## 2.9 scheduling排课模块
**职责**:自动排课算法 + 课表调整 + 排课规则管理。
**导出函数**
- Actions`autoScheduleAction` / `applyAutoScheduleAction` / `getSchedulingRulesAction` / `updateSchedulingRulesAction` / `getScheduleChangesAction` / `createScheduleChangeAction` / `updateScheduleChangeAction` / `deleteScheduleChangeAction`
- Data-access`getSchedulingRules` / `getScheduleChanges` / `getAdminClassesForScheduling` / `getTeachersForScheduling` / `getClassroomsForScheduling` / `getClassSubjectsForScheduling`
- 算法:`findOptimalSlot` / `validateSchedule` / `autoSchedule` / `buildDefaultTimeSlots`(纯函数,标杆)
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(❌ actions 直查 users + 直写 classSchedule`school`(⚠️ 排课辅助查询,可接受)
- 被依赖:与 `classes` 共写 `classSchedule`
**已知问题**
- ❌ P0`applyAutoScheduleAction` 直接 transaction 写 `classSchedule` 表(第三个写入口)
- ❌ P1`autoScheduleAction` 直查 `users`
- ⚠️ P2`actions.ts` 末尾 re-export data-access 函数(反模式)
-`auto-scheduler.ts` 是算法独立化的最佳实践(纯函数、无 DB、可测试
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `auto-scheduler.ts` | 310 | 排课算法(纯函数,标杆) |
| `actions.ts` | 302 | 8 个 Server Action |
| `data-access.ts` | 272 | 排课辅助查询 + 规则/变更 CRUD |
| `schema.ts` | - | Zod 校验 |
| `types.ts` | - | 类型定义 |
---
## 2.10 attendance考勤模块— 结构典范
**职责**:考勤记录管理 + 统计分析。
**导出函数**
- Actions`getAttendanceRecordsAction` / `createAttendanceRecordAction` / `updateAttendanceRecordAction` / `deleteAttendanceRecordAction` / `getStudentAttendanceAction` / `getAttendanceStatsAction`
- Data-access`getAttendanceRecords` / `createAttendanceRecord` / `updateAttendanceRecord` / `deleteAttendanceRecord` / `getClassStudentsForAttendance` / `getAttendanceStats`
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(❌ `getClassStudentsForAttendance` 直查 classEnrollments
- 被依赖:无
**已知问题**
- ⚠️ P2`getClassStudentsForAttendance` 直查 `classEnrollments`(应通过 classes data-access
- ✅ stats 独立拆分为 `data-access-stats.ts`(拆分范例)
- ✅ DataScope 完整接入 6 种 scope 类型
- ✅ actions 层无直接 DB 访问
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 271 | 6 个 Server Action |
| `data-access.ts` | 271 | 考勤 CRUD |
| `data-access-stats.ts` | 145 | 统计逻辑(拆分范例) |
| `schema.ts` | - | Zod 校验 |
| `types.ts` | - | 类型定义 |
---
## 2.11 users用户模块
**职责**:用户资料管理 + 批量导入导出。
**导出函数**
- Actions`getUserProfileAction` / `updateUserProfileAction` / `importUsersAction` / `exportUsersAction` / `downloadUserTemplateAction`
- Data-access`getUserProfile`
- Import-export`generateUserImportTemplate` / `parseUserImportData` / `exportUsersToExcel`+ re-export `batchImportUsers` / `UserImportResult` 保持向后兼容)
- User-service`batchImportUsers`(用户创建 + 密码哈希 + 角色分配)
- Class-registration`registerStudentByInvitationCode`(委托 classes/data-access 完成班级注册)
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(✅ P1-4 已修复:通过 `class-registration.ts` 调用 `classes/data-access.enrollStudentByInvitationCode`,不再直写 classEnrollments
- 被依赖:`dashboard`(通过 data-accessP0-4 已修复)、`grades`(❌ 直查)、`homework`(❌ 直查)
**已知问题**
- ✅ P1 已解决:`import-export.ts` 四重职责已拆分为 `import-export.ts`(解析/生成)+ `user-service.ts`(用户创建)+ `class-registration.ts`(班级注册)
- ✅ P1 已解决:`batchImportUsers` 不再跨模块直写 `classEnrollments`,改为调用 `classes/data-access.enrollStudentByInvitationCode`
- ❌ P1`updateUserProfile` 绕过 data-access 直接 DB 写
- ⚠️ P2`data-access.ts` 133 行写操作仍缺失updateUserProfile 绕过 data-access
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `import-export.ts` | 157 | 文件解析/生成(模板生成 + 解析校验 + Excel 导出)+ re-export 向后兼容 |
| `user-service.ts` | 82 | 用户创建(批量导入 + 密码哈希 + 角色分配) |
| `class-registration.ts` | 21 | 班级注册(委托 classes/data-access |
| `actions.ts` | 131 | 5 个 Server Action |
| `data-access.ts` | 133 | getUserProfile + 用户查询 |
---
## 2.12 dashboard仪表盘模块
**职责**:管理员/教师/学生仪表盘数据聚合。
**导出函数**
- Data-access`getAdminDashboardData` / `getTeacherDashboardData` / `getStudentDashboardData`
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(通过 data-access合理`homework`(通过 data-access合理`grades`(合理)、`users`/`textbooks`/`questions`/`exams`(通过各模块 dashboard stats 函数P0-4 已修复)
- 被依赖:无
**已知问题**
- ✅ P0-4 已修复:`getAdminDashboardData` 改为并行调用各模块 dashboard stats 函数(`getUsersDashboardStats`/`getClassesDashboardStats`/`getTextbooksDashboardStats`/`getQuestionsDashboardStats`/`getExamsDashboardStats`/`getHomeworkDashboardStats`),不再直查跨模块表
- ⚠️ P2教师仪表盘直查 `users` 表获取教师姓名
- ✅ 学生/教师仪表盘正确通过各模块 data-access 获取数据
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | - | 仪表盘数据聚合P0-4 已修复,通过各模块 data-access 获取数据) |
| `types.ts` | - | 类型定义 |
| `components/*` | 14 文件 | 三种角色仪表盘组件 |
---
## 2.13 messaging私信模块
**职责**:站内私信 + 站内通知列表 + 通知偏好。
**导出函数**
- Actions`sendMessageAction` / `getMessagesAction` / `getMessageAction` / `deleteMessageAction` / `getNotificationsAction` / `markNotificationReadAction` / `markAllNotificationsReadAction` / `getNotificationPreferencesAction` / `updateNotificationPreferencesAction`
- Data-access`createNotification` / `getNotifications` / `getRecipients`
- Notification-preferences`getNotificationPreferences` / `updateNotificationPreferences`
**依赖关系**
- 依赖:`shared/*``@/auth`、❌ 绕过 notifications 直接写 `messageNotifications`
- 被依赖:`notifications`(❌ 反向依赖 messaging 的偏好和 in-app 渠道)、`settings`(通知偏好表单)、`layout`(通知下拉)
**已知问题**
- ❌ P0`sendMessageAction` 绕过 notifications dispatcher 直接调用 `createNotification`,导致多渠道通知失效
- ❌ P0与 notifications 双向依赖 + 职责重叠
- ⚠️ P1同时管理 3 类数据messages + messageNotifications + notificationPreferences
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 245 | 9 个 Server Action |
| `data-access.ts` | 252 | 私信 CRUD + 通知 CRUD |
| `notification-preferences.ts` | 166 | 通知偏好 CRUD |
| `schema.ts` | 17 | 私信发送校验 |
| `types.ts` | 108 | 私信 + 通知 + 偏好类型 |
---
## 2.14 notifications通知分发模块
**职责**多渠道通知分发SMS/Email/WeChat/InApp
**导出函数**
- Actions`sendNotificationAction` / `sendClassNotificationAction`
- Dispatcher`sendNotification(payload)`
- Channels`InAppChannelSender` / `SmsChannelSender` / `EmailChannelSender` / `WeChatChannelSender`
**依赖关系**
- 依赖:`shared/*``@/auth`、❌ 反向依赖 `messaging`(偏好 + in-app 渠道 + createNotification
- 被依赖messaging 绕过它)
**已知问题**
- ❌ P0不拥有任何数据全部依赖 messaging 模块
- ❌ P0与 messaging 双向依赖
- ❌ P1类型系统不一致messaging 按业务类别notifications 按严重级别)
- ⚠️ P1`sendClassNotificationAction` 直查 `classes`/`classEnrollments`
- ⚠️ P1发送日志仅 console`notification_logs`
- ✅ 渠道抽象优秀(接口 + 工厂 + Mock 实现)
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `dispatcher.ts` | 152 | 渠道选择 + 并行分发 |
| `data-access.ts` | 86 | 用户偏好 + 联系方式 + 日志 |
| `actions.ts` | 119 | 2 个 Server Action |
| `types.ts` | 70 | 通知负载 + 渠道配置类型 |
| `index.ts` | 38 | 对外导出入口 |
| `channels/*` | 5 文件 | 4 个渠道实现 |
---
## 2.15 audit审计模块
**职责**:操作日志 + 登录日志 + 数据变更日志查询与导出。
**导出函数**
- Actions`getAuditLogsAction` / `getLoginLogsAction` / `getDataChangeLogsAction` / `exportAuditLogsAction` / `exportLoginLogsAction` / `exportDataChangeLogsAction`
- Data-access`getAuditLogs` / `getLoginLogs` / `getDataChangeLogs` / `getAuditModuleOptions`
**依赖关系**
- 依赖:`shared/*``@/auth`
- 被依赖:无
**已知问题**
- ⚠️ P2Excel 导出逻辑内联在 actions 层(应抽取到 `export.ts`
- ⚠️ P2三个导出 Action 结构高度重复
- ✅ data-access 职责清晰,无跨模块问题
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 212 | 6 个 Server Action含内联导出 |
| `data-access.ts` | 260 | 日志查询 |
| `types.ts` | - | 类型定义 |
---
## 2.16 announcements公告模块
**职责**:公告 CRUD + 发布/归档。
**导出函数**
- Actions`getAnnouncementsAction` / `createAnnouncementAction` / `updateAnnouncementAction` / `deleteAnnouncementAction` / `publishAnnouncementAction` / `archiveAnnouncementAction`(✅ P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access
- Data-access`getAnnouncements` / `getAnnouncementById` / `insertAnnouncement` / `updateAnnouncementById` / `deleteAnnouncementById` / `publishAnnouncementById` / `archiveAnnouncementById`(后 5 个为 P1-2 新增)
**依赖关系**
- 依赖:`shared/*``@/auth``school`(合理,获取年级列表)
- 被依赖:无
**已知问题**
- ✅ P1-2 已修复:~~所有写操作直接在 actions 层 `db.insert/update/delete`,未下沉到 data-access~~ 写操作已下沉到 data-access5 个新函数)
- ⚠️ P2死代码 `void wasPublished`
- ⚠️ P2`getAnnouncementsAction` 使用 `requireAuth()` 而非 `requirePermission(ANNOUNCEMENT_READ)`
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 197 | 6 个 Server ActionP1-2 已修复,无直接 DB 操作) |
| `data-access.ts` | 171 | 公告 CRUD + 发布/归档(含 P1-2 新增 5 个写函数) |
| `schema.ts` | - | Zod 校验 |
| `types.ts` | - | 类型定义 |
---
## 2.17 files文件模块
**职责**:文件附件 CRUD + 批量删除 + 统计。
**导出函数**
- Data-access`getAllFileAttachments` / `getFileAttachmentsByOwner` / `getFileAttachmentById` / `createFileAttachment` / `updateFileAttachment` / `deleteFileAttachment` / `batchDeleteFileAttachments` / `getFileStats`
**依赖关系**
- 依赖:`shared/*``@/auth`
- 被依赖:`app/api/upload` / `app/api/files/[id]` / `app/api/files/batch-delete`
**已知问题**
- ⚠️ P2所有函数 try-catch 吞错误返回空数组/null
- ⚠️ P2`actions.ts`data-access 被路由直接调用
- ✅ 职责单一,不跨模块查询
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 267 | 文件 CRUD + 批量删除 + 统计 |
| `types.ts` | - | 类型定义 |
| `components/*` | 6 文件 | 上传/列表/预览/管理 |
---
## 2.18 course-plans课程计划模块
**职责**:课程计划 CRUD + 周计划项 CRUD + 排序。
**导出函数**
- Actions`getCoursePlansAction` / `getCoursePlanByIdAction` / `createCoursePlanAction` / `updateCoursePlanAction` / `deleteCoursePlanAction` / `createCoursePlanItemAction` / `updateCoursePlanItemAction` / `deleteCoursePlanItemAction` / `toggleCoursePlanItemCompletedAction`
- Data-access与 actions 对应
**依赖关系**
- 依赖:`shared/*``@/auth``classes`合理getAdminClasses/getStaffOptions`school`合理getAcademicYears
- 被依赖:无
**已知问题**
- ⚠️ P2`getSubjectOptions` 直查 `subjects`subjects 无独立模块,可接受)
- ✅ actions 层使用 `handleError`/`revalidatePlanPaths` 辅助函数(良好范例)
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 320 | 课程计划 + 周计划项 CRUD |
| `actions.ts` | 265 | 9 个 Server Action |
| `schema.ts` | - | Zod 校验 |
| `types.ts` | - | 类型定义 |
---
## 2.19 parent家长模块
**职责**:家长视角的子女数据聚合与展示。
**导出函数**
- Data-access`getChildren` / `getChildBasicInfo` / `getChildDashboardData`
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(合理)、`homework`(合理)、`grades`(合理)
- 被依赖:无
**已知问题**
- ⚠️ P2`getChildBasicInfo` 多次串行查询,可优化为 join
- ✅ 职责单一,正确复用其他模块 data-access
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 234 | 子女关系 + 仪表盘数据聚合 |
| `types.ts` | 57 | 类型定义 |
| `components/*` | 7 文件 | 子女卡片/详情/仪表盘 |
---
## 2.20 elective选课模块
**职责**:选修课程管理 + 学生选课 + 抽签。
**导出函数**
- Actions`getElectiveCoursesAction` / `createElectiveCourseAction` / `updateElectiveCourseAction` / `deleteElectiveCourseAction` / `getStudentSelectionsAction` / `selectCourseAction` / `dropCourseAction` / `runLotteryAction` / `getAvailableCoursesForStudentAction`
- Data-access`getElectiveCourses` / `getElectiveCourseById` / `createElectiveCourse` / `updateElectiveCourse` / `deleteElectiveCourse` / `selectCourse` / `dropCourse` / `runLottery` / `getStudentSelections` / `getAvailableCoursesForStudent`
**依赖关系**
- 依赖:`shared/*``@/auth`
- 被依赖:无
**已知问题**
- ⚠️ P1`data-access.ts``data-access-selections.ts` 重复定义 `mapCourseRow`/`buildCourseSelect`60 行重复)
- ⚠️ P2`runLottery` 使用 `Math.random()`,结果不可复现
- ⚠️ P2`selectCourse` FCFS 模式存在并发超卖风险
- ✅ 权限校验完整ELECTIVE_MANAGE/SELECT/READ
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 304 | 11 个 Server Action |
| `data-access.ts` | 242 | 课程 CRUD + scope 过滤 |
| `data-access-operations.ts` | 217 | 选课操作select/drop/lottery |
| `data-access-selections.ts` | 189 | 选课记录查询 |
| `schema.ts` | 132 | Zod 校验 |
| `types.ts` | 108 | 类型定义 + 标签常量 |
---
## 2.21 proctoring监考模块
**职责**:考试监考事件记录 + 防作弊监控 + 监考面板。
**导出函数**
- Actions`recordProctoringEventAction` / `getProctoringDashboardAction`
- Data-access`recordProctoringEvent` / `getExamForProctoring` / `getExamProctoringSummary` / `getStudentProctoringStatuses` / `getRecentProctoringEvents`
**依赖关系**
- 依赖:`shared/*``@/auth``exams`(❌ 直查 exams/examSubmissions`users`(❌ 直查)
- 被依赖:无
**已知问题**
- ❌ P0`exam-mode-config.tsx` 未集成到考试表单(死代码,监考功能无法启用)
- ❌ P0事件上报存在 Server Action 与 REST API 双通道重复
- ⚠️ P1跨模块直查 `exams`/`examSubmissions`/`users`(监考本质是考试扩展,可接受但需标注)
- ⚠️ P2`actions.ts` 直接 import `db``examSubmissions`
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 388 | 事件记录 + 查询 + 摘要统计 |
| `actions.ts` | 144 | 2 个 Server Action |
| `types.ts` | 136 | 类型定义 + 标签常量 + 阈值常量 |
| `components/anti-cheat-monitor.tsx` | - | 学生端防作弊监控 |
| `components/exam-mode-config.tsx` | - | 考试模式配置(**未集成** |
| `components/proctoring-dashboard.tsx` | - | 教师监考面板 |
---
## 2.22 diagnostic学情诊断模块
**职责**:知识点掌握度查询 + 诊断报告生成。
**导出函数**
- Actions`generateStudentDiagnosticReportAction` / `generateClassDiagnosticReportAction` / `publishDiagnosticReportAction` / `deleteDiagnosticReportAction` / `getDiagnosticReportsAction` / `getStudentMasteryAction`
- Data-access`updateMasteryFromSubmission` / `getStudentMastery` / `getClassMasteryOverview`
- Data-access-reports`createDiagnosticReport` / `getDiagnosticReport` / `getDiagnosticReports` / `deleteDiagnosticReport` / `publishDiagnosticReport`
**依赖关系**
- 依赖:`shared/*``@/auth``exams`(❌ 直查 examSubmissions/submissionAnswers`questions`(❌ 直查 questionsToKnowledgePoints`classes`(❌ 直查 classEnrollments/classes/users
- 被依赖:无
**已知问题**
- ❌ P1`updateMasteryFromSubmission` 跨模块直查 4 张表(与 exams/homework/questions 紧耦合)
- ⚠️ P2`data-access-reports.ts` 有未使用代码(`round2`
- ⚠️ P2班级报告将生成者 ID 存入 `studentId` 字段schema 设计缺陷 workaround
- ✅ 与 grades 模块无职责重叠grades 管分数diagnostic 管知识点掌握度)
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 254 | 知识点掌握度查询 + 更新 |
| `data-access-reports.ts` | 202 | 诊断报告 CRUD |
| `actions.ts` | 148 | 6 个 Server Action |
| `types.ts` | 97 | 类型定义 |
| `components/*` | 4 文件 | 学生/班级诊断视图 + 雷达图 |
---
## 2.23 settings设置模块
**职责**AI Provider 管理 + 密码修改 + 个人资料 + 主题偏好 + 通知偏好。
**导出函数**
- Actions`getAiProvidersAction` / `createAiProviderAction` / `updateAiProviderAction` / `deleteAiProviderAction` / `testAiProviderAction`
- Actions-password`changePasswordAction`
**依赖关系**
- 依赖:`shared/*``@/auth``messaging`(通知偏好表单调用 messaging Action
- 被依赖:无
**已知问题**
- ⚠️ P2混合 5 类职责AI Provider + 密码 + 资料 + 主题 + 通知偏好)
- ⚠️ P2`data-access.ts``actions.ts` 直接使用 `db`
- ⚠️ P2`notification-preferences-form.tsx` 跨模块 UI 依赖
- ✅ 密码修改有速率限制
- ✅ AI Provider 操作有 `AI_CONFIGURE` 权限校验
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 205 | AI Provider CRUD + 测试 |
| `actions-password.ts` | 113 | 修改密码 |
| `components/*` | 8 文件 | 通用设置 + AI 配置 + 密码 + 主题 + 通知偏好 |
---
## 2.24 auth认证 UI 模块)
**职责**:认证页面 UI登录/注册/布局)。
**导出函数**:纯 UI 组件(`LoginForm` / `RegisterForm` / `AuthLayout`
**依赖关系**
- 依赖:`shared/*`
- 被依赖:`app/(auth)/*`
**已知问题**
- ✅ 纯 UI 模块,无 data-access/actions/types
- ✅ 认证逻辑由 NextAuth + `shared/lib/auth-guard` 统一处理
**文件清单**
| 文件 | 职责 |
|------|------|
| `components/auth-layout.tsx` | 认证页面布局 |
| `components/login-form.tsx` | 登录表单 |
| `components/register-form.tsx` | 注册表单 |
---
## 2.25 layout布局模块
**职责**:应用骨架(侧边栏 + 顶部导航 + 导航配置)。
**导出函数**`AppSidebar` / `SidebarProvider` / `SiteHeader` + `navigation` 配置
**依赖关系**
- 依赖:`shared/hooks/use-permission``@/auth`useSession`messaging`(通知下拉)
- 被依赖:`app/(dashboard)/layout.tsx`
**已知问题**
- ⚠️ P2用权限反推角色`permissions.includes(HOMEWORK_SUBMIT) && !permissions.includes(EXAM_CREATE)`),应改用 `hasRole("student")`
- ✅ navigation.ts 无幽灵路由13 个已修复)
**文件清单**
| 文件 | 职责 |
|------|------|
| `components/app-sidebar.tsx` | 侧边栏(根据权限渲染) |
| `components/sidebar-provider.tsx` | 侧边栏状态 Context |
| `components/site-header.tsx` | 顶部导航(含通知下拉) |
| `config/navigation.ts` | 导航配置4 个角色) |
---
## 2.26 student学生 UI 模块)
**职责**:学生端 UI 组件(课程视图 + 课表筛选/视图)。
**导出函数**`StudentCoursesView` / `StudentScheduleFilters` / `StudentScheduleView`
**依赖关系**
- 依赖:`shared/*`
- 被依赖:`app/(dashboard)/student/*`
**已知问题**
- ⚠️ P2与 classes 模块的 `schedule-view.tsx`/`schedule-filters.tsx` 可能功能重叠
- ✅ 纯 UI 模块,数据由页面通过 classes data-access 获取
**文件清单**
| 文件 | 职责 |
|------|------|
| `components/student-courses-view.tsx` | 学生课程视图 |
| `components/student-schedule-filters.tsx` | 课表筛选器 |
| `components/student-schedule-view.tsx` | 学生课表视图 |
---
# 第三部分:已知架构问题和技术债
## 3.1 P0 严重问题(必须立即修复)
### P0-1文件超 1000 行硬上限3 个文件)
| 文件 | 行数 | 问题 | 拆分建议 |
|------|------|------|---------|
| `classes/data-access.ts` | ~~2104~~ → 548 | ~~混入 homework/scheduling/grades 逻辑~~ ✅ 已拆分 | 已拆为 5 个文件data-access.ts(548行) + data-access-stats.ts(531行) + data-access-schedule.ts(194行) + data-access-students.ts(244行) + data-access-admin.ts(406行),通过 re-export 保持向后兼容 |
| `homework/data-access.ts` | ~~1038~~ → 598 | ~~混入排名计算业务逻辑~~ ✅ 已拆分 | 已拆为 data-access.ts(598行) + stats-service.ts(425行),统计函数迁移至 stats-service.ts |
| `shared/db/schema.ts` | 1111 | 54 张表混合 | 按业务域拆分为 schema/auth.ts + schema/academic.ts + schema/exam.ts + ...,通过 index.ts 聚合 |
### P0-2shared/lib ↔ auth 循环依赖
```
shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
```
**影响**shared 层无法独立测试/复用;架构上基础设施不应反向依赖应用层。
**解耦建议**
- 创建 `shared/lib/session.ts` 封装 session 获取
- logger 函数改为接收 `session` 参数(由调用方传入)
- 或通过依赖注入打破循环
### P0-3dashboard 跨模块直接查询 11 张表 ✅ 已修复
`dashboard/data-access.ts``getAdminDashboardData` 原直查 sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions。
**修复方案**(已实施):
- 各模块新增 dashboard stats 函数:
- `users/data-access.ts``getUsersDashboardStats()`userCount/activeSessionsCount/userRoleCounts/recentUsers
- `classes/data-access.ts``getClassesDashboardStats()`classCount
- `textbooks/data-access.ts``getTextbooksDashboardStats()`textbookCount/chapterCount
- `questions/data-access.ts``getQuestionsDashboardStats()`questionCount
- `exams/data-access.ts``getExamsDashboardStats(scope?)`examCount支持 scope 过滤)
- `homework/stats-service.ts``getHomeworkDashboardStats(scope?)`4 个计数,支持 scope 过滤)
- dashboard 改为并行调用:`Promise.all([getUsersDashboardStats(), getClassesDashboardStats(), ...])`
- 返回值结构保持不变,调用方无需修改
### P0-4messaging 绕过 notifications 直接写通知
`messaging/actions.ts` 第 66-72 行直接调用 `createNotification`,导致用户通知偏好失效、多渠道通知无效。
**解耦建议**
- 方案 A推荐notifications 吞并 messaging 的通知部分messaging 仅保留 `messages`
- 方案 Bmessaging 改为调用 `notifications.sendNotification`,消除双向依赖
### P0-5classSchedule 表三处写入口
- `classes/data-access.ts`createClassScheduleItem 等)
- `scheduling/actions.ts`applyAutoScheduleAction 直接 transaction 写入)
- `scheduling/data-access.ts`(间接)
**影响**:数据完整性高风险。
**解耦建议**:统一 classSchedule 写入口到 scheduling 模块classes 模块仅保留读权限。
### P0-6proctoring 死代码与重复实现
- `exam-mode-config.tsx` 未集成到考试表单(监考功能无法启用)
- 事件上报存在 Server Action 与 REST API 双通道重复
**解耦建议**
-`exam-mode-config.tsx` 集成到 `exam-form.tsx`,或迁移到 exams 模块
- 删除未使用的 `/api/proctoring/event` 路由
---
## 3.2 P1 较严重问题(短期执行)
### P1-1跨模块直接 DB 查询普遍存在
| 被访问表 | 访问次数 | 应归属模块 | 主要违规者 |
|---------|---------|-----------|-----------|
| `classes` | 8+ | classes | exams, homework, grades, dashboard |
| `classEnrollments` | 6+ | classes | homework, grades, attendance, users |
| `users` | 6+ | users | 多个模块 |
| `subjects` | 6+ | school | exams, homework, questions, grades |
| `exams` | 5+ | exams | homework, grades, dashboard, classes |
| `homeworkAssignments` | 5+ | homework | classes反向直查 |
**解耦建议**:在各模块 data-access 暴露查询接口:
- `classes/data-access``getClassGradeIdsByClassIds` / `getClassStudentsByClassId` / `getActiveClassStudents`
- `exams/data-access``getExamForHomeworkCreation`
- `school/data-access``getSubjectOptions` / `getGradeOptions`
- `users/data-access``getUserNameByIds` / `getStudentInfo`
- `textbooks/data-access``getKnowledgePointOptions`
- `questions/data-access``insertQuestionWithRelations` / `deleteQuestionRecursive`
### P1-2actions 层混入数据访问逻辑 ✅ 已修复
**已完成修复**2026-06-17commit 84d66364 个模块的 actions 层 DB 操作全部下沉到 data-access
| 模块 | 问题 Action | 修复内容 |
|------|------------|---------|
| exams | `updateExamAction` / `deleteExamAction` / `duplicateExamAction` / `getExamPreviewAction` / `getSubjectsAction` / `getGradesAction` | ✅ 新增 7 个 data-access 函数getExamCreatorId/updateExamWithQuestions/deleteExamById/duplicateExam/getExamPreview/getExamSubjects/getExamGradesactions.ts 831→691 行data-access.ts 374→471 行 |
| homework | `createHomeworkAssignmentAction`157 行)/ `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction` | ✅ 新建 `data-access-write.ts`285 行10 个写函数actions.ts 387→239 行 |
| questions | `createQuestionAction` / `updateQuestionAction` / `deleteQuestionAction` / `getKnowledgePointOptionsAction` | ✅ 新增 4 个 data-access 函数createQuestionWithRelations/updateQuestionById/deleteQuestionByIdRecursive/getKnowledgePointOptionsactions.ts 294→149 行data-access.ts 138→260 行 |
| announcements | 所有写操作 Action | ✅ 新增 5 个 data-access 函数insertAnnouncement/updateAnnouncementById/deleteAnnouncementById/publishAnnouncementById/archiveAnnouncementByIdactions.ts 242→197 行data-access.ts 120→171 行 |
**剩余未修复模块**(不在本次 P1-2 范围):
- users`updateUserProfileAction` 直接 db.update
- scheduling`applyAutoScheduleAction` / `autoScheduleAction` 直接 db.transaction + db.select
### P1-3auth.ts 混合 5 类职责 ✅ 已完成
`src/auth.ts` 原 293 行混合NextAuth 配置 + 密码安全 DB 操作 + 角色规范化 + IP 解析 + 回调函数。
**已完成拆分**auth.ts 现 193 行,仅保留 NextAuth 配置):
- ✅ 密码安全 DB 操作 → `shared/lib/password-security-service.ts`getOrCreatePasswordSecurity / recordFailedLogin / resetFailedLoginserver-only
- ✅ 角色规范化 → `shared/lib/role-utils.ts`normalizeRole / resolvePrimaryRole纯函数
- ✅ bcrypt 哈希规范化 → `shared/lib/bcrypt-utils.ts`normalizeBcryptHash纯函数
- ✅ IP 解析 → `shared/lib/http-utils.ts`resolveClientIpserver-only
**后续可选优化**(未执行,需保持 NextAuth 配置不变原则下评估):
- `authorize` 回调可进一步拆分为 `checkRateLimit` / `checkAccountLockout` / `verifyPassword` / `loadUserRoles`,使 auth.ts 降至 ≤150 行
### P1-4users/import-export.ts 四重职责 ✅ 已完成
`users/import-export.ts` 原 291 行混合:导入解析 + 导出 + 用户创建(含密码哈希)+ 班级注册(跨模块写 classEnrollments
**已完成拆分**import-export.ts 现 157 行,仅保留文件解析/生成):
- ✅ 用户创建(含密码哈希、角色分配)→ `user-service.ts``batchImportUsers`82 行server-only
- ✅ 班级注册 → `class-registration.ts``registerStudentByInvitationCode`21 行server-only
-`batchImportUsers` 不再直写 `classEnrollments`,改为调用 `classes/data-access.enrollStudentByInvitationCode`
-`import-export.ts` 通过 re-export `batchImportUsers` / `UserImportResult` 保持向后兼容(`actions.ts``app/api/export/route.ts` 无需修改)
### P1-5notifications 反向依赖 messaging
`notifications/data-access.ts``in-app-channel.ts` 反向依赖 messaging 模块的偏好和 createNotification。
**解耦建议**:与 P0-4 一并解决,将 `messageNotifications``notificationPreferences` 表所有权移交 notifications 模块。
### P1-6三个 logger 重复实现 IP/Header 提取
`audit-logger.ts` / `change-logger.ts` / `login-logger.ts` / `auth.ts` 四处重复实现 IP/User-Agent 提取逻辑,且实现略有差异。
**解耦建议**:提取 `shared/lib/http-utils.ts`,导出 `getClientIp()``getUserAgent()` 统一复用。
---
## 3.3 P2 代码质量问题(机会修复)
| 序号 | 问题 | 模块 |
|------|------|------|
| P2-1 | `exams/ai-pipeline.ts` 857 行,混合 4 类职责 | exams |
| ~~P2-2~~ | ~~`exams/actions.ts` 832 行(超 800 建议)~~ ✅ 已修复P1-2 后降至 691 行) | exams |
| ~~P2-3~~ | ~~`shared/lib/ai.ts` 218 行,混合 5 类职责~~ ✅ 已修复P2-2 已拆分为 `ai/` 目录) | shared |
| P2-4 | `onboarding-gate.tsx` 业务逻辑泄漏到 shared | shared |
| P2-5 | `global-search.tsx` 业务类型硬编码在 shared | shared |
| P2-6 | `proxy.ts` 硬编码权限字符串,未复用 Permissions 常量 | proxy |
| P2-7 | `useA11yId` Hook 错放在 lib/ 而非 hooks/ | shared |
| P2-8 | `schema.ts` 分节编号混乱section 12 出现在 14b 之后) | shared/db |
| P2-9 | `audit/actions.ts` Excel 导出逻辑内联 | audit |
| P2-10 | school 模块审计日志不一致(仅 school 实体记录) | school |
| P2-11 | `announcements` 死代码 `void wasPublished` | announcements |
| P2-12 | `announcements` 权限模式不一致requireAuth vs requirePermission | announcements |
| P2-13 | `files` try-catch 吞错误 | files |
| P2-14 | `elective` runLottery 使用 Math.random | elective |
| P2-15 | `elective` selectCourse FCFS 并发超卖风险 | elective |
| P2-16 | `diagnostic` 班级报告 studentId 字段复用 | diagnostic |
| P2-17 | `layout` 用权限反推角色 | layout |
| P2-18 | `scheduling/actions.ts` 末尾 re-export data-access | scheduling |
| P2-19 | `ExamAssembly` / `ExamPreviewQuestionEditor` 10 个 props | exams |
| P2-20 | `homework/data-access.getDemoStudentUser` 使用 `auth()` 而非 auth-guard | homework |
---
## 3.4 解耦优先级路线图
### 立即执行P0
1. ~~拆分 `classes/data-access.ts`2104 行 → 按职责拆 3-4 个文件)~~ ✅ 已完成(拆为 5 个文件data-access.ts 548行 + data-access-stats.ts 531行 + data-access-schedule.ts 194行 + data-access-students.ts 244行 + data-access-admin.ts 406行
2. ~~拆分 `homework/data-access.ts`1038 行 → 分离排名逻辑)~~ ✅ 已完成(拆为 data-access.ts 598行 + stats-service.ts 425行
3. 修复 `shared/lib``auth` 循环依赖
4. dashboard 改为通过各模块 data-access 获取数据
5. messaging 写通知改为通过 notifications dispatcher
6. 统一 classSchedule 写入口到 scheduling 模块
7. 集成 proctoring/exam-mode-config 到考试表单
### 短期执行P1
8. ~~actions 层移除直接 DB 操作exams/homework/questions/announcements/users/scheduling~~ ✅ 部分完成exams/homework/questions/announcements 已修复users/scheduling 待处理)
9. ~~拆分 `auth.ts`~~ ✅ 已完成4 个辅助函数组迁移至 shared/libauth.ts 保留 NextAuth 配置)
10. ~~拆分 `users/import-export.ts`~~ ✅ 已完成(拆为 import-export.ts 157行 + user-service.ts 82行 + class-registration.ts 21行班级注册改为调用 classes/data-access
11. 消除 notifications → messaging 反向依赖
12. 提取 `shared/lib/http-utils.ts` 统一 IP 提取
13. 各模块暴露跨模块查询接口(见 P1-1
### 中期执行P2
14. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
15. `schema.ts` 按业务域分节
16. 拆分 `exams/ai-pipeline.ts`
17. ~~拆分 `shared/lib/ai.ts`~~ ✅ 已完成P2-2commit 6588f74拆分为 `ai/` 目录 6 个文件,原 ai.ts 保留为重导出)
18. shared 层业务逻辑下沉到 modules 层
19. 代码质量问题逐项修复
---
## 3.5 标杆实践(建议推广)
| 实践 | 模块 | 说明 |
|------|------|------|
| 算法纯函数化 | `scheduling/auto-scheduler.ts` | 无 DB 依赖,可独立测试,应作为算法抽取模板 |
| stats 文件拆分 | `attendance/data-access-stats.ts` | 统计逻辑独立成文件classes 应效仿 |
| data-access 多文件拆分 | `grades/data-access*.ts` | 按职责拆分为 3 个文件CRUD/分析/排名) |
| actions 辅助函数 | `course-plans/actions.ts` | handleError / revalidatePlanPaths 消除重复 |
| actions 编排模式 | `textbooks/actions.ts` | 权限校验 → 调用 data-access → revalidatePath标杆 |
| DataScope 接入 | `attendance/actions.ts` | 6 种数据范围完整支持 |
| 权限统一接入 | school / attendance / course-plans | 全部 Action 使用 requirePermission |
| 跨模块解耦 | `grades` | 通过外键引用 exams/homework不直接访问其表 |
| 渠道抽象 | `notifications/channels/` | 接口 + 工厂 + Mock 实现 |
---
# 附录 A模块间依赖矩阵
> 行表示使用方,列表示被使用方。`✅` 合理依赖,`❌` 违规直查,`⟳` 循环依赖。
| ↓ 使用 → | shared | auth | exams | homework | questions | textbooks | classes | school | dashboard | users | grades | messaging | notifications | 其他 |
|----------|--------|------|-------|----------|-----------|-----------|---------|--------|-----------|-------|--------|-----------|---------------|------|
| **shared** | - | ⟳ | - | - | - | - | - | - | - | - | - | - | - | - |
| **auth(root)** | ✅ db/lib | - | - | - | - | - | - | - | - | - | - | - | - | - |
| **exams** | ✅ | ✅ | - | - | ✅类型/❌insert | - | ❌直查 | ❌直查 | - | - | - | - | - | - |
| **homework** | ✅ | ✅ | ❌直查5处 | - | ✅关系 | - | ❌直查 | ❌直查 | - | ❌直查 | - | - | - | - |
| **questions** | ✅ | ✅ | - | - | - | ❌直查 | - | - | - | - | - | - | - | - |
| **textbooks** | ✅ | ✅ | - | - | ✅UI | - | - | - | - | - | - | - | - | - |
| **classes** | ✅ | ✅ | ❌直查 | ❌直查5表 | - | - | - | ❌直查 | - | - | ❌混入 | - | - | - |
| **school** | ✅ | ✅ | - | - | - | - | - | - | - | ⚠️可接受 | - | - | - | - |
| **grades** | ✅ | ✅ | ✅外键 | ✅外键 | - | - | ❌直查 | ❌直查 | - | ❌直查 | - | - | - | - |
| **dashboard** | ✅ | ✅ | ✅data-access | ✅data-access | ✅data-access | ✅data-access | ✅data-access | - | - | ✅data-access | - | - | - | - |
| **users** | ✅ | ✅ | - | - | - | - | ✅data-access | - | - | - | - | - | - | - |
| **messaging** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | ❌绕过 | - |
| **notifications** | ✅ | ✅ | - | - | - | - | ❌直查 | - | - | - | - | ⟳反向依赖 | - | - |
| **attendance** | ✅ | ✅ | - | - | - | - | ❌直查 | - | - | - | - | - | - | - |
| **scheduling** | ✅ | ✅ | - | - | - | - | ❌写schedule | - | - | ❌直查 | - | - | - | - |
| **proctoring** | ✅ | ✅ | ❌直查 | - | - | - | - | - | - | ❌直查 | - | - | - | - |
| **diagnostic** | ✅ | ✅ | ❌直查 | ❌直查 | ❌直查 | - | ❌直查 | - | - | ❌直查 | - | - | - | - |
| **parent** | ✅ | ✅ | - | ✅ | - | - | ✅ | - | - | - | ✅ | - | - | - |
| **elective** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | - | - |
| **course-plans** | ✅ | ✅ | - | - | - | - | ✅ | ✅ | - | ✅ | - | - | - | - |
| **audit** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | - | - |
| **announcements** | ✅ | ✅ | - | - | - | - | - | ✅ | - | - | - | - | - | - |
| **files** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | - | - |
| **settings** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | ✅ | - | - |
| **layout** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | ✅ | - | - |
---
# 附录 B关键参数影响链
### `userId`
1.`auth.ts` JWT callback 从 `users` 表查询产生,存入 JWT
2. 通过 `session.user.id` 传递到所有 Server/Client Components
3. 通过 `getAuthContext().userId` 传递到所有 Server Actions
4.`auth-guard.ts` 中用于查询 `usersToRoles`(角色)和 `classSubjectTeachers`/`grades`DataScope
5.`exams/actions.ts` 中作为 `creatorId` 写入 `exams`
6.`homework/actions.ts` 中作为 `creatorId` 写入 `homeworkAssignments`
7.`classes/data-access.ts` 中查询 `getTeacherClasses(teacherId)` / `getGradeManagedClasses(userId)`
8.`elective/actions.ts` 中作为 `teacherId`/`studentId` 用于选课过滤
### `examId`
1.`exams/actions.createExamAction` 产生CUID2写入 `exams`
2.`exams/data-access.getExamById(id)` 读取
3.`exams/actions``updateExamAction`/`deleteExamAction`/`duplicateExamAction` 用于定位考试
4. 传入 `homework/actions.createHomeworkAssignmentAction``sourceExamId` 参数
5.`homeworkAssignments` 表中作为外键关联到源考试
6.`homework/data-access.getHomeworkAssignmentAnalytics` 用于追溯作业来源
### `classId`
1.`classes/actions``createTeacherClassAction`/`createAdminClassAction` 产生
2.`classes/data-access.getClassStudents(classId)` 读取学生列表
3.`classes/data-access.getClassSchedule(classId)` 读取课表
4.`classes/data-access.getClassHomeworkInsights(classId)` 读取作业洞察(❌ 应属 homework
5.`homework/data-access.getHomeworkAssignments({ classId })` 过滤作业列表
6.`auth-guard.ts` 中通过 `classSubjectTeachers` 查询教师关联的 classIds构建 `DataScope.class_taught`
### `permission`
1.`shared/types/permissions.ts``Permissions` 常量定义54 个权限点)
2.`shared/lib/permissions.ts` 中通过 `ROLE_PERMISSIONS` 映射角色到权限列表
3.`auth.ts` JWT callback 中通过 `resolvePermissions(roleNames)` 合并多角色权限,存入 JWT
4.`proxy.ts` middleware 中通过 `token.permissions` 检查路由访问权限
5.`shared/lib/auth-guard.ts` 中通过 `requirePermission(permission)` 在 Server Action 层断言权限
6.`shared/hooks/use-permission.ts` 中通过 `hasPermission(permission)` 在客户端组件中条件渲染
7.`layout/config/navigation.ts` 中作为 `NavItem.permission` 字段过滤侧边栏菜单
### `DataScope`
1.`auth-guard.ts``resolveDataScope(userId, roles)` 根据用户角色和 DB 关系动态计算
2. 支持类型:`all` / `grade_managed` / `class_taught` / `class_members` / `children` / `owned`
3. 传递到 `exams`/`homework`/`grades`/`attendance`/`elective`/`dashboard` 的 data-access 进行行级过滤
4. 对 parent 角色,查询 `parentStudentRelations` 表构建 `{ type: "children", childrenIds: string[] }`
5.`parent/children/[studentId]/page.tsx` 中通过 `ctx.dataScope.childrenIds.includes(studentId)` 二次校验
---
# 附录 C核心函数签名索引
> 完整函数签名见 `005_architecture_data.json`。本附录仅列出关键函数。
### shared 层核心函数
```typescript
// shared/lib/auth-guard.ts
getAuthContext(): Promise<AuthContext>
requirePermission(permission: Permission): Promise<AuthContext>
requireAuth(): Promise<AuthContext>
checkPermission(permission: Permission): Promise<{ allowed: boolean; ctx: AuthContext }>
resolveDataScope(userId: string, roleNames: string[]): Promise<DataScope>
// shared/lib/permissions.ts
resolvePermissions(roleNames: string[]): Permission[]
// shared/lib/audit-logger.ts
logAudit(params: LogAuditParams): Promise<void>
// shared/lib/login-logger.ts
logLoginEvent(params: LogLoginEventParams): Promise<void>
// shared/lib/change-logger.ts
logDataChange(params: LogDataChangeParams): Promise<void>
// shared/lib/ai/ (P2-2 已拆分,原 ai.ts 保留为重导出)
// ai/client.ts
createAiChatCompletion(input: AiChatRequest): Promise<{ content, usage }>
// ai/payload-parser.ts
parseAiChatPayload(body: unknown): AiChatRequest
// ai/api-key-crypto.ts
encryptAiApiKey(value: string): string
decryptAiApiKey(value: string): string
// shared/lib/password-policy.ts
validatePassword(password: string): { valid: boolean; errors: string[] }
getPasswordStrength(password: string): "weak" | "medium" | "strong"
isAccountLocked(failedAttempts: number, lastFailedAt: Date | null): boolean
// shared/lib/rate-limit.ts
rateLimit(params: { key: string; limit: number; windowMs: number }): RateLimitResult
rateLimitKey(prefix: string, identifier: string): string
rateLimitHeaders(result: RateLimitResult): Record<string, string>
// shared/lib/excel.ts
exportToExcel(params: { sheets: ExcelSheet[] }): Promise<Buffer>
parseExcel(buffer: Buffer): Promise<ParsedSheet[]>
generateTemplate(params: { sheets: TemplateSheet[] }): Promise<Buffer>
// shared/lib/file-storage.ts
isAllowedMimeType(mimeType: string): boolean
generateStoragePath(originalName: string): string
formatFileSize(bytes: number): string
// shared/lib/utils.ts
cn(...inputs: ClassValue[]): string
formatDate(date: string | Date, locale?: string): string
```
### 业务模块核心 Actions
```typescript
// exams/actions.ts
createExamAction(prevState: ActionState, formData: FormData): Promise<ActionState<Exam>>
createAiExamAction(prevState: ActionState, formData: FormData): Promise<ActionState<{ examId: string }>>
updateExamAction(prevState: ActionState, formData: FormData): Promise<ActionState>
deleteExamAction(prevState: ActionState, formData: FormData): Promise<ActionState>
duplicateExamAction(prevState: ActionState, formData: FormData): Promise<ActionState<{ examId: string }>>
// homework/actions.ts
createHomeworkAssignmentAction(prevState: ActionState, formData: FormData): Promise<ActionState>
startHomeworkSubmissionAction(prevState: ActionState, formData: FormData): Promise<ActionState<{ submissionId: string }>>
saveHomeworkAnswerAction(prevState: ActionState, formData: FormData): Promise<ActionState>
submitHomeworkAction(prevState: ActionState, formData: FormData): Promise<ActionState>
gradeHomeworkSubmissionAction(prevState: ActionState, formData: FormData): Promise<ActionState>
// classes/actions.ts
createTeacherClassAction(prevState: ActionState, formData: FormData): Promise<ActionState>
createAdminClassAction(prevState: ActionState, formData: FormData): Promise<ActionState>
createGradeClassAction(prevState: ActionState, formData: FormData): Promise<ActionState>
// + update/delete 各 3 个,共 9 个
// grades/actions.ts
getGradeRecordsAction(params: GetGradeRecordsParams): Promise<ActionState<GradeRecord[]>>
createGradeRecordAction(prevState: ActionState, formData: FormData): Promise<ActionState>
exportGradesAction(params: ExportGradesParams): Promise<ActionState<Buffer>>
// scheduling/actions.ts
autoScheduleAction(prevState: ActionState, formData: FormData): Promise<ActionState>
applyAutoScheduleAction(prevState: ActionState, formData: FormData): Promise<ActionState>
```
### 业务模块核心 Data-access
```typescript
// exams/data-access.ts
getExams(params: GetExamsParams & { scope: DataScope }): Promise<{ items: Exam[]; total: number }>
getExamById(id: string, scope: DataScope): Promise<Exam | null>
persistExamDraft(input: ExamDraftInput): Promise<{ examId: string }>
persistAiGeneratedExamDraft(input: AiExamDraftInput): Promise<{ examId: string }>
// homework/data-access.ts
getHomeworkAssignments(params: GetHomeworkAssignmentsParams & { scope: DataScope }): Promise<{ items, total }>
getStudentHomeworkAssignments(studentId: string): Promise<StudentHomeworkAssignment[]>
getStudentDashboardGrades(studentId: string): Promise<StudentDashboardGrades>
getHomeworkAssignmentAnalytics(assignmentId: string): Promise<HomeworkAnalytics>
// classes/data-access.ts
getAdminClasses(scope: DataScope): Promise<Class[]>
getTeacherClasses(teacherId: string): Promise<Class[]>
getStudentClasses(studentId: string): Promise<Class[]>
getClassStudents(classId: string): Promise<Student[]>
getClassHomeworkInsights(classId: string): Promise<ClassHomeworkInsights> // ❌ 应属 homework
// grades/data-access.ts
getGradeRecords(params: GetGradeRecordsParams & { scope: DataScope }): Promise<GradeRecord[]>
getStudentGradeSummary(studentId: string): Promise<StudentGradeSummary>
getClassRanking(classId: string, examId?: string): Promise<ClassRanking[]>
// scheduling/auto-scheduler.ts纯函数标杆
findOptimalSlot(input: FindOptimalSlotInput): ScheduleSlot | null
validateSchedule(schedule: ScheduleItem[]): ValidationResult
autoSchedule(input: AutoScheduleInput): AutoScheduleResult
buildDefaultTimeSlots(): TimeSlot[]
```
---
## 文档维护说明
- **修改源码后**:同步更新本文档对应模块章节 + `005_architecture_data.json`
- **新增模块**:在第二部分添加模块清单 + 更新 1.1 分层架构图 + 更新附录 A 依赖矩阵
- **新增/删除导出函数**:更新对应模块的"导出函数"清单 + 附录 C
- **修改依赖关系**:更新 1.2 模块依赖关系图 + 附录 A 依赖矩阵
- **新增路由**:更新 `005_architecture_data.json``routes` 节点
- **新增数据库表**:更新 `shared/db/schema.ts` 分节 + `005``dbTables` 节点
> 完整路由表、DevOps 脚本、E2E 测试等信息见 `005_architecture_data.json`。