Files
NextEdu/docs/architecture/004_architecture_impact_map.md

79 KiB
Raw Blame History

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不直接访问 DB
  • modules/ 之间通过对方 data-access 通信,不直接查询对方表
  • shared/ 是被依赖方,不应反向依赖 app/modules/
  • src/auth.tssrc/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 { 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
   │
   ├─▶ 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(循环依赖)

已知问题

  • P0shared/lib/*@/auth 循环依赖
  • ⚠️ P1schema.ts 1111 行54 张表混合,超 1000 硬上限)
  • ⚠️ P1auth.ts 293 行混合 5 类职责
  • ⚠️ P2ai.ts 218 行混合 5 类职责
  • ⚠️ P2onboarding-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 辅助出题。

导出函数

  • ActionscreateExamAction / createAiExamAction / previewAiExamAction / regenerateAiQuestionAction / updateExamAction / deleteExamAction / duplicateExamAction / getExamPreviewAction / getSubjectsAction / getGradesAction
  • Data-accessgetExams / getExamById / persistExamDraft / persistAiGeneratedExamDraft / buildExamDescription / resolveSubjectGradeNames
  • AI PipelinegenerateAiCreateDraftFromSource / generateAiPreviewData / regenerateAiQuestionByInstruction

依赖关系

  • 依赖:shared/*@/authquestions(类型)、classes 直查)、school 直查 subjects/gradesquestions 直查 insert
  • 被依赖:homework(通过 sourceExamId 外键,合理)、dashboard(通过 data-accessP0-4 已修复)、proctoring 直查)

已知问题

  • P0persistAiGeneratedExamDraft 直接 insert 到 questions
  • P0getExams/getExamById 直查 classes
  • P1getSubjectsAction/getGradesAction 直查 subjects/grades 表(应属 school 模块)
  • P1actions.ts 832 行(超 800 建议),多处直接 DB 操作
  • ⚠️ P1ai-pipeline.ts 912 行(超 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作业模块

职责:作业全生命周期(创建/发布/作答/批改/分析)。

导出函数

  • ActionscreateHomeworkAssignmentAction / startHomeworkSubmissionAction / saveHomeworkAnswerAction / submitHomeworkAction / gradeHomeworkSubmissionAction
  • Data-accessgetHomeworkAssignments / getHomeworkAssignmentById / getHomeworkSubmissions / getStudentHomeworkAssignments / getStudentHomeworkTakeData / getHomeworkAssignmentReviewList / getHomeworkSubmissionDetails / getDemoStudentUser / isRecord / toQuestionContent / getAssignmentMaxScoreById(后三者供 stats-service 使用)
  • Stats-servicegetTeacherGradeTrends / getHomeworkAssignmentAnalytics / getStudentDashboardGrades(从 data-access.ts re-export 以保持向后兼容)

依赖关系

  • 依赖:shared/*@/authexams 直查 5 处)、classes 直查)、school 直查 subjectsusers 直查)
  • 被依赖:dashboard(通过 data-access合理parent(通过 data-access合理classes classes 反向直查 homework 表)

已知问题

  • P0 已解决:data-access.ts 已拆分至 596 行(原 1038 行超 1000 硬上限),统计函数迁移至 stats-service.ts
  • P0 已解决:getStudentDashboardGrades 排名计算逻辑迁移至 stats-service.ts
  • P0 已解决:getHomeworkAssignmentAnalytics 错误率统计逻辑迁移至 stats-service.ts
  • P15 处直查 exams
  • P1actions.ts 多处直接 DB 操作(createHomeworkAssignmentAction 157 行)

文件清单

文件 行数 职责
data-access.ts 596 作业 CRUD + 学生视角 + 批改(含 re-export stats 函数)
stats-service.ts 346 统计分析(教师趋势/作业分析/学生仪表盘成绩)
actions.ts 387 5 个 Server Action
types.ts 186 类型定义
schema.ts 29 Zod 校验

2.4 questions题库模块

职责:题库管理(题目 CRUD、知识点关联、题型支持

导出函数

  • ActionsgetQuestionsAction / createQuestionAction / updateQuestionAction / deleteQuestionAction / getKnowledgePointOptionsAction
  • Data-accessgetQuestions / insertQuestionWithRelations(错放 actions/ deleteQuestionRecursive(错放 actions

依赖关系

  • 依赖:shared/*@/authtextbooks actions 直查 knowledgePoints/chapters/textbooks
  • 被依赖:exams(通过类型导入,合理)、textbooksUI 组合,合理)

已知问题

  • P1写操作函数错放在 actions.tsinsertQuestionWithRelations / deleteQuestionRecursive
  • P1getKnowledgePointOptionsAction 直查 textbooks 模块表
  • ⚠️ P2data-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 内容编辑、知识图谱)。

导出函数

  • ActionsgetTextbooksAction / 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成绩模块— 标杆模块(拆分范例)

职责:成绩分析(录入/查询/统计/导出/趋势对比分析)。

导出函数

  • ActionsgetGradeRecordsAction / createGradeRecordAction / updateGradeRecordAction / deleteGradeRecordAction / exportGradesAction / getGradeTrendAction / getClassComparisonAction / getSubjectComparisonAction / getGradeDistributionAction / getClassRankingAction / getRankingTrendAction
  • Data-accessgetGradeRecords / getStudentGradeSummary / getClassRanking / getClassStudentsForEntry / getClassGradeStats / getClassGradeStatsWithMeta / getGradeTrend / getClassComparison / getSubjectComparison / getGradeDistribution / getRankingTrend

依赖关系

  • 依赖:shared/*@/authclasses 直查 classes/classEnrollmentsschool 直查 subjectsusers 直查)
  • 被依赖:parent(通过 data-access合理dashboard

已知问题

  • P1多处直查 classes/classEnrollments/subjects/users
  • ⚠️ P2统计计算业务逻辑混入 data-accessgetClassGradeStats / 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 + 学生/教师管理 + 邀请码注册。

导出函数

  • ActionscreateTeacherClassAction / updateTeacherClassAction / deleteTeacherClassAction / createAdminClassAction / updateAdminClassAction / deleteAdminClassAction / createGradeClassAction / updateGradeClassAction / deleteGradeClassAction
  • Data-accessgetAdminClasses / getTeacherClasses / getGradeManagedClasses / getStudentClasses / getClassDetails / getClassStudents / getClassSchedule / getClassHomeworkInsights / getGradeHomeworkInsights / getStudentsSubjectScores / createClassScheduleItem / updateClassScheduleItem / deleteClassScheduleItem

依赖关系

  • 依赖:shared/*@/authschool actions 直查 grades 表)、homework data-access 直查 5 张 homework 表)、exams data-access 直查)
  • 被依赖:exams/homework/grades/attendance/scheduling/dashboard(通过 data-accessP0-4 已修复)/parent/course-plans/users8+ 处直查 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
  • P0classSchedule 表三处写入口(数据完整性高风险)
  • P1actions.ts 直查 grades 表做权限校验
  • P1getSessionTeacherId 在 data-access 调用 auth()

文件清单

文件 行数 职责
data-access.ts 656 核心班级 CRUD + 邀请码 + 教师班级管理(含 re-export 向后兼容)
data-access-stats.ts 604 作业统计查询(班级/年级作业洞察)
data-access-schedule.ts 230 课表查询(学生/班级课表 CRUD
data-access-students.ts 280 学生相关查询(科目成绩、学生名单、学生班级)
data-access-admin.ts 441 管理员班级管理(管理员班级 CRUD、年级管理班级查询
actions.ts 765 9 个 Server Action三组重复
types.ts 201 类型定义(含跨领域类型污染)

2.8 school学校模块

职责:学校/学年/部门/年级的 CRUD。

导出函数

  • ActionsgetSchoolsAction / createSchoolAction / updateSchoolAction / deleteSchoolAction / getAcademicYearsAction / createAcademicYearAction / updateAcademicYearAction / deleteAcademicYearAction / getDepartmentsAction / createDepartmentAction / updateDepartmentAction / deleteDepartmentAction / getGradesAction / createGradeAction / updateGradeAction / deleteGradeAction / getStaffOptions
  • Data-access与 actions 对应的只读查询

依赖关系

  • 依赖:shared/*@/authusers⚠️ getStaffOptions 直查 users/roles可接受
  • 被依赖:exams 直查 subjects/gradeshomework 直查 subjectsgrades 直查 subjectsquestions 直查)、classes actions 直查 grades 表)、course-plans(合理)

已知问题

  • ⚠️ P2审计日志不一致仅 school 实体记录department/academicYear/grade 未记录)
  • ⚠️ P2getStaffOptions/getGrades 直查 users/roles展示用可接受

文件清单

文件 行数 职责
actions.ts 325 17 个 Server Action
data-access.ts 186 只读查询
schema.ts 51 Zod 校验
types.ts 42 类型定义

2.9 scheduling排课模块

职责:自动排课算法 + 课表调整 + 排课规则管理。

导出函数

  • ActionsautoScheduleAction / applyAutoScheduleAction / getSchedulingRulesAction / updateSchedulingRulesAction / getScheduleChangesAction / createScheduleChangeAction / updateScheduleChangeAction / deleteScheduleChangeAction
  • Data-accessgetSchedulingRules / getScheduleChanges / getAdminClassesForScheduling / getTeachersForScheduling / getClassroomsForScheduling / getClassSubjectsForScheduling
  • 算法:findOptimalSlot / validateSchedule / autoSchedule / buildDefaultTimeSlots(纯函数,标杆)

依赖关系

  • 依赖:shared/*@/authclasses actions 直查 users + 直写 classScheduleschool⚠️ 排课辅助查询,可接受)
  • 被依赖:与 classes 共写 classSchedule

已知问题

  • P0applyAutoScheduleAction 直接 transaction 写 classSchedule 表(第三个写入口)
  • P1autoScheduleAction 直查 users
  • ⚠️ P2actions.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考勤模块— 结构典范

职责:考勤记录管理 + 统计分析。

导出函数

  • ActionsgetAttendanceRecordsAction / createAttendanceRecordAction / updateAttendanceRecordAction / deleteAttendanceRecordAction / getStudentAttendanceAction / getAttendanceStatsAction
  • Data-accessgetAttendanceRecords / createAttendanceRecord / updateAttendanceRecord / deleteAttendanceRecord / getClassStudentsForAttendance / getAttendanceStats

依赖关系

  • 依赖:shared/*@/authclasses getClassStudentsForAttendance 直查 classEnrollments
  • 被依赖:无

已知问题

  • ⚠️ P2getClassStudentsForAttendance 直查 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用户模块

职责:用户资料管理 + 批量导入导出。

导出函数

  • ActionsgetUserProfileAction / updateUserProfileAction / importUsersAction / exportUsersAction / downloadUserTemplateAction
  • Data-accessgetUserProfile
  • Import-exportgenerateUserImportTemplate / parseUserImportData / batchImportUsers / exportUsersToExcel

依赖关系

  • 依赖:shared/*@/authclasses batchImportUsers 直查 classes + 直写 classEnrollments
  • 被依赖:dashboard(通过 data-accessP0-4 已修复)、grades 直查)、homework 直查)

已知问题

  • P1import-export.ts 四重职责混合(导入解析 + 导出 + 用户创建 + 班级注册)
  • P1batchImportUsers 跨模块写 classEnrollmentsclasses 模块的写操作)
  • P1updateUserProfile 绕过 data-access 直接 DB 写
  • ⚠️ P2data-access.ts 仅 71 行,写操作缺失

文件清单

文件 行数 职责
import-export.ts 291 导入解析 + 导出 + 用户创建(职责混合)
actions.ts 151 5 个 Server Action
data-access.ts 71 仅 getUserProfile

2.12 dashboard仪表盘模块

职责:管理员/教师/学生仪表盘数据聚合。

导出函数

  • Data-accessgetAdminDashboardData / getTeacherDashboardData / getStudentDashboardData

依赖关系

  • 依赖:shared/*@/authclasses(通过 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私信模块

职责:站内私信 + 站内通知列表 + 通知偏好。

导出函数

  • ActionssendMessageAction / getMessagesAction / getMessageAction / deleteMessageAction / getNotificationsAction / markNotificationReadAction / markAllNotificationsReadAction / getNotificationPreferencesAction / updateNotificationPreferencesAction
  • Data-accesscreateNotification / getNotifications / getRecipients
  • Notification-preferencesgetNotificationPreferences / updateNotificationPreferences

依赖关系

  • 依赖:shared/*@/auth 绕过 notifications 直接写 messageNotifications
  • 被依赖:notifications 反向依赖 messaging 的偏好和 in-app 渠道)、settings(通知偏好表单)、layout(通知下拉)

已知问题

  • P0sendMessageAction 绕过 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

导出函数

  • ActionssendNotificationAction / sendClassNotificationAction
  • DispatchersendNotification(payload)
  • ChannelsInAppChannelSender / SmsChannelSender / EmailChannelSender / WeChatChannelSender

依赖关系

  • 依赖:shared/*@/auth 反向依赖 messaging(偏好 + in-app 渠道 + createNotification
  • 被依赖messaging 绕过它)

已知问题

  • P0不拥有任何数据全部依赖 messaging 模块
  • P0与 messaging 双向依赖
  • P1类型系统不一致messaging 按业务类别notifications 按严重级别)
  • ⚠️ P1sendClassNotificationAction 直查 classes/classEnrollments
  • ⚠️ P1发送日志仅 consolenotification_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审计模块

职责:操作日志 + 登录日志 + 数据变更日志查询与导出。

导出函数

  • ActionsgetAuditLogsAction / getLoginLogsAction / getDataChangeLogsAction / exportAuditLogsAction / exportLoginLogsAction / exportDataChangeLogsAction
  • Data-accessgetAuditLogs / 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 + 发布/归档。

导出函数

  • ActionsgetAnnouncementsAction / createAnnouncementAction / updateAnnouncementAction / deleteAnnouncementAction / publishAnnouncementAction / archiveAnnouncementAction
  • Data-accessgetAnnouncements / getAnnouncementById

依赖关系

  • 依赖:shared/*@/authschool(合理,获取年级列表)
  • 被依赖:无

已知问题

  • P1所有写操作直接在 actions 层 db.insert/update/delete,未下沉到 data-access
  • ⚠️ P2死代码 void wasPublished
  • ⚠️ P2getAnnouncementsAction 使用 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-accessgetAllFileAttachments / 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
  • ⚠️ P2actions.tsdata-access 被路由直接调用
  • 职责单一,不跨模块查询

文件清单

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

2.18 course-plans课程计划模块

职责:课程计划 CRUD + 周计划项 CRUD + 排序。

导出函数

  • ActionsgetCoursePlansAction / getCoursePlanByIdAction / createCoursePlanAction / updateCoursePlanAction / deleteCoursePlanAction / createCoursePlanItemAction / updateCoursePlanItemAction / deleteCoursePlanItemAction / toggleCoursePlanItemCompletedAction
  • Data-access与 actions 对应

依赖关系

  • 依赖:shared/*@/authclasses合理getAdminClasses/getStaffOptionsschool合理getAcademicYears
  • 被依赖:无

已知问题

  • ⚠️ P2getSubjectOptions 直查 subjectssubjects 无独立模块,可接受)
  • actions 层使用 handleError/revalidatePlanPaths 辅助函数(良好范例)

文件清单

文件 行数 职责
data-access.ts 320 课程计划 + 周计划项 CRUD
actions.ts 265 9 个 Server Action
schema.ts - Zod 校验
types.ts - 类型定义

2.19 parent家长模块

职责:家长视角的子女数据聚合与展示。

导出函数

  • Data-accessgetChildren / getChildBasicInfo / getChildDashboardData

依赖关系

  • 依赖:shared/*@/authclasses(合理)、homework(合理)、grades(合理)
  • 被依赖:无

已知问题

  • ⚠️ P2getChildBasicInfo 多次串行查询,可优化为 join
  • 职责单一,正确复用其他模块 data-access

文件清单

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

2.20 elective选课模块

职责:选修课程管理 + 学生选课 + 抽签。

导出函数

  • ActionsgetElectiveCoursesAction / createElectiveCourseAction / updateElectiveCourseAction / deleteElectiveCourseAction / getStudentSelectionsAction / selectCourseAction / dropCourseAction / runLotteryAction / getAvailableCoursesForStudentAction
  • Data-accessgetElectiveCourses / getElectiveCourseById / createElectiveCourse / updateElectiveCourse / deleteElectiveCourse / selectCourse / dropCourse / runLottery / getStudentSelections / getAvailableCoursesForStudent

依赖关系

  • 依赖:shared/*@/auth
  • 被依赖:无

已知问题

  • ⚠️ P1data-access.tsdata-access-selections.ts 重复定义 mapCourseRow/buildCourseSelect60 行重复)
  • ⚠️ P2runLottery 使用 Math.random(),结果不可复现
  • ⚠️ P2selectCourse 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监考模块

职责:考试监考事件记录 + 防作弊监控 + 监考面板。

导出函数

  • ActionsrecordProctoringEventAction / getProctoringDashboardAction
  • Data-accessrecordProctoringEvent / getExamForProctoring / getExamProctoringSummary / getStudentProctoringStatuses / getRecentProctoringEvents

依赖关系

  • 依赖:shared/*@/authexams 直查 exams/examSubmissionsusers 直查)
  • 被依赖:无

已知问题

  • P0exam-mode-config.tsx 未集成到考试表单(死代码,监考功能无法启用)
  • P0事件上报存在 Server Action 与 REST API 双通道重复
  • ⚠️ P1跨模块直查 exams/examSubmissions/users(监考本质是考试扩展,可接受但需标注)
  • ⚠️ P2actions.ts 直接 import dbexamSubmissions

文件清单

文件 行数 职责
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学情诊断模块

职责:知识点掌握度查询 + 诊断报告生成。

导出函数

  • ActionsgenerateStudentDiagnosticReportAction / generateClassDiagnosticReportAction / publishDiagnosticReportAction / deleteDiagnosticReportAction / getDiagnosticReportsAction / getStudentMasteryAction
  • Data-accessupdateMasteryFromSubmission / getStudentMastery / getClassMasteryOverview
  • Data-access-reportscreateDiagnosticReport / getDiagnosticReport / getDiagnosticReports / deleteDiagnosticReport / publishDiagnosticReport

依赖关系

  • 依赖:shared/*@/authexams 直查 examSubmissions/submissionAnswersquestions 直查 questionsToKnowledgePointsclasses 直查 classEnrollments/classes/users
  • 被依赖:无

已知问题

  • P1updateMasteryFromSubmission 跨模块直查 4 张表(与 exams/homework/questions 紧耦合)
  • ⚠️ P2data-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 管理 + 密码修改 + 个人资料 + 主题偏好 + 通知偏好。

导出函数

  • ActionsgetAiProvidersAction / createAiProviderAction / updateAiProviderAction / deleteAiProviderAction / testAiProviderAction
  • Actions-passwordchangePasswordAction

依赖关系

  • 依赖:shared/*@/authmessaging(通知偏好表单调用 messaging Action
  • 被依赖:无

已知问题

  • ⚠️ P2混合 5 类职责AI Provider + 密码 + 资料 + 主题 + 通知偏好)
  • ⚠️ P2data-access.tsactions.ts 直接使用 db
  • ⚠️ P2notification-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@/authuseSessionmessaging(通知下拉)
  • 被依赖: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 → 656 混入 homework/scheduling/grades 逻辑 已拆分 已拆为 5 个文件data-access.ts(656行) + data-access-stats.ts(604行) + data-access-schedule.ts(230行) + data-access-students.ts(280行) + data-access-admin.ts(441行),通过 re-export 保持向后兼容
homework/data-access.ts 1038 → 596 混入排名计算业务逻辑 已拆分 已拆为 data-access.ts(596行) + stats-service.ts(346行),统计函数迁移至 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.tsgetAdminDashboardData 原直查 sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions。

修复方案(已实施):

  • 各模块新增 dashboard stats 函数:
    • users/data-access.tsgetUsersDashboardStats()userCount/activeSessionsCount/userRoleCounts/recentUsers
    • classes/data-access.tsgetClassesDashboardStats()classCount
    • textbooks/data-access.tsgetTextbooksDashboardStats()textbookCount/chapterCount
    • questions/data-access.tsgetQuestionsDashboardStats()questionCount
    • exams/data-access.tsgetExamsDashboardStats(scope?)examCount支持 scope 过滤)
    • homework/stats-service.tsgetHomeworkDashboardStats(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.tscreateClassScheduleItem 等)
  • scheduling/actions.tsapplyAutoScheduleAction 直接 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-accessgetClassGradeIdsByClassIds / getClassStudentsByClassId / getActiveClassStudents
  • exams/data-accessgetExamForHomeworkCreation
  • school/data-accessgetSubjectOptions / getGradeOptions
  • users/data-accessgetUserNameByIds / getStudentInfo
  • textbooks/data-accessgetKnowledgePointOptions
  • questions/data-accessinsertQuestionWithRelations / deleteQuestionRecursive

P1-2actions 层混入数据访问逻辑

模块 问题 Action 违规
exams updateExamAction / deleteExamAction / duplicateExamAction / getExamPreviewAction 直接 db.query + db.insert/update/delete
homework createHomeworkAssignmentAction157 行)/ 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-3auth.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-4users/import-export.ts 四重职责

同时处理:导入解析 + 导出 + 用户创建(含密码哈希)+ 班级注册(跨模块写 classEnrollments

解耦建议

  • 拆分为 import.ts(解析+校验)+ export.ts(模板生成+列表导出)
  • 用户创建逻辑迁移至 data-access.tscreateUser
  • classEnrollments 写入改为调用 classes/data-access.enrollStudentByInvitationCode

P1-5notifications 反向依赖 messaging

notifications/data-access.tsin-app-channel.ts 反向依赖 messaging 模块的偏好和 createNotification。

解耦建议:与 P0-4 一并解决,将 messageNotificationsnotificationPreferences 表所有权移交 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

  1. 拆分 classes/data-access.ts2104 行 → 按职责拆 3-4 个文件) 已完成(拆为 5 个文件data-access.ts 656行 + data-access-stats.ts 604行 + data-access-schedule.ts 230行 + data-access-students.ts 280行 + data-access-admin.ts 441行
  2. 拆分 homework/data-access.ts1038 行 → 分离排名逻辑) 已完成(拆为 data-access.ts 596行 + stats-service.ts 346行
  3. 修复 shared/libauth 循环依赖
  4. dashboard 改为通过各模块 data-access 获取数据
  5. messaging 写通知改为通过 notifications dispatcher
  6. 统一 classSchedule 写入口到 scheduling 模块
  7. 集成 proctoring/exam-mode-config 到考试表单

短期执行P1

  1. actions 层移除直接 DB 操作exams/homework/questions/announcements/users/scheduling
  2. 拆分 auth.ts
  3. 拆分 users/import-export.ts
  4. 消除 notifications → messaging 反向依赖
  5. 提取 shared/lib/http-utils.ts 统一 IP 提取
  6. 各模块暴露跨模块查询接口(见 P1-1

中期执行P2

  1. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
  2. schema.ts 按业务域分节
  3. 拆分 exams/ai-pipeline.ts
  4. shared 层业务逻辑下沉到 modules 层
  5. 代码质量问题逐项修复

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 - - - - 写enrollments - - - - - - -
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/gradesDataScope
  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/actionsupdateExamAction/deleteExamAction/duplicateExamAction 用于定位考试
  4. 传入 homework/actions.createHomeworkAssignmentActionsourceExamId 参数
  5. homeworkAssignments 表中作为外键关联到源考试
  6. homework/data-access.getHomeworkAssignmentAnalytics 用于追溯作业来源

classId

  1. classes/actionscreateTeacherClassAction/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.tsPermissions 常量定义57 个权限点)
  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.tsresolveDataScope(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 层核心函数

// 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.jsonroutes 节点
  • 新增数据库表:更新 shared/db/schema.ts 分节 + 005dbTables 节点

完整路由表、DevOps 脚本、E2E 测试等信息见 005_architecture_data.json