- 全项目逐文件审查: 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
76 KiB
Next_Edu 架构影响地图
重写日期:2026-06-17 目标:一次阅读即可直观理解整个项目架构 规则:源码修改后须同步更新本文档与
005_architecture_data.json审查依据:docs/architecture/audit/下 4 份审查报告
目录
第一部分:全局架构概览
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,不直接访问 DBmodules/之间通过对方 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 2104 行
│ ═══ 混入 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 { 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) │
│ ├─▶ db.query.homeworkAssignments [⚠️ 直接 DB] │
│ ├─▶ db.insert(homeworkSubmissions) [⚠️ 直接 DB] │
│ └─▶ 返回 submissionId │
│ │
│ └─▶ homework/actions.saveHomeworkAnswerAction │
│ └─▶ db.transaction(insert homeworkAnswers) [⚠️ 直接 DB] │
│ │
│ └─▶ homework/actions.submitHomeworkAction │
│ └─▶ db.update(homeworkSubmissions.status="submitted") │
│ │
│ 数据写入:homeworkSubmissions 表 + homeworkAnswers 表 │
│ ⚠️ 违规:actions 层直接 DB 操作,应下沉到 data-access │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 3:教师批改 │
│ ───────────────────────────────────────────────────────────────── │
│ teacher/homework/submissions/[submissionId]/page.tsx │
│ └─▶ homework/actions.gradeHomeworkSubmissionAction │
│ ├─▶ requirePermission(HOMEWORK_GRADE) │
│ └─▶ db.update(homeworkAnswers) 循环 [⚠️ 直接 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)
│
├─▶ db.query.homeworkSubmissions.findFirst ❌ 应在 data-access
│ (校验 submission 归属)
│
├─▶ db.update(homeworkSubmissions) ❌ 应在 data-access
│ SET status = "submitted", submittedAt = now()
│
└─▶ 返回 ActionState<{ submissionId }>
1.4.3 调用链路:管理员仪表盘聚合
[Route] /admin/dashboard/page.tsx (Server Component)
│
▼
[DataAccess] dashboard/data-access.getAdminDashboardData
│
├─▶ db.query.sessions.count() ❌ 跨模块直查(auth)
├─▶ db.query.users.count() ❌ 跨模块直查(users)
├─▶ db.query.usersToRoles ❌ 跨模块直查(users)
├─▶ db.query.roles ❌ 跨模块直查(users)
├─▶ db.query.classes.count() ❌ 跨模块直查(classes)
├─▶ db.query.textbooks.count() ❌ 跨模块直查(textbooks)
├─▶ db.query.chapters.count() ❌ 跨模块直查(textbooks)
├─▶ db.query.questions.count() ❌ 跨模块直查(questions)
├─▶ db.query.exams (含 scope 过滤) ❌ 跨模块直查(exams)
├─▶ db.query.homeworkAssignments ❌ 跨模块直查(homework)
└─▶ db.query.homeworkSubmissions ❌ 跨模块直查(homework)
⚠️ 单函数直查 11 张跨模块表,是本次审查最严重的封装违规
建议:各模块暴露 getModuleStats(scope) 函数,dashboard 聚合调用
第二部分:模块清单
每个模块包含:职责 · 导出函数 · 依赖关系 · 已知问题 · 文件清单
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.ts1111 行(54 张表混合,超 1000 硬上限) - ⚠️ P1:
auth.ts293 行混合 5 类职责 - ⚠️ P2:
ai.ts218 行混合 5 类职责 - ⚠️ 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 |
218 | AI 调用 + Provider 配置 + 加密 |
lib/audit-logger.ts |
- | 操作日志 |
lib/change-logger.ts |
- | 数据变更日志 |
lib/login-logger.ts |
- | 登录日志 |
lib/password-policy.ts |
- | 密码策略纯函数 |
lib/rate-limit.ts |
- | 内存滑动窗口限流 |
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 | 57 个权限点常量 |
2.2 exams(考试模块)
职责:考试全生命周期管理(创建/编辑/预览/发布/删除/复制)+ AI 辅助出题。
导出函数:
- Actions:
createExamAction/createAiExamAction/previewAiExamAction/regenerateAiQuestionAction/updateExamAction/deleteExamAction/duplicateExamAction/getExamPreviewAction/getSubjectsAction/getGradesAction - Data-access:
getExams/getExamById/persistExamDraft/persistAiGeneratedExamDraft/buildExamDescription/resolveSubjectGradeNames - AI Pipeline:
generateAiCreateDraftFromSource/generateAiPreviewData/regenerateAiQuestionByInstruction
依赖关系:
- 依赖:
shared/*、@/auth、questions(类型)、classes(❌ 直查)、school(❌ 直查 subjects/grades)、questions(❌ 直查 insert) - 被依赖:
homework(通过 sourceExamId 外键,合理)、dashboard(❌ 直查)、proctoring(❌ 直查)
已知问题:
- ❌ P0:
persistAiGeneratedExamDraft直接 insert 到questions表 - ❌ P0:
getExams/getExamById直查classes表 - ❌ P1:
getSubjectsAction/getGradesAction直查subjects/grades表(应属 school 模块) - ❌ P1:
actions.ts832 行(超 800 建议),多处直接 DB 操作 - ⚠️ P1:
ai-pipeline.ts912 行(超 800 建议),混合 4 类职责
文件清单:
| 文件 | 行数 | 职责 |
|---|---|---|
actions.ts |
832 | 10 个 Server Action(超限) |
ai-pipeline.ts |
912 | AI 出题管线(超限) |
data-access.ts |
339 | 考试 CRUD |
types.ts |
31 | 类型定义 |
hooks/use-exam-preview.ts |
295 | 预览 Hook |
components/* |
18 文件 | 考试表单/组卷/预览组件 |
2.3 homework(作业模块)
职责:作业全生命周期(创建/发布/作答/批改/分析)。
导出函数:
- Actions:
createHomeworkAssignmentAction/startHomeworkSubmissionAction/saveHomeworkAnswerAction/submitHomeworkAction/gradeHomeworkSubmissionAction - Data-access:
getHomeworkAssignments/getHomeworkAssignmentById/getHomeworkSubmissions/getStudentHomeworkAssignments/getStudentHomeworkTakeData/getStudentDashboardGrades/getHomeworkAssignmentAnalytics/getHomeworkAssignmentReviewList/getHomeworkSubmissionDetails/getTeacherGradeTrends/getDemoStudentUser
依赖关系:
- 依赖:
shared/*、@/auth、exams(❌ 直查 5 处)、classes(❌ 直查)、school(❌ 直查 subjects)、users(❌ 直查) - 被依赖:
dashboard(通过 data-access,合理)、parent(通过 data-access,合理)、classes(❌ classes 反向直查 homework 表)
已知问题:
- ❌ P0:
data-access.ts1038 行(超 1000 硬上限),必须拆分 - ❌ P0:
getStudentDashboardGrades混入 150+ 行排名计算业务逻辑 - ❌ P0:
getHomeworkAssignmentAnalytics混入 145+ 行错误率统计业务逻辑 - ❌ P1:5 处直查
exams表 - ❌ P1:
actions.ts多处直接 DB 操作(createHomeworkAssignmentAction157 行)
文件清单:
| 文件 | 行数 | 职责 |
|---|---|---|
data-access.ts |
1038 | 作业 CRUD + 学生视角 + 分析 + 批改(超硬上限) |
actions.ts |
387 | 5 个 Server Action |
types.ts |
186 | 类型定义 |
schema.ts |
29 | Zod 校验 |
2.4 questions(题库模块)
职责:题库管理(题目 CRUD、知识点关联、题型支持)。
导出函数:
- Actions:
getQuestionsAction/createQuestionAction/updateQuestionAction/deleteQuestionAction/getKnowledgePointOptionsAction - Data-access:
getQuestions/insertQuestionWithRelations(错放 actions)/deleteQuestionRecursive(错放 actions)
依赖关系:
- 依赖:
shared/*、@/auth、textbooks(❌ actions 直查 knowledgePoints/chapters/textbooks) - 被依赖:
exams(通过类型导入,合理)、textbooks(UI 组合,合理)
已知问题:
- ❌ P1:写操作函数错放在
actions.ts(insertQuestionWithRelations/deleteQuestionRecursive) - ❌ P1:
getKnowledgePointOptionsAction直查 textbooks 模块表 - ⚠️ P2:
data-access.ts仅 129 行,写操作缺失
文件清单:
| 文件 | 行数 | 职责 |
|---|---|---|
actions.ts |
294 | 5 个 Server Action(含错放的 data-access 函数) |
data-access.ts |
129 | 仅读查询 |
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(❌ 直查)
已知问题:
- ✅ 无跨模块 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/parent/course-plans/users(8+ 处直查 classes 表)
已知问题:
- ❌ P0:
data-access.ts2104 行(超 1000 硬上限 2.1 倍),必须拆分 - ❌ 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 |
2104 | 班级 CRUD + 作业洞察 + 课表 + 成绩(严重超限) |
actions.ts |
765 | 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/batchImportUsers/exportUsersToExcel
依赖关系:
- 依赖:
shared/*、@/auth、classes(❌batchImportUsers直查 classes + 直写 classEnrollments) - 被依赖:
dashboard(❌ 直查)、grades(❌ 直查)、homework(❌ 直查)
已知问题:
- ❌ P1:
import-export.ts四重职责混合(导入解析 + 导出 + 用户创建 + 班级注册) - ❌ P1:
batchImportUsers跨模块写classEnrollments(classes 模块的写操作) - ❌ P1:
updateUserProfile绕过 data-access 直接 DB 写 - ⚠️ P2:
data-access.ts仅 71 行,写操作缺失
文件清单:
| 文件 | 行数 | 职责 |
|---|---|---|
import-export.ts |
291 | 导入解析 + 导出 + 用户创建(职责混合) |
actions.ts |
151 | 5 个 Server Action |
data-access.ts |
71 | 仅 getUserProfile |
2.12 dashboard(仪表盘模块)
职责:管理员/教师/学生仪表盘数据聚合。
导出函数:
- Data-access:
getAdminDashboardData/getTeacherDashboardData/getStudentDashboardData
依赖关系:
- 依赖:
shared/*、@/auth、classes(合理)、homework(合理)、grades(合理)、❌ 直查 11 张跨模块表 - 被依赖:无
已知问题:
- ❌ P0:
getAdminDashboardData直查 11 张跨模块表(sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions) - ⚠️ P2:教师仪表盘直查
users表获取教师姓名 - ✅ 学生/教师仪表盘正确通过各模块 data-access 获取数据
文件清单:
| 文件 | 行数 | 职责 |
|---|---|---|
data-access.ts |
- | 仪表盘数据聚合(含违规直查) |
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 - 被依赖:无
已知问题:
- ⚠️ P2:Excel 导出逻辑内联在 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 - Data-access:
getAnnouncements/getAnnouncementById
依赖关系:
- 依赖:
shared/*、@/auth、school(合理,获取年级列表) - 被依赖:无
已知问题:
- ❌ P1:所有写操作直接在 actions 层
db.insert/update/delete,未下沉到 data-access - ⚠️ P2:死代码
void wasPublished - ⚠️ P2:
getAnnouncementsAction使用requireAuth()而非requirePermission(ANNOUNCEMENT_READ)
文件清单:
| 文件 | 行数 | 职责 |
|---|---|---|
actions.ts |
242 | 6 个 Server Action(含直接 DB 写) |
data-access.ts |
120 | 仅 2 个只读函数 |
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:
selectCourseFCFS 模式存在并发超卖风险 - ✅ 权限校验完整(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直接 importdb和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 | 混入 homework/scheduling/grades 逻辑 | 拆为 data-access.ts + data-access-enrollments.ts + data-access-insights.ts;迁移 homework/scheduling/grades 逻辑回所属模块 |
homework/data-access.ts |
1038 | 混入排名计算业务逻辑 | 拆为 data-access.ts + data-access-student.ts + data-access-analytics.ts + data-access-grading.ts |
shared/db/schema.ts |
1111 | 54 张表混合 | 按业务域拆分为 schema/auth.ts + schema/academic.ts + schema/exam.ts + ...,通过 index.ts 聚合 |
P0-2:shared/lib ↔ auth 循环依赖
shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
影响:shared 层无法独立测试/复用;架构上基础设施不应反向依赖应用层。
解耦建议:
- 创建
shared/lib/session.ts封装 session 获取 - logger 函数改为接收
session参数(由调用方传入) - 或通过依赖注入打破循环
P0-3:dashboard 跨模块直接查询 11 张表
dashboard/data-access.ts 的 getAdminDashboardData 直查 sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions。
解耦建议:
- 各模块暴露
getModuleStats(scope?)函数 - dashboard 聚合调用:
Promise.all([getUsersStats(scope), getClassStats(scope), ...]) - 至少消除 dashboard 中重复实现的 exam/homework scope 过滤
P0-4:messaging 绕过 notifications 直接写通知
messaging/actions.ts 第 66-72 行直接调用 createNotification,导致用户通知偏好失效、多渠道通知无效。
解耦建议:
- 方案 A(推荐):notifications 吞并 messaging 的通知部分,messaging 仅保留
messages表 - 方案 B:messaging 改为调用
notifications.sendNotification,消除双向依赖
P0-5:classSchedule 表三处写入口
classes/data-access.ts(createClassScheduleItem 等)scheduling/actions.ts(applyAutoScheduleAction 直接 transaction 写入)scheduling/data-access.ts(间接)
影响:数据完整性高风险。
解耦建议:统一 classSchedule 写入口到 scheduling 模块,classes 模块仅保留读权限。
P0-6:proctoring 死代码与重复实现
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/getActiveClassStudentsexams/data-access:getExamForHomeworkCreationschool/data-access:getSubjectOptions/getGradeOptionsusers/data-access:getUserNameByIds/getStudentInfotextbooks/data-access:getKnowledgePointOptionsquestions/data-access:insertQuestionWithRelations/deleteQuestionRecursive
P1-2:actions 层混入数据访问逻辑
| 模块 | 问题 Action | 违规 |
|---|---|---|
| exams | updateExamAction / deleteExamAction / duplicateExamAction / getExamPreviewAction |
直接 db.query + db.insert/update/delete |
| homework | createHomeworkAssignmentAction(157 行)/ startHomeworkSubmissionAction / saveHomeworkAnswerAction / submitHomeworkAction / gradeHomeworkSubmissionAction |
直接 DB 操作 |
| questions | createQuestionAction / updateQuestionAction / deleteQuestionAction |
内联 db.transaction |
| announcements | 所有写操作 Action | 直接 db.insert/update/delete |
| users | updateUserProfileAction |
直接 db.update |
| scheduling | applyAutoScheduleAction / autoScheduleAction |
直接 db.transaction + db.select |
解耦建议:actions 层仅做"权限校验 → 解析 → 调用 data-access → revalidatePath → 返回",所有 DB 操作下沉到 data-access。
P1-3:auth.ts 混合 5 类职责
src/auth.ts 293 行混合:NextAuth 配置 + 密码安全 DB 操作 + 角色规范化 + IP 解析 + 回调函数。
解耦建议:
- 密码安全 DB 操作 →
shared/lib/password-security-service.ts - 角色规范化 →
shared/lib/role-utils.ts - IP 解析 →
shared/lib/http-utils.ts(与三个 logger 共用) authorize回调拆分为checkRateLimit/checkAccountLockout/verifyPassword/loadUserRoles
P1-4:users/import-export.ts 四重职责
同时处理:导入解析 + 导出 + 用户创建(含密码哈希)+ 班级注册(跨模块写 classEnrollments)。
解耦建议:
- 拆分为
import.ts(解析+校验)+export.ts(模板生成+列表导出) - 用户创建逻辑迁移至
data-access.ts的createUser - classEnrollments 写入改为调用
classes/data-access.enrollStudentByInvitationCode
P1-5:notifications 反向依赖 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 912 行,混合 4 类职责 |
exams |
| P2-2 | exams/actions.ts 832 行(超 800 建议) |
exams |
| P2-3 | shared/lib/ai.ts 218 行,混合 5 类职责 |
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)
- 拆分
classes/data-access.ts(2104 行 → 按职责拆 3-4 个文件) - 拆分
homework/data-access.ts(1038 行 → 分离排名逻辑) - 修复
shared/lib↔auth循环依赖 - dashboard 改为通过各模块 data-access 获取数据
- messaging 写通知改为通过 notifications dispatcher
- 统一 classSchedule 写入口到 scheduling 模块
- 集成 proctoring/exam-mode-config 到考试表单
短期执行(P1)
- actions 层移除直接 DB 操作(exams/homework/questions/announcements/users/scheduling)
- 拆分
auth.ts - 拆分
users/import-export.ts - 消除 notifications → messaging 反向依赖
- 提取
shared/lib/http-utils.ts统一 IP 提取 - 各模块暴露跨模块查询接口(见 P1-1)
中期执行(P2)
- 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
schema.ts按业务域分节- 拆分
exams/ai-pipeline.ts - shared 层业务逻辑下沉到 modules 层
- 代码质量问题逐项修复
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 | ✅ | ✅ | ❌直查 | ✅/❌直查 | ❌直查 | ❌直查 | ✅/❌直查 | - | - | ❌直查 | - | - | - | - |
| users | ✅ | ✅ | - | - | - | - | ❌写enrollments | - | - | - | - | - | - | - |
| messaging | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | ❌绕过 | - |
| notifications | ✅ | ✅ | - | - | - | - | ❌直查 | - | - | - | - | ⟳反向依赖 | - | - |
| attendance | ✅ | ✅ | - | - | - | - | ❌直查 | - | - | - | - | - | - | - |
| scheduling | ✅ | ✅ | - | - | - | - | ❌写schedule | - | - | ❌直查 | - | - | - | - |
| proctoring | ✅ | ✅ | ❌直查 | - | - | - | - | - | - | ❌直查 | - | - | - | - |
| diagnostic | ✅ | ✅ | ❌直查 | ❌直查 | ❌直查 | - | ❌直查 | - | - | ❌直查 | - | - | - | - |
| parent | ✅ | ✅ | - | ✅ | - | - | ✅ | - | - | - | ✅ | - | - | - |
| elective | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | - | - |
| course-plans | ✅ | ✅ | - | - | - | - | ✅ | ✅ | - | ✅ | - | - | - | - |
| audit | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | - | - |
| announcements | ✅ | ✅ | - | - | - | - | - | ✅ | - | - | - | - | - | - |
| files | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | - | - |
| settings | ✅ | ✅ | - | - | - | - | - | - | - | - | - | ✅ | - | - |
| layout | ✅ | ✅ | - | - | - | - | - | - | - | - | - | ✅ | - | - |
附录 B:关键参数影响链
userId
- 由
auth.tsJWT callback 从users表查询产生,存入 JWT - 通过
session.user.id传递到所有 Server/Client Components - 通过
getAuthContext().userId传递到所有 Server Actions - 在
auth-guard.ts中用于查询usersToRoles(角色)和classSubjectTeachers/grades(DataScope) - 在
exams/actions.ts中作为creatorId写入exams表 - 在
homework/actions.ts中作为creatorId写入homeworkAssignments表 - 在
classes/data-access.ts中查询getTeacherClasses(teacherId)/getGradeManagedClasses(userId) - 在
elective/actions.ts中作为teacherId/studentId用于选课过滤
examId
- 由
exams/actions.createExamAction产生(CUID2),写入exams表 - 被
exams/data-access.getExamById(id)读取 - 被
exams/actions的updateExamAction/deleteExamAction/duplicateExamAction用于定位考试 - 传入
homework/actions.createHomeworkAssignmentAction的sourceExamId参数 - 在
homeworkAssignments表中作为外键关联到源考试 - 被
homework/data-access.getHomeworkAssignmentAnalytics用于追溯作业来源
classId
- 由
classes/actions的createTeacherClassAction/createAdminClassAction产生 - 被
classes/data-access.getClassStudents(classId)读取学生列表 - 被
classes/data-access.getClassSchedule(classId)读取课表 - 被
classes/data-access.getClassHomeworkInsights(classId)读取作业洞察(❌ 应属 homework) - 被
homework/data-access.getHomeworkAssignments({ classId })过滤作业列表 - 在
auth-guard.ts中通过classSubjectTeachers查询教师关联的 classIds,构建DataScope.class_taught
permission
- 由
shared/types/permissions.ts的Permissions常量定义(57 个权限点) - 在
shared/lib/permissions.ts中通过ROLE_PERMISSIONS映射角色到权限列表 - 在
auth.tsJWT callback 中通过resolvePermissions(roleNames)合并多角色权限,存入 JWT - 在
proxy.tsmiddleware 中通过token.permissions检查路由访问权限 - 在
shared/lib/auth-guard.ts中通过requirePermission(permission)在 Server Action 层断言权限 - 在
shared/hooks/use-permission.ts中通过hasPermission(permission)在客户端组件中条件渲染 - 在
layout/config/navigation.ts中作为NavItem.permission字段过滤侧边栏菜单
DataScope
- 由
auth-guard.ts的resolveDataScope(userId, roles)根据用户角色和 DB 关系动态计算 - 支持类型:
all/grade_managed/class_taught/class_members/children/owned - 传递到
exams/homework/grades/attendance/elective/dashboard的 data-access 进行行级过滤 - 对 parent 角色,查询
parentStudentRelations表构建{ type: "children", childrenIds: string[] } - 在
parent/children/[studentId]/page.tsx中通过ctx.dataScope.childrenIds.includes(studentId)二次校验
附录 C:核心函数签名索引
完整函数签名见
005_architecture_data.json。本附录仅列出关键函数。
shared 层核心函数
// 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.ts
createAiChatCompletion(input: AiChatRequest): Promise<{ content, usage }>
parseAiChatPayload(body: unknown): AiChatRequest
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
// 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
// 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。