Files
NextEdu/docs/architecture/004_architecture_impact_map.md
SpecialX 868ac5f9cf feat(dashboard): 仪表盘模块审计重构 — 权限校验 + i18n + 逻辑抽离
基于 dashboard-audit-report.md 审计结论,对仪表盘模块进行 P0/P1 级修复:

- 新增 4 个 dashboard 权限点(DASHBOARD_ADMIN/TEACHER/STUDENT/PARENT_READ),补充到 permissions.ts 和角色-权限映射

- 新建 actions.ts:4 个 Server Action 均调用 requirePermission() 校验权限,消除 admin 页面零鉴权、teacher/student/parent 仅 requireAuth 的安全隐患

- 根重定向页 /dashboard 改用 resolvePermissions() + 权限点判断,不再 role === xxx 硬编码

- 新建 lib/dashboard-utils.ts:抽取 toWeekday / countStudentAssignments / sortUpcomingAssignments / filterTodaySchedule / computeTeacherMetrics / getGreetingKey 纯函数,与 UI 分离,便于单测

- 新建 messages/{zh-CN,en}/dashboard.json 翻译文件,i18n request.ts 加载 dashboard 命名空间;所有视图组件接入 useTranslations / getTranslations,消除中英混杂硬编码

- 重构 4 个角色 page.tsx:通过 actions 获取数据,generateMetadata 使用 i18n

- 同步更新架构图 004 / 005 文档(dashboard exports / permissions / 文件清单)
2026-06-22 15:50:56 +08:00

148 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       │
│              · lesson-preparation                                     │
│  教学管理:  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/ · global-search · ...        │
│  types/           permissions · action-state                        │
└─────────────────────────────────────────────────────────────────────┘
                               ▲
                               │ 反向依赖(违规,见 1.2
┌──────────────────────────────┴──────────────────────────────────────┐
│  根模块src/auth.ts (NextAuth 配置) · src/proxy.ts (中间件)         │
│  ✅ shared/lib/{audit-logger, change-logger, auth-guard} 已通过       │
│     shared/lib/session.ts 单一入口获取 session不再直依赖 @/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  │
     └─────┬──────┘  └────┬─────┘  └─────┬──────┘
           │ ✅ P1-1      │ ✅ P1-1      │ ✅ P1-1 已修复
           │ 通过 textbooks│ 通过 questions│ 通过 exams/classes/
           │ data-access  │ data-access  │   school/users data-access
           │              │ 通过 classes  │
           │              │ data-access   │
           ┌─┴────────┐     │              │
           │ grades   │◀────┘ 仅外键引用(合理)
           │ (成绩)   │
           └────┬─────┘
                │ ✅ P1-1 已修复
                │ 通过 classes/school/users data-access
                ▼
           ┌──────────┐
           │ classes  │ ✅ P1-1 已修复:通过 homework/data-access-classes
           └────┬─────┘   获取作业数据,不再直查 homework/exams 表
                │ ✅ P0-1 已修复data-access.ts 已拆分为 5 文件
                │ ✅ P0-5 已修复classSchedule 写入口统一到 scheduling
                │
                    ┌─────────┼─────────┐
                    │         │         │
                    ▼         ▼         ▼
              ┌──────────┐ ┌──────┐ ┌──────────┐
              │scheduling│ │school│ │ attendance│
              └────┬─────┘ └──────┘ └──────────┘
                   │ ✅ P0-5 已修复
                   │ classSchedule 写入口统一到 scheduling
                   │ 通过 classes/data-access 校验归属
                   │ ✅ P1-1 已修复:通过 users data-access

1.2.2 扩展模块依赖

┌─────────────┐  ✅ P0-3 已修复:通过各模块 data-access    ┌──────────────┐
│ dashboard   │  获取数据getUsersDashboardStats 等)       │ users/classes│
│ (聚合层)    │──────────────────────────────────────▶│ /exams/...   │
└─────────────┘  ✅ P0-4 已修复Promise.all 并行调用     └──────────────┘

┌─────────────┐  ─── 调用 data-access合理   ┌──────────────┐
│ parent      │──────────────────────────────▶│ classes/      │
│ (聚合层)    │  ✅ P1-1 已修复:通过各模块     │ homework/grades│
└─────────────┘   data-access 获取数据          └──────────────┘

┌─────────────┐  ✅ P1-1 已修复:通过 exams/questions/      ┌──────────────┐
│ diagnostic  │  classes/users data-access 获取数据          │ exams/questions│
│             │──────────────────────────────────────▶│ /classes/users│
└─────────────┘                                       └──────────────┘

┌─────────────┐  ✅ P1-1 已修复:通过 exams/users           ┌──────────────┐
│ proctoring  │  data-access 获取数据                       │ exams/users   │
└─────────────┘──────────────────────────────────────▶└──────────────┘

┌─────────────┐  ─── 调用 notifications dispatcher     ┌──────────────┐
│ messaging   │  (通知偏好/CRUD 已迁移至 notifications│ notifications │
│             │──────────────────────────────────────▶│ (拥有         │
│             │  ✅ P0-4 / P1-5 已修复:单向依赖       │  messageNotif│
└─────────────┘                                       │  ications +  │
                                                      │  preferences)│
                                                      └──────────────┘

┌─────────────┐  ─── 调用 messaging Action       ┌──────────────┐
│ settings    │  (通知偏好表单)                 │ messaging     │
└─────────────┘──────────────────────────────▶└──────────────┘

┌─────────────────┐  ───▶ data-access合理       ┌──────────────┐
│ lesson-prep     │──────────────────────────────▶│ textbooks    │
│ (备课聚合层)    │  只读章节/知识点树              │ (章节/KP 树) │
│                 │──────────────────────────────▶└──────────────┘
│                 │──────────────────────────────▶┌──────────────┐
│                 │  创建/查询题目                  │ questions    │
│                 │──────────────────────────────▶└──────────────┘
│                 │──────────────────────────────▶┌──────────────┐
│                 │  创建 exam 草稿                │ exams        │
│                 │──────────────────────────────▶└──────────────┘
│                 │──────────────────────────────▶┌──────────────┐
│                 │  创建作业下发                  │ homework     │
│                 │──────────────────────────────▶└──────────────┘
│                 │──────────────────────────────▶┌──────────────┐
│                 │  查询教师班级                  │ classes      │
│                 │──────────────────────────────▶└──────────────┘
│                 │──────────────────────────────▶┌──────────────┐
│                 │  附件                          │ files        │
└─────────────────┘──────────────────────────────▶└──────────────┘

1.2.3 循环依赖详情 已修复

shared/lib/audit-logger.ts   ──┐
shared/lib/change-logger.ts  ──┼──▶ shared/lib/session.ts ──▶ (dynamic import) @/auth
shared/lib/auth-guard.ts     ──┘

src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
              ──▶ import { ... } from "@/shared/lib/login-logger"
              ──▶ import { ... } from "@/shared/lib/password-policy"
              ──▶ import { ... } from "@/shared/lib/rate-limit"
              ──▶ import { ... } from "@/shared/lib/role-utils"        # P1-3 拆出
              ──▶ import { ... } from "@/shared/lib/bcrypt-utils"      # P1-3 拆出
              ──▶ import { ... } from "@/shared/lib/http-utils"        # P1-3 拆出
              ──▶ import { ... } from "@/shared/lib/password-security-service"  # P1-3 拆出
              ──▶ import { db, schema } from "@/shared/db"

  ✅ 修复shared/lib/* 不再静态 import @/auth统一通过 session.ts 单一入口
     session.ts 内部使用 dynamic import("@/auth") 打破模块级静态循环
     运行时调用链保持不变,模块加载图无环

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 表                                │
│ ✅ P0-1 已修复persistAiGeneratedExamDraft 改为调用 questions/data-access.createQuestionWithRelations不再直查 questions 表 │
└─────────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 2学生作答作业化考试                                        │
│ ─────────────────────────────────────────────────────────────────  │
│ student/learning/assignments/[assignmentId]/page.tsx                │
│   └─▶ homework/actions.startHomeworkSubmissionAction                │
│         ├─▶ requirePermission(HOMEWORK_SUBMIT)                      │
│         ├─▶ data-access-write.startHomeworkSubmission  ✅ P1-2 已修复 │
│         │     └─▶ db.insert(homeworkSubmissions)  [shared/db]       │
│         └─▶ 返回 submissionId                                       │
│                                                                     │
│   └─▶ homework/actions.saveHomeworkAnswerAction                     │
│         └─▶ data-access-write.saveHomeworkAnswer  ✅ P1-2 已修复     │
│              └─▶ db.transaction(insert homeworkAnswers) [shared/db] │
│                                                                     │
│   └─▶ homework/actions.submitHomeworkAction                         │
│         └─▶ data-access-write.submitHomework  ✅ P1-2 已修复         │
│              └─▶ db.update(homeworkSubmissions.status="submitted")  │
│                                                                     │
│ 数据写入homeworkSubmissions 表 + homeworkAnswers 表                │
│ ✅ P1-2 已修复actions 层不再直接 DB 操作,已下沉到 data-access-write│
└─────────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 3教师批改                                                     │
│ ─────────────────────────────────────────────────────────────────  │
│ teacher/homework/submissions/[submissionId]/page.tsx                │
│   └─▶ homework/actions.gradeHomeworkSubmissionAction                │
│         ├─▶ requirePermission(HOMEWORK_GRADE)                       │
│         └─▶ data-access-write.gradeHomeworkSubmission  ✅ P1-2 已修复│
│              └─▶ db.update(homeworkAnswers) 循环  [shared/db]       │
│                                                                     │
│ 数据更新homeworkAnswers.isCorrect / score / feedback               │
└─────────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 阶段 4成绩统计与诊断                                               │
│ ─────────────────────────────────────────────────────────────────  │
│ teacher/grades/page.tsx                                             │
│   └─▶ grades/data-access.getGradeRecords                            │
│         └─▶ ✅ P1-1 已修复:通过 classes/school/users data-access    │
│                                                                     │
│ teacher/diagnostic/page.tsx                                         │
│   └─▶ diagnostic/data-access.updateMasteryFromSubmission            │
│         ├─▶ ✅ P1-1 已修复:通过 exams data-access 获取提交          │
│         ├─▶ ✅ P1-1 已修复:通过 questions data-access 获取知识点    │
│         └─▶ 更新 knowledgePointMastery                              │
│                                                                     │
│ 数据读取homeworkSubmissions → grades → knowledgePointMastery        │
└─────────────────────────────────────────────────────────────────────┘

关键观察:考试流程横跨 4 个模块exams → homework → grades → diagnostic P1-1 已修复:所有跨模块查询已改为通过对方 data-access 接口,模块封装性已恢复。


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)      ✅ 合理
   │           └─▶ questions/data-access.createQuestionWithRelations  ✅ P0-1 已修复:通过 data-access
   │
   └─▶ revalidatePath("/teacher/exams")

1.4.2 调用链路:学生提交作业

[Client] homework-take-view.tsx
   │
   ▼
[Action] homework/actions.submitHomeworkAction
   │
   ├─▶ requirePermission(HOMEWORK_SUBMIT)
   │
   ├─▶ data-access-write.submitHomework  ✅ P1-2 已修复
   │     (校验 submission 归属 + 更新状态)
   │     └─▶ db.update(homeworkSubmissions)
   │           SET status = "submitted", submittedAt = now()
   │
   └─▶ 返回 ActionState<{ submissionId }>

1.4.3 调用链路:管理员仪表盘聚合

[Route]  /admin/dashboard/page.tsx (Server Component)
   │
   ▼
[DataAccess] dashboard/data-access.getAdminDashboardData
   │
   ├─▶ users/data-access.getUsersDashboardStats()           ✅ 通过模块 data-access
   │     ├─ userCount / activeSessionsCount / userRoleCounts
   │     └─ recentUsers (含角色解析)
   ├─▶ classes/data-access.getClassesDashboardStats()       ✅ 通过模块 data-access
   │     └─ classCount
   ├─▶ textbooks/data-access.getTextbooksDashboardStats()   ✅ 通过模块 data-access
   │     └─ textbookCount / chapterCount
   ├─▶ questions/data-access.getQuestionsDashboardStats()   ✅ 通过模块 data-access
   │     └─ questionCount
   ├─▶ exams/data-access.getExamsDashboardStats(scope?)     ✅ 通过模块 data-access
   │     └─ examCount (含 scope 过滤)
   └─▶ homework/stats-service.getHomeworkDashboardStats(scope?)  ✅ 通过模块 data-access
         ├─ homeworkAssignmentCount / homeworkAssignmentPublishedCount
         └─ homeworkSubmissionCount / homeworkSubmissionToGradeCount

   ✅ P0-4 已修复dashboard 改为并行调用各模块 dashboard stats 函数,不再直查跨模块表

1.4.4 调用链路admin 路由组统一权限守卫

[Layout]  app/(dashboard)/admin/layout.tsx (Server Component)
   │
   ▼
[AuthGuard] shared/lib/auth-guard.getAuthContext()
   │
   └─▶ getSession() → 校验已登录(未登录抛 PermissionDeniedError
   │
   ▼
[Children] 各 admin/* 页面page.tsx在函数体首行调用 requirePermission(XXX)
   │
   ├─▶ /admin/school/schools         → requirePermission(SCHOOL_MANAGE)
   ├─▶ /admin/school/academic-year   → requirePermission(SCHOOL_MANAGE)
   ├─▶ /admin/school/classes         → requirePermission(SCHOOL_MANAGE)
   ├─▶ /admin/school/departments     → requirePermission(SCHOOL_MANAGE)
   ├─▶ /admin/school/grades          → requirePermission(SCHOOL_MANAGE)
   ├─▶ /admin/school/grades/insights → requirePermission(SCHOOL_MANAGE)
   ├─▶ /admin/users/import           → requirePermission(USER_MANAGE)
   ├─▶ /admin/users                  → requirePermission(USER_MANAGE)
   ├─▶ /admin/scheduling/auto        → requirePermission(SCHEDULE_AUTO)
   ├─▶ /admin/scheduling/changes     → requirePermission(SCHEDULE_ADJUST)
   ├─▶ /admin/scheduling/rules       → requirePermission(SCHEDULE_ADJUST)
   ├─▶ /admin/announcements          → requirePermission(ANNOUNCEMENT_MANAGE)
   ├─▶ /admin/announcements/[id]     → requirePermission(ANNOUNCEMENT_MANAGE)
   └─▶ /admin/audit-logs             → requirePermission(AUDIT_LOG_READ)

   ✅ P0 安全修复admin/layout.tsx 提供登录态统一守卫,
      各页面 requirePermission() 提供细粒度权限校验

第二部分:模块清单

每个模块包含:职责 · 导出函数 · 依赖关系 · 已知问题 · 文件清单

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() — 通用工具
  • getInitials(name) / formatDateForFile(d?) — 通用工具P1-c / P1-a 重构新增:从 parent/lib/utils.ts、grades/export-button.tsx 等多处重复实现抽取)
  • downloadBase64File(base64, filename, mimeType?) / downloadBlob(blob, filename) — 客户端文件下载P1-c 重构新增:从 grades/export-button、users/user-import-dialog、audit/audit-log-export-button 三处重复实现抽取,位于 lib/download.ts

共享组件导出P0-b / P1-a / P1-b / P1-c / P2-a / P2-b / P3-a / P3-b / P3-c / P3-d / 第二轮 P0-1/P0-2/P0-3/P1-1/P1-2/P1-3/P1-4 重构新增,按类别组织):

类别 组件 文件 用途 消费方数量
UI 组件 StatCard components/ui/stat-card.tsx 统计卡片(标题+数值+图标+描述+跳转+骨架屏) 8 个P1-a
UI 组件 StatItem components/ui/stat-item.tsx 紧凑统计项label+icon+value+hint用于统计面板网格 8 个P1-a
UI 组件 ChipNav components/ui/chip-nav.tsx 芯片导航组(通过 URL search params 切换筛选维度Link 跳转) 3 个P1-b
UI 组件 PageHeader components/ui/page-header.tsx 页面头部(标题+描述+icon+actions响应式布局 2 个P2-b: profile/page.tsx, settings/security/page.tsx
UI 组件 FilterBar / FilterSearchInput / FilterResetButton components/ui/filter-bar.tsx 筛选栏容器+搜索框+重置按钮统一布局壳URL 状态由各模块处理) 5 个P3-b: exam/textbook/question/audit-log/login-log filters
UI 组件 ConfirmDeleteDialog components/ui/confirm-delete-dialog.tsx 通用删除确认对话框AlertDialog 包装,支持自定义 confirmText/cancelText 5 个P0-1: announcement-detail, message-detail, course-plan-detail, grade-classes-view, students-table
UI 组件 Pagination components/ui/pagination.tsx 通用分页 UIShowing X-Y of Z + Page X of Y + 上一页/下一页按钮) 3 个P0-2: audit-log-table, login-log-table, data-change-log-table
UI 组件 EmptyTableRow components/ui/empty-table-row.tsx 表格空状态行TableRow + TableCell 居中显示空状态文案) 3 个P0-3: audit-log-table, login-log-table, data-change-log-table
UI 组件 StatusBadge components/ui/status-badge.tsx 通用状态徽章Badge + 状态→variant/label/className 映射表,修复 in_progress 颜色不一致 bug 9+ 个P1-1: audit 3 文件, grades 2 文件, student/learning/assignments, parent/child-homework-summary, student-upcoming-assignments-card, question-columns
表单字段 TextField components/form-fields/text-field.tsx 通用文本字段FormField + Input 包装,支持 text/number/password/datetime-local 类型 + value 转换器) 3 个文件 16 处P1-2: profile-settings-form 6, exam-basic-info-form 4, ai-provider-settings-card 4
表单字段 SelectField components/form-fields/select-field.tsx 通用选择字段FormField + Select 包装,支持 toSelectValue/fromSelectValue 处理 number↔string 4 个文件 8 处P1-2: exam-basic-info-form 3, ai-provider-settings-card 1, create-question-dialog 2, profile-settings-form 1
表单字段 TextareaField components/form-fields/textarea-field.tsx 通用多行文本字段FormField + Textarea 包装) 1 个P1-2: create-question-dialog
图表组件 ChartCardShell components/charts/chart-card-shell.tsx 图表卡片外壳Card+Header+EmptyState+Content 统一结构) 8 个P3-c
图表组件 TrendLineChart components/charts/trend-line-chart.tsx 趋势折线图LineChart 统一配置,支持单/多系列) 8 个P3-c: grade-trend-chart 等)
图表组件 SimpleBarChart components/charts/simple-bar-chart.tsx 柱状图BarChart 统一配置,支持单/多 Bar + Cell 分桶着色) 8 个P3-c: grade-distribution-chart 等)
图表组件 ComparisonRadarChart components/charts/comparison-radar-chart.tsx 对比雷达图RadarChart 统一配置,支持双 Radar 对比) 8 个P3-c: subject-comparison-chart, mastery-radar-chart 等)
课表组件 ScheduleList / ScheduleListItem components/schedule/schedule-list.tsx 课表列表+列表项(课程+时间+地点+班级徽章separator/card 两种变体) 3 个P3-a: student-today-schedule-card, child-schedule-card, student-schedule-view
题库组件 QuestionBankFilters components/question/question-bank-filters.tsx 题库筛选栏(搜索+题型+难度default/compact 两种布局) 2 个P3-d: exam-assembly, question-bank-picker
设置组件 SettingsView modules/settings/components/settings-view.tsx 统一设置页布局5 标签页General/Notifications/Appearance/Security/AI角色差异通过 props 注入Tab URL 持久化,登出二次确认) 4 个P2-a: admin/teacher/student/parent 设置页)

共享 Hooks 导出(第二轮 P1-4 重构新增):

Hook 文件 签名 用途 消费方
useActionMutation hooks/use-action-mutation.ts useActionMutation<T>(options?): { isWorking, mutate } 通用 Server Action mutation Hook替代 50+ 文件中重复的 setIsWorking + try/catch/finally + toast 模式 1 个示范P1-4: schools-view潜在影响 50+ 文件
useActionQuery hooks/use-action-query.ts useActionQuery<T>(action, options?): { data, loading, error, refetch } 通用 Server Action 查询 Hook替代 11 个文件中重复的 useEffect + useState(loading) + Action().then().catch().finally() 模式,内置竞态防护 1 个示范P1-4: create-question-dialog潜在影响 11 个文件

共享工具函数导出(第二轮 P1-3 重构新增):

函数 文件 签名 用途 消费方
formatDateTime lib/utils.ts formatDateTime(date, locale?): string 国际化日期+时间格式化(含小时、分钟) 4 个P1-3: lesson-plan-card, version-history-drawer, proctoring-dashboard, exam-ai-generator
formatLongDate lib/utils.ts formatLongDate(date, locale?): string 国际化长日期格式化(含星期、完整月份名),默认 zh-CNweekday=short 1 个P1-3: teacher-dashboard-header

注:SettingsView 位于 modules/settings/components/(非 shared 层),因仅被 settings 模块消费,未下沉到 shared。此处列出以完整反映本次重构的组件抽取范围。

依赖关系

  • 被依赖方:所有模块依赖 shared
  • 反向依赖已修复:shared/lib/{audit-logger, change-logger, auth-guard} 通过 shared/lib/session.ts 单一入口获取 session不再直接依赖 @/auth

已知问题

  • P0shared/lib/*@/auth 循环依赖 已修复(新增 shared/lib/session.ts 封装 session 获取3 个文件改为 import { getSession } from "@/shared/lib/session"
  • ⚠️ P1schema.ts 1111 行54 张表混合,超 1000 硬上限)
  • P1auth.ts 293 行混合 5 类职责 已拆分4 个辅助函数组迁移至 shared/lib/{role-utils,bcrypt-utils,http-utils,password-security-service}auth.ts 仅保留 NextAuth 配置)
  • P2-2 已修复:ai.ts 218 行混合 5 类职责 已拆分为 ai/ 目录payload-parser.ts/api-key-crypto.ts/provider-config.ts/client.ts/errors.ts/index.tsai.ts 保留为向后兼容的重导出文件9 行)
  • P2-4 已修复:onboarding-gate.tsx 业务逻辑泄漏到 shared 已迁移至 modules/onboarding/actions/data-access/schema/types/components引导流程改为独立路由 /onboarding + middleware 重定向 + Server Action
  • P0-2/P0-3/P0-4/P0-5/P1-1/P1-2/P1-4/P1-5 已修复v3 对标 PowerSchool/Veracross/Auth0家长绑定三因子验证邮箱+生日+手机号后4位、教师多科目循环绑定、审计日志、服务端幂等、URL query 持久化步骤、局部错误收集、家长多子女动态行、跳过机制明确化
  • v3 i18n 体系引入:采用 next-intl 4.xwithout i18n routing 模式cookie 驱动 locale 切换,字典放在 shared/i18n/messages/{locale}/,支持 zh-CN/en 两种语言,不破坏现有路由组结构
  • v3 班级邀请码体系引入(对标 Google Classroom / 钉钉教育 / 智学网):新增 class_invitation_codes 表(独立表,支持有效期/次数限制/审计/多码并存6 位字母数字(剔除歧义字符 0/O/1/I/L空间 1.13 亿rate limit 防爆破10 次/5 分钟),审计日志全链路记录,懒清理过期码

文件清单

文件 行数 职责
db/schema.ts 1111 54 张表定义(超硬上限)
db/relations.ts - 表关系定义
db/index.ts - Drizzle 客户端
lib/auth-guard.ts - 认证上下文 + 权限校验 + DataScope
lib/permissions.ts - 角色-权限映射
lib/session.ts 38 session 获取单一入口getSessionserver-onlydynamic import 打破循环)
lib/ai.ts 9 向后兼容重导出P2-2 已拆分到 ai/ 目录)
lib/ai/payload-parser.ts 78 请求负载解析
lib/ai/api-key-crypto.ts 28 API Key 加密/解密
lib/ai/provider-config.ts 61 Provider 配置查询
lib/ai/client.ts 58 AI 客户端创建与调用
lib/ai/errors.ts 8 错误格式化
lib/ai/index.ts 5 聚合导出
lib/audit-logger.ts - 操作日志(通过 session.ts 获取 sessionhttp-utils 获取 IP/UA
lib/change-logger.ts - 数据变更日志(通过 session.ts 获取 sessionhttp-utils 获取 IP
lib/login-logger.ts - 登录日志(通过 http-utils 获取 IP/UA
lib/password-policy.ts - 密码策略纯函数
lib/rate-limit.ts - 内存滑动窗口限流
lib/role-utils.ts 31 角色规范化纯函数normalizeRole / resolvePrimaryRole
lib/bcrypt-utils.ts 18 bcrypt 哈希前缀规范化纯函数
lib/http-utils.ts 44 请求头解析resolveClientIp / getUserAgentserver-only
lib/password-security-service.ts 84 密码安全 DB 操作(账户锁定/失败登录追踪server-only
lib/excel.ts - Excel 导入导出
lib/file-storage.ts - 文件存储抽象
hooks/use-permission.ts - 客户端权限 Hook
components/ui/* 34 文件 shadcn/ui 标准组件
components/ui/stat-card.tsx 95 StatCard 统计卡片P1-a 新增)
components/ui/stat-item.tsx 38 StatItem 紧凑统计项P1-a 新增)
components/ui/chip-nav.tsx 78 ChipNav 芯片导航P1-b 新增)
components/ui/page-header.tsx 44 PageHeader 页面头部P2-b 新增,含 icon 属性)
components/ui/filter-bar.tsx 124 FilterBar + FilterSearchInput + FilterResetButtonP3-b 新增)
components/charts/chart-card-shell.tsx 90 ChartCardShell 图表卡片外壳P3-c 新增)
components/charts/trend-line-chart.tsx 153 TrendLineChart 趋势折线图P3-c 新增)
components/charts/simple-bar-chart.tsx 162 SimpleBarChart 柱状图P3-c 新增)
components/charts/comparison-radar-chart.tsx 143 ComparisonRadarChart 对比雷达图P3-c 新增)
components/schedule/schedule-list.tsx 112 ScheduleList + ScheduleListItem 课表列表P3-a 新增)
components/question/question-bank-filters.tsx 137 QuestionBankFilters 题库筛选栏P3-d 新增)
lib/download.ts 47 downloadBase64File + downloadBlob 客户端下载工具P1-c 新增)
lib/utils.ts - 通用工具P1-a/P1-c 新增 getInitials + formatDateForFile
components/onboarding-gate.tsx 312 引导流程(业务泄漏) 已废弃,逻辑迁移至 modules/onboarding/P2-4 已修复)
components/global-search.tsx 221 全局搜索(业务泄漏)
types/permissions.ts 157 61 个权限点常量 + Role/DataScope/AuthContext 类型

2.2 exams考试模块

职责:考试全生命周期管理(创建/编辑/预览/发布/删除/复制)+ AI 辅助出题。

导出函数

  • ActionscreateExamAction / createAiExamAction / previewAiExamAction / regenerateAiQuestionAction / updateExamAction / deleteExamAction / duplicateExamAction / getExamPreviewAction / getSubjectsAction / getGradesAction P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access
  • Data-accessgetExams / getExamById / persistExamDraft / persistAiGeneratedExamDraft / buildExamDescription / resolveSubjectGradeNames / getExamCreatorId / updateExamWithQuestions / deleteExamById / duplicateExam / getExamPreview / getExamSubjects / getExamGrades(后 7 个为 P1-2 新增)
  • AI PipelinegenerateAiCreateDraftFromSource / generateAiPreviewData / regenerateAiQuestionByInstruction
  • UtilsnormalizeStructurev3 新增:将持久化的 exam.structure unknown JSON 运行时校验并归一化为类型安全的 ExamNode[],类型守卫模式无 as 断言,从 teacher/exams/[id]/build/page.tsx 提取)

依赖关系

  • 依赖:shared/*@/authquestions P0-1 已修复:通过 data-access.createQuestionWithRelationsclasses P0-2 已修复:通过 data-access.getClassGradeIdsByClassIdsschool P1-1 已修复:通过 school data-access.getSubjectOptions/getGradeOptions
  • 被依赖:homework(通过 sourceExamId 外键,合理)、dashboard(通过 data-accessP0-4 已修复)、proctoring P1-1 已修复:通过 exams data-accessdiagnostic P1-1 已修复:通过 exams data-access

已知问题

  • P0-1 已修复:persistAiGeneratedExamDraft 直接 insert 到 questions 改为调用 questions/data-access.createQuestionWithRelations,通过 ID 映射保持 structure 引用一致
  • P0-2 已修复:getExams/getExamById/getExamsDashboardStats 直查 classes 改为调用 classes/data-access.getClassGradeIdsByClassIds
  • P1-1 已修复:getSubjectsAction/getGradesAction 直查 subjects/grades 改为调用 school/data-access.getSubjectOptions / getGradeOptions
  • P1-2 已修复:actions.ts 832 行(超 800 建议),多处直接 DB 操作 DB 操作已下沉到 data-accessactions.ts 现 691 行
  • ⚠️ P1ai-pipeline.ts 857 行(超 800 建议),混合 4 类职责
  • P2 已修复:ai-pipeline.ts 中 3 处非空断言清理(draft.sections!.forEach → 安全守卫、aiParsed.sections!.flatMap?? []aiParsed.sections!.map?? []

文件清单

文件 行数 职责
actions.ts 691 10 个 Server ActionP1-2 已修复,无直接 DB 操作)
ai-pipeline.ts 857 AI 出题管线(超限)
data-access.ts 473 考试 CRUD含 P1-2 新增 7 个写/查询函数P0-1/P0-2 已修复:通过 questions/classes data-access 跨模块通信)
types.ts 31 类型定义
hooks/use-exam-preview.ts 295 预览 Hook
utils/normalize-structure.ts 57 v3 新增exam.structure 运行时校验与归一化(从 build/page.tsx 提取)
components/* 18 文件 考试表单/组卷/预览组件

2.3 homework作业模块

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

导出函数

  • ActionscreateHomeworkAssignmentAction / startHomeworkSubmissionAction / saveHomeworkAnswerAction / submitHomeworkAction / gradeHomeworkSubmissionAction P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access/data-access-write
  • Data-accessgetHomeworkAssignments / getHomeworkAssignmentById / getHomeworkSubmissions / getStudentHomeworkAssignments / getStudentHomeworkTakeData / getHomeworkAssignmentReviewList / getHomeworkSubmissionDetails / getDemoStudentUser(已迁移至 users 模块 getCurrentStudentUser,此处为 re-export 向后兼容)/ isRecord / toQuestionContent / getAssignmentMaxScoreById(后三者供 stats-service 使用)
  • Data-access-classesgetAssignmentIdsForStudents / getHomeworkAssignmentsWithSubject / getHomeworkAssignmentsByIds / getAssignmentTargetCounts / getHomeworkSubmissionsForStudents / getPublishedHomeworkAssignmentsWithSubject / getHomeworkSubmissionsForAssignmentsP0-7 新增,供 classes 模块跨模块调用,封装 homework/exams 表查询)
  • Data-access-write10 个写操作函数P1-2 新增,从 actions 下沉)
  • Stats-servicegetTeacherGradeTrends / getHomeworkAssignmentAnalytics / getStudentDashboardGrades(从 data-access.ts re-export 以保持向后兼容)

依赖关系

  • 依赖:shared/*@/authexams P1-1 已修复:通过 exams data-access.getExamIdsByGradeIds/getExamSubjectIdMap/getExamWithQuestionsForHomeworkclasses P1-1 已修复:通过 classes data-access.getStudentIdsByClassId 等 7 个函数)、school P1-1 已修复:通过 school data-access.getSubjectOptionsusers P1-1 已修复:通过 users data-access.getUserWithRole/getUserNamesByIds
  • 被依赖:dashboard(通过 data-access合理parent(通过 data-access合理classes P0-7 已修复classes 通过 homework/data-access-classes 获取作业数据,不再反向直查 homework/exams 表)

已知问题

  • P0 已解决:data-access.ts 已拆分至 598 行(原 1038 行超 1000 硬上限),统计函数迁移至 stats-service.ts
  • P0 已解决:getStudentDashboardGrades 排名计算逻辑迁移至 stats-service.ts
  • P0 已解决:getHomeworkAssignmentAnalytics 错误率统计逻辑迁移至 stats-service.ts
  • P0-7 已修复:新增 data-access-classes.ts,将 classes 模块对 homework/exams 表的直查封装为 homework 模块的导出函数,恢复三层架构
  • P1-1 已修复:5 处直查 exams 改为调用 exams/data-access.getExamIdsByGradeIds / getExamSubjectIdMap / getExamWithQuestionsForHomework
  • P1-2 已修复:actions.ts 多处直接 DB 操作(createHomeworkAssignmentAction 157 行) DB 操作已下沉到 data-access-write.tsactions.ts 现 239 行

文件清单

文件 行数 职责
data-access.ts 598 作业 CRUD + 学生视角 + 批改(含 re-export stats 函数)
data-access-write.ts 285 作业写操作P1-2 新增10 个写函数从 actions 下沉)
data-access-classes.ts 232 跨模块查询封装P0-7 新增,供 classes 模块调用,封装 homework/exams 表查询)
stats-service.ts 425 统计分析(教师趋势/作业分析/学生仪表盘成绩)
actions.ts 239 5 个 Server ActionP1-2 已修复,无直接 DB 操作)
types.ts 186 类型定义
schema.ts 29 Zod 校验

2.4 questions题库模块

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

导出函数

  • ActionsgetQuestionsAction / createQuestionAction / updateQuestionAction / deleteQuestionAction / getKnowledgePointOptionsAction P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access
  • Data-accessgetQuestions / createQuestionWithRelations / updateQuestionById / deleteQuestionByIdRecursive / getKnowledgePointOptions(后 4 个为 P1-2 新增/迁移)

依赖关系

  • 依赖:shared/*@/authtextbooks P1-1 已修复:通过 textbooks data-access.getKnowledgePointOptions
  • 被依赖:exams(通过类型导入,合理)、textbooksUI 组合,合理)

已知问题

  • P1-2 已修复:写操作函数错放在 actions.tsinsertQuestionWithRelations / deleteQuestionRecursive 已下沉到 data-accesscreateQuestionWithRelations / updateQuestionById / deleteQuestionByIdRecursive / getKnowledgePointOptions
  • P1-1 已修复:getKnowledgePointOptionsAction 直查 textbooks 模块表 改为调用 textbooks/data-access.getKnowledgePointOptions
  • P2 已解决:data-access.ts 仅 129 行,写操作缺失 P1-2 后 data-access.ts 扩充至 260 行

文件清单

文件 行数 职责
actions.ts 149 5 个 Server ActionP1-2 已修复,无直接 DB 操作)
data-access.ts 260 题目 CRUD + 知识点选项(含 P1-2 新增 4 个写/查询函数)
schema.ts 18 Zod 校验
types.ts 34 类型定义

2.5 textbooks教材模块— 标杆模块data-access 层)

职责:教材与知识体系管理(教材/章节树形结构、知识点 CRUD、Markdown 内容编辑、知识图谱)。

导出函数

  • Actions10 个,均为写操作;读操作由 RSC 页面直接调用 data-accesscreateTextbookAction / updateTextbookAction / deleteTextbookAction / createChapterAction / updateChapterContentAction / deleteChapterAction / reorderChaptersAction / createKnowledgePointAction / updateKnowledgePointAction / deleteKnowledgePointAction
  • Data-accessgetTextbooks / getTextbookById / getChaptersByTextbookId / getKnowledgePointsByChapterId / getKnowledgePointsByTextbookId / createTextbook / updateTextbook / deleteTextbook / createChapter / updateChapterContent / deleteChapter / createKnowledgePoint / updateKnowledgePoint / deleteKnowledgePoint / reorderChapters / getTextbooksDashboardStats / getKnowledgePointOptions(跨模块接口,供 questions 调用)

依赖关系

  • 依赖:shared/*@/auth
  • 被依赖:questions P1-1 已修复:通过 textbooks data-accessexams(通过类型)、dashboard(通过 data-accessP0-4 已修复)
  • ⚠️ UI 层跨模块依赖:textbooks/components/knowledge-point-dialogs.tsx 直接 import questions/components/create-question-dialogP0 待解耦,详见 textbooks-audit-report.md

已知问题

  • 无跨模块 DB 访问data-access 层)
  • actions 层编排模式标杆(权限校验 → 调用 data-access → revalidatePath
  • data-access 层职责单一
  • P2 已修复:data-access.tsbyId.get(pid)!.children.push 非空断言清理为安全守卫;or(...)! 非空断言清理为条件 push
  • ⚠️ P0 跨模块 UI 依赖:knowledge-point-dialogs.tsx 直接 import questions 模块组件
  • ⚠️ P0 前端权限硬编码:canEdit={true} 按路由写死,未用 usePermission().hasPermission()
  • ⚠️ P0 全模块零 i18n中英文文案硬编码未接入 next-intl
  • ⚠️ P1 Server Action 未校验资源归属chapterId 是否属于 textbookId
  • ⚠️ P1 data-access 缺数据范围过滤(学生端未按年级过滤)
  • ⚠️ P1 缺 Error Boundary无 error.tsx
  • ⚠️ P1 知识点列表/弹窗存在重复实现knowledge-point-panel.tsx 无调用方)
  • ⚠️ P1 学科/年级选项硬编码三处且彼此不一致
  • ⚠️ P1 纯逻辑未导出,零单测

文件清单

文件 行数 职责
actions.ts 317 10 个 Server Action写操作
data-access.ts 514 教材/章节/知识点 CRUD + 跨模块查询接口
types.ts 45 类型定义
schema.ts 64 Zod 校验
hooks/use-knowledge-point-actions.ts 121 知识点操作 Hook
hooks/use-text-selection.ts 57 文本选区捕获 Hook
components/* 11 文件 教材编辑/知识图谱组件

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 P1-1 已修复:通过 classes data-access.getClassExists/getClassNameById/getClassNamesByIds/getActiveStudentIdsByClassId/getStudentActiveClassId/getClassesByGradeIdschool P1-1 已修复:通过 school data-access.getSubjectOptions/getGradeOptionsusers P1-1 已修复:通过 users data-access.getUserNamesByIds
  • 被依赖:parent(通过 data-access合理dashboard

已知问题

  • P1-1 已修复:多处直查 classes/classEnrollments/subjects/users 改为调用对应模块 data-access 函数classes/school/users
  • ⚠️ P2统计计算业务逻辑混入 data-accessgetClassGradeStats / getGradeDistribution
  • actions 层无直接 DB 访问(标杆)
  • data-access 按职责拆分为 3 个文件(标杆)
  • P2 已修复:export.tsscoreMap.get(r.studentId)! 非空断言清理为安全守卫(if (!subjMap) continue

文件清单

文件 行数 职责
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 / verifyTeacherOwnsClass / getTeacherIdsByClassIds(获取多个班级的所有教师 ID班主任 + 任课教师,跨模块接口,供 messaging 模块调用)( P0-5 已修复classSchedule 写函数 createClassScheduleItem/updateClassScheduleItem/deleteClassScheduleItem 已迁移至 scheduling/data-access-class-schedule.tsclasses 模块仅保留 classSchedule 读函数; P2 已修复:getAccessibleClassIdsForTeacher 使用 Promise.all 并行化 ownedIds 与 assignedIds 查询)
  • SchemaCreateTeacherClassSchema / UpdateTeacherClassSchema / DeleteTeacherClassSchema / CreateAdminClassSchema / UpdateAdminClassSchema / DeleteAdminClassSchema / CreateGradeClassSchema / UpdateGradeClassSchema / DeleteGradeClassSchema / CreateClassScheduleItemSchema / UpdateClassScheduleItemSchema / DeleteClassScheduleItemSchema / EnrollStudentByEmailSchema

依赖关系

  • 依赖:shared/*@/authschool P1-1 已修复:通过 school data-access.isGradeHead/isGradeManager/findGradeIdByHeadAndNamehomework P0-7 已修复:通过 homework/data-access-classes 暴露的函数获取作业数据,不再直查 homework/exams 表)
  • 被依赖:exams/homework/grades/attendance/scheduling/dashboard(通过 data-accessP0-4 已修复)/parent/course-plans/users P1-1 已修复8+ 处直查 classes 表改为通过 classes data-access/messaging(通过 data-access.getTeacherIdsByClassIds/getStudentActiveClassId支持学生/家长给班级教师发消息)

已知问题

  • P0-1 已修复:data-access.ts 已拆分为 5 个文件data-access/data-access-stats/data-access-schedule/data-access-students/data-access-admin所有文件均 ≤800 行
  • P0-5 已修复classSchedule 写函数createClassScheduleItem/updateClassScheduleItem/deleteClassScheduleItem已迁移至 scheduling/data-access-class-schedule.tsclasses 模块仅保留 classSchedule 读函数getStudentSchedule/getClassSchedule新增 verifyTeacherOwnsClass 供 scheduling 模块跨模块校验教师班级归属
  • P0-7 已修复:data-access-stats.tsdata-access-students.ts 不再直查 homeworkAssignmentQuestions/homeworkAssignmentTargets/homeworkAssignments/homeworkSubmissions/exams 表,改为调用 homework/data-access-classes.ts 暴露的函数(getAssignmentIdsForStudents/getHomeworkAssignmentsWithSubject/getHomeworkAssignmentsByIds/getAssignmentMaxScoreById/getAssignmentTargetCounts/getHomeworkSubmissionsForStudents/getPublishedHomeworkAssignmentsWithSubject/getHomeworkSubmissionsForAssignments
  • P1-1 已修复:actions.ts 直查 grades 表做权限校验 改为调用 school/data-access 函数
  • P1-1 已修复:getSessionTeacherId 在 data-access 调用 auth() 改为通过 shared/lib/auth-guard.getAuthContext() 获取
  • P2 已修复:data-access.tsidByName.get(name)! 非空断言清理为 flatMap 安全过滤;data-access-admin.ts 中同类非空断言清理

文件清单

文件 行数 职责
data-access.ts 548 核心班级 CRUD + 邀请码 + 教师班级管理(含 re-export 向后兼容)
data-access-stats.ts 513 作业统计查询(班级/年级作业洞察,通过 homework/data-access-classes 获取数据)
data-access-schedule.ts 93 课表查询(学生/班级课表只读P0-5 已修复:写函数已迁移至 scheduling 模块)
data-access-students.ts 253 学生相关查询(科目成绩、学生名单、学生班级,通过 homework/data-access-classes 获取数据)
data-access-admin.ts 406 管理员班级管理(管理员班级 CRUD、年级管理班级查询
actions.ts 785 17 个 Server Action三组重复使用 Zod schema 校验)
schema.ts 152 Zod 校验13 个 schema教师/管理员/年级班级 CRUD + 课表 CRUD + 邮箱注册)
types.ts 201 类型定义(含跨领域类型污染)

2.8 school学校模块

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

导出函数

  • ActionscreateSchoolAction / updateSchoolAction / deleteSchoolAction / createAcademicYearAction / updateAcademicYearAction / deleteAcademicYearAction / createDepartmentAction / updateDepartmentAction / deleteDepartmentAction / createGradeAction / updateGradeAction / deleteGradeAction(编排层:权限校验 + Zod 校验 + 调用 data-access + revalidatePath + after(logAudit)
  • Data-access只读查询getSchools / getGrades / getDepartments / getAcademicYears / getStaffOptions / getGradesForStaff+ 写操作(create/update/delete × Department/School/Grade/AcademicYear

依赖关系

  • 依赖:shared/*@/authusers⚠️ getStaffOptions 直查 users/roles可接受
  • 被依赖:exams P1-1 已修复:通过 school data-accesshomework P1-1 已修复:通过 school data-accessgrades P1-1 已修复:通过 school data-accessquestions P1-1 已修复:通过 textbooks data-accessclasses P1-1 已修复:通过 school data-accesscourse-plans(合理)

已知问题

  • P0-8 已修复:actions.ts 不再直接导入 db 和 schema所有 DB 写操作下沉到 data-access.ts,符合三层架构
  • P2 已修复:logAudit() 通过 Next.js after() 异步非阻塞执行
  • P2 已修复:data-access.ts 中 8 处 catch 块添加 console.error 输出错误上下文getDepartments/getAcademicYears/getSchools/getGrades/getStaffOptions/getGradesForStaff/getSubjectOptions/getGradeOptions
  • ⚠️ P2审计日志不一致仅 school 实体记录department/academicYear/grade 未记录)
  • ⚠️ P2getStaffOptions/getGrades 直查 users/roles展示用可接受

文件清单

文件 行数 职责
actions.ts 326 12 个 Server Action编排层无 DB 直访)
data-access.ts 320 只读查询 + 12 个写操作CRUD
schema.ts 51 Zod 校验
types.ts 96 类型定义(含 Insert/Update 入参类型)

2.9 scheduling排课模块

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

导出函数

  • ActionsautoScheduleAction / applyAutoScheduleAction / getSchedulingRulesAction / updateSchedulingRulesAction / getScheduleChangesAction / createScheduleChangeAction / updateScheduleChangeAction / deleteScheduleChangeAction
  • Data-accessgetSchedulingRules / getScheduleChanges / getAdminClassesForScheduling / getTeachersForScheduling / getClassroomsForScheduling / getClassSubjectsForScheduling
  • Data-access-class-schedule P0-5 新增):createClassScheduleItem / updateClassScheduleItem / deleteClassScheduleItem(从 classes 模块迁移,含教师班级归属校验,通过 classes/data-access.verifyTeacherOwnsClass 跨模块校验)
  • Data-access低级写入insertClassScheduleItem / updateClassScheduleItemById / deleteClassScheduleItemById / replaceClassSchedule(统一 classSchedule DB 写入口)
  • 算法:findOptimalSlot / validateSchedule / autoSchedule / buildDefaultTimeSlots(纯函数,标杆)

依赖关系

  • 依赖:shared/*@/authclasses P0-5 已修复:通过 classes/data-access.verifyTeacherOwnsClass / getTeacherIdForMutations 校验教师班级归属,不再直写 classSchedule 表的写入口分散在 classes 模块)、school⚠️ 排课辅助查询,可接受)、users P1-1 已修复:通过 users data-access.getUserNamesByIds
  • 被依赖:classes/actions.ts P0-5 已修复:通过 scheduling/data-access-class-schedule 调用写函数)

已知问题

  • P0-5 已修复:applyAutoScheduleAction 直接 transaction 写 classSchedule 表(第三个写入口) 改为调用 replaceClassSchedule 统一写入口classSchedule 所有写函数统一在 scheduling 模块
  • P1-1 已修复:autoScheduleAction 直查 users 改为调用 users/data-access.getUserNamesByIds
  • ⚠️ P2actions.ts 末尾 re-export data-access 函数(反模式)
  • P2 已修复:data-access.ts 中 3 处非空断言清理(userIds[0]!rows[i]!rows[j]!auto-scheduler.ts 中 2 处非空断言清理(schedule[i]!schedule[j]!
  • auto-scheduler.ts 是算法独立化的最佳实践(纯函数、无 DB、可测试

文件清单

文件 行数 职责
auto-scheduler.ts 310 排课算法(纯函数,标杆)
actions.ts 302 8 个 Server Action
data-access.ts 398 排课辅助查询 + 规则/变更 CRUD + classSchedule 低级写入insert/update/delete/replace
data-access-class-schedule.ts 165 classSchedule 业务写入P0-5 新增,从 classes 模块迁移,含教师归属校验)
schema.ts - Zod 校验
types.ts - 类型定义(含 P0-5 迁移的 CreateClassScheduleItemInput / UpdateClassScheduleItemInput

2.10 attendance考勤模块— 结构典范

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

导出函数

  • ActionsgetAttendanceRecordsAction / createAttendanceRecordAction / updateAttendanceRecordAction / deleteAttendanceRecordAction / getStudentAttendanceAction / getAttendanceStatsAction
  • Data-accessgetAttendanceRecords / createAttendanceRecord / updateAttendanceRecord / deleteAttendanceRecord / getClassStudentsForAttendance / getAttendanceStats(管理员考勤总览页统计概览,基于 getAttendanceRecords 聚合)
  • ComponentsAttendanceStatsCards(管理员考勤总览页 6 卡片统计概览)

依赖关系

  • 依赖:shared/*@/authclasses P1-1 已修复:通过 classes data-access.getTeacherClasses/getAdminClasses
  • 被依赖:无

已知问题

  • P1-1 已修复:getClassStudentsForAttendance 直查 classEnrollments 改为通过 classes data-access 获取
  • stats 独立拆分为 data-access-stats.ts(拆分范例)
  • DataScope 完整接入 6 种 scope 类型
  • actions 层无直接 DB 访问

文件清单

文件 行数 职责
actions.ts 271 6 个 Server Action
data-access.ts 309 考勤 CRUD + 管理员统计概览
data-access-stats.ts 145 统计逻辑(拆分范例)
schema.ts - Zod 校验
types.ts - 类型定义

2.11 users用户模块

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

导出函数

  • ActionsgetUserProfileAction / updateUserProfileAction / importUsersAction / exportUsersAction / downloadUserTemplateAction / updateUserRoleAction / deleteUserAction
  • Data-accessgetUserProfile / getCurrentStudentUser P2-20 已修复:从 homework 模块迁移而来6 个 student 页面通过此函数获取学生身份,不再依赖 homework 模块)/ getAdminUsers(管理员用户列表分页查询,支持搜索+角色聚合)/ getAdminUserRoles(角色名列表,用于筛选下拉框)
  • Import-exportgenerateUserImportTemplate / parseUserImportData / exportUsersToExcel+ re-export batchImportUsers / UserImportResult 保持向后兼容)
  • User-servicebatchImportUsers(用户创建 + 密码哈希 + 角色分配)
  • Class-registrationregisterStudentByInvitationCode(委托 classes/data-access 完成班级注册)
  • ComponentsUserImportDialog(批量导入对话框)/ AdminUsersView(管理员用户列表客户端组件,搜索+筛选+分页+删除)

依赖关系

  • 依赖:shared/*(含 shared/lib/role-utils P2 已修复:删除本地 normalizeRoleName/resolvePrimaryRole/rolePriority,统一复用 shared/lib/role-utils.resolvePrimaryRole)、@/authclasses P1-4 已修复:通过 class-registration.ts 调用 classes/data-access.enrollStudentByInvitationCode,不再直写 classEnrollments
  • 被依赖:dashboard(通过 data-accessP0-4 已修复)、grades P1-1 已修复:通过 users data-accesshomework P1-1 已修复:通过 users data-accessscheduling P1-1 已修复:通过 users data-accessdiagnostic P1-1 已修复:通过 users data-accesselective P1-1 已修复:通过 users data-accessproctoring P1-1 已修复:通过 users data-accessparent P1-1 已修复:通过 users data-access

已知问题

  • P1 已解决:import-export.ts 四重职责已拆分为 import-export.ts(解析/生成)+ user-service.ts(用户创建)+ class-registration.ts(班级注册)
  • P1 已解决:batchImportUsers 不再跨模块直写 classEnrollments,改为调用 classes/data-access.enrollStudentByInvitationCode
  • P2 已解决:删除本地 normalizeRoleName/resolvePrimaryRole/rolePriority,统一复用 shared/lib/role-utils.resolvePrimaryRole,消除重复代码
  • P1-1 已修复:updateUserProfile 绕过 data-access 直接 DB 写 已下沉到 data-access
  • P2-20 已修复:新增 getCurrentStudentUser 函数(从 homework 模块迁移6 个 student 页面通过此函数获取学生身份,不再依赖 homework 模块
  • P2 已解决:data-access.ts 已扩充写操作updateUserProfile 已下沉)
  • ⚠️ 已知限制:AdminUsersView 客户端组件的删除操作通过 fetch("/api/admin/users/:id") 调用,对应 API 路由尚未实现(deleteUserAction Server Action 已就绪,可作为后续 API 路由的实现基础)

文件清单

文件 行数 职责
import-export.ts 157 文件解析/生成(模板生成 + 解析校验 + Excel 导出)+ re-export 向后兼容
user-service.ts 82 用户创建(批量导入 + 密码哈希 + 角色分配)
class-registration.ts 21 班级注册(委托 classes/data-access
actions.ts 218 7 个 Server Actionprofile 更新 + 模板下载/导入/导出 + 角色更新 + 删除)
data-access.ts 394 getUserProfile + 用户查询 + 管理员用户列表分页查询getAdminUsers/getAdminUserRoles
components/admin-users-view.tsx 290 管理员用户列表客户端组件(搜索+筛选+表格+分页+删除对话框)

2.12 dashboard仪表盘模块

职责:管理员/教师/学生/家长仪表盘数据聚合 + 权限校验 + i18n + 纯逻辑工具函数。

导出函数

  • ActionsgetAdminDashboardAction / getTeacherDashboardAction / getStudentDashboardAction / getParentDashboardAction(均调用 requirePermission() 校验对应 DASHBOARD_*_READ 权限)
  • Data-accessgetAdminDashboardData(并行调用 6 个模块 stats 函数)
  • Lib 纯函数:toWeekday / countStudentAssignments / sortUpcomingAssignments / filterTodaySchedule / computeTeacherMetrics / getGreetingKey
  • ComponentsAdminDashboardView / TeacherDashboardView / StudentDashboard / UserGrowthChart(均接入 next-intl i18n

依赖关系

  • 依赖:shared/*@/authclasses(通过 data-accesshomework(通过 data-accessusers(通过 data-accessparent(通过 data-access.getParentDashboardDatatextbooks/questions/exams(通过各模块 dashboard stats 函数)、rechartsnext-intl
  • 被依赖:无

权限点

  • DASHBOARD_ADMIN_READadmin
  • DASHBOARD_TEACHER_READteacher
  • DASHBOARD_STUDENT_READstudent
  • DASHBOARD_PARENT_READparent

已知问题

  • P0-4 已修复:getAdminDashboardData 改为并行调用各模块 dashboard stats 函数,不再直查跨模块表
  • P0 已修复2026-06-22所有仪表盘页面通过 actions.ts 调用 requirePermission() 进行权限校验,不再裸调 data-access
  • P0 已修复2026-06-22根重定向页 /dashboard 改用 resolvePermissions() + 权限点判断,不再 role === "xxx" 硬编码
  • P0 已修复2026-06-22所有仪表盘组件接入 next-intluseTranslations / getTranslations),翻译文件 messages/{zh-CN,en}/dashboard.json
  • P1 已修复2026-06-22业务逻辑weekday 转换、作业统计、教师指标计算、问候语时段)抽取至 lib/dashboard-utils.ts 纯函数,与 UI 分离
  • V1 新增:AdminDashboardData 类型含 userGrowth/homeworkTrend 字段,data-access.ts 当前返回空数组占位,待后续接入真实统计
  • parent 仪表盘组件仍位于 modules/parent/components/parent-dashboard.tsx,通过 dashboard/actions.getParentDashboardAction 调用(架构决策:保留在 parent 模块以避免移动文件破坏其他 import

文件清单

文件 行数 职责
actions.ts 120 4 个 Server Action编排层requirePermission() 权限校验)
data-access.ts 49 admin 仪表盘数据聚合(并行调用各模块 stats 函数)
lib/dashboard-utils.ts 170 纯逻辑工具函数weekday / 统计 / 排序 / 指标计算 / 问候语)
types.ts 74 Admin / Teacher / Student 类型定义
components/admin-dashboard/admin-dashboard.tsx 267 管理员仪表盘视图i18n
components/admin-dashboard/user-growth-chart.tsx 50 recharts 折线图i18n
components/teacher-dashboard/*.tsx 9 文件 教师仪表盘组件i18n
components/student-dashboard/*.tsx 6 文件 学生仪表盘组件i18n

2.13 messaging私信模块

职责站内私信messages 表 CRUD

导出函数

  • ActionssendMessageAction / getMessagesAction / getMessageAction / deleteMessageAction / getNotificationsAction / markNotificationReadAction / markAllNotificationsReadAction / getNotificationPreferencesAction / updateNotificationPreferencesAction
  • Data-accessgetMessages / getMessageById / getMessageThread / createMessage / markMessageAsRead / deleteMessage / getUnreadMessageCount / getRecipients(按 DataScope 过滤可发送对象class_taught 教师→学生、grade_managed 年级管理员→教师/学生、all 管理员、class_members 学生→自己班级的任课教师/班主任、children 家长→孩子的班主任/任课教师;通过 classes data-access.getTeacherIdsByClassIds/getStudentActiveClassId 获取班级教师 ID通知 CRUD 通过 re-export 从 notifications 模块重导出,保持向后兼容)
  • Notification-preferencesre-export shim实际逻辑在 notifications/preferences.ts P0-b 已修复:notification-preferences.ts 文件已删除(通知模块去重),消费方改为直接从 @/modules/notifications/preferences 导入 getNotificationPreferences / upsertNotificationPreferences

依赖关系

  • 依赖:shared/*@/authnotifications P0-4 / P1-5 已修复:通过 sendNotification dispatcher 发送通知,通知 CRUD 和偏好已迁移至 notifications 模块)、classes(通过 data-access.getTeacherIdsByClassIds/getStudentActiveClassId 获取班级教师 ID支持学生 class_members 和家长 children 数据范围)、users(通过 data-access.getUserNamesByIds 获取用户显示名称)
  • 被依赖:notifications 已消除反向依赖)、settings(通知偏好表单)、layout(通知下拉)

已知问题

  • P0-4 已修复:sendMessageAction 绕过 notifications dispatcher 直接调用 createNotification 改为调用 notifications.sendNotification,通知 CRUD 已迁移至 notifications 模块
  • P0 已修复:与 notifications 双向依赖 + 职责重叠 通知相关表messageNotifications / notificationPreferences所有权已移交 notifications 模块messaging 仅保留 messages 表
  • P1-5 已修复:同时管理 3 类数据messages + messageNotifications + notificationPreferences 仅管理 messages 表,通知相关数据由 notifications 模块管理
  • P1 已修复:通知相关 Action 使用 requireAuth() 而非 requirePermission() 5 个通知 ActiongetNotifications / markNotificationAsRead / markAllNotificationsAsRead / getNotificationPreferences / updateNotificationPreferences已改为 requirePermission(Permissions.MESSAGE_READ)
  • P1 已修复:markMessageAsReadAction / deleteMessageAction / getMessageDetailAction 缺少 Zod 校验 已添加 MessageIdSchema 校验 messageId 参数
  • P1 已修复:updateNotificationPreferencesAction 缺少 Zod 校验 已添加 UpdateNotificationPreferencesSchema 校验 8 个布尔字段
  • P2 已修复:data-access.ts 中 3 处 or(...)! 非空断言清理为安全守卫(条件 push
  • P0-b 已修复:notification-preferences.ts re-export shim 文件 已删除通知模块去重8 个消费方改为直接从 @/modules/notifications/preferences 导入 getNotificationPreferences / upsertNotificationPreferences,消除 messaging 模块对通知偏好的冗余 re-export 层

文件清单

文件 行数 职责
actions.ts 276 9 个 Server Action通知相关 Action 委托 notifications 模块)
data-access.ts 199 私信 CRUD + re-export 通知 CRUD向后兼容
notification-preferences.ts 11 re-export shim P0-b 已删除(消费方改为直接从 notifications/preferences 导入)
schema.ts 41 私信发送校验 + messageId 校验 + 通知偏好更新校验
types.ts 72 私信类型 + re-export 通知类型(向后兼容)

2.14 notifications通知分发模块

职责多渠道通知分发SMS/Email/WeChat/InApp+ 站内通知 CRUD + 通知偏好管理。

导出函数

  • ActionssendNotificationAction / sendClassNotificationAction
  • DispatchersendNotification(payload) / sendBatchNotifications(payloads)
  • Data-accesscreateNotification / getNotifications / markNotificationAsRead / markAllNotificationsAsRead / getUnreadNotificationCount / getUserContactInfo / logNotificationSend / logNotificationSendBatch P0-4 / P1-5 修复后从 messaging 迁移)
  • PreferencesgetNotificationPreferences / upsertNotificationPreferences P0-4 / P1-5 修复后从 messaging 迁移)
  • ChannelsInAppChannelSender / SmsChannelSender / EmailChannelSender / WeChatChannelSender

依赖关系

  • 依赖:shared/*@/authclasses P1-1 已修复:通过 classes data-access.getClassExists/getStudentIdsByClassId
  • 被依赖:messaging P0-4 / P1-5 已修复messaging 通过 sendNotification dispatcher 发送通知,通知 CRUD 和偏好通过 re-export 保持向后兼容)

已知问题

  • P0-4 已修复:不拥有任何数据,全部依赖 messaging 模块 messageNotifications 和 notificationPreferences 表所有权已从 messaging 迁移至 notifications 模块
  • P0 已修复:与 messaging 双向依赖 notifications 不再反向依赖 messagingin-app-channel 改为静态导入本地 createNotification
  • P1-1 已修复:sendClassNotificationAction 直查 classes/classEnrollments 改为调用 classes/data-access.getClassExists / getStudentIdsByClassId
  • ⚠️ P1发送日志仅 consolenotification_logs
  • 渠道抽象优秀(接口 + 工厂 + Mock 实现)

文件清单

文件 行数 职责
dispatcher.ts 152 渠道选择 + 并行分发
data-access.ts 177 站内通知 CRUD + 用户联系方式 + 日志P0-4 / P1-5 修复后新增通知 CRUD
preferences.ts 166 通知偏好 CRUDP0-4 / P1-5 修复后从 messaging 迁移)
actions.ts 119 2 个 Server Action
types.ts 120 通知负载 + 渠道配置 + 通知记录 + 偏好类型P0-4 / P1-5 修复后扩充)
index.ts 61 对外导出入口
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 结构高度重复
  • P2 已修复:data-access.ts 中 6 处 catch 块添加 console.error 输出错误上下文;toIso/clampPageSize/clampPage 工具函数补齐显式返回类型
  • data-access 职责清晰,无跨模块问题

文件清单

文件 行数 职责
actions.ts 212 6 个 Server Action含内联导出
data-access.ts 260 日志查询
types.ts - 类型定义

2.16 announcements公告模块

职责:公告 CRUD + 发布/归档 + 发布通知。

导出函数

  • ActionsgetAnnouncementsAction / createAnnouncementAction / updateAnnouncementAction / deleteAnnouncementAction / publishAnnouncementAction / archiveAnnouncementAction P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access 发布公告时触发通知模块 sendBatchNotifications
  • Data-accessgetAnnouncements(支持 audience 受众过滤)/ getAnnouncementById / insertAnnouncement / updateAnnouncementById / deleteAnnouncementById / publishAnnouncementById / archiveAnnouncementById(后 5 个为 P1-2 新增)

依赖关系

  • 依赖:shared/*@/authschool(获取年级列表)、classes(获取班级列表 + 解析受众)、users(获取目标用户 ID 列表)、notifications(发布公告时发送通知)
  • 被依赖:无

已知问题

  • P1-2 已修复:所有写操作直接在 actions 层 db.insert/update/delete,未下沉到 data-access 写操作已下沉到 data-access5 个新函数)
  • P2 已修复:getAnnouncementsAction 使用 requireAuth() 而非 requirePermission(ANNOUNCEMENT_READ) 改为 requirePermission(Permissions.ANNOUNCEMENT_READ)
  • 已修复:用户端列表页传入 audience 受众过滤school/grade/class管理端返回所有公告
  • 已修复:用户端新增公告详情页 /announcements/[id](只读模式)
  • 已修复:管理端列表页传递 classes 数据给 AdminAnnouncementsView
  • 已修复:发布公告时(publishAnnouncementAction / createAnnouncementAction 直接发布 / updateAnnouncementAction 状态变为 published触发通知模块 sendBatchNotifications
  • 已修复:新增 loading.tsx 骨架屏(用户端 + 管理端)

文件清单

文件 行数 职责
actions.ts ~270 6 个 Server Action + 通知触发逻辑P1-2 已修复,无直接 DB 操作)
data-access.ts ~190 公告 CRUD + 发布/归档 + 受众过滤(含 P1-2 新增 5 个写函数)
schema.ts - Zod 校验
types.ts - 类型定义(GetAnnouncementsParams 新增 audience 字段)

2.17 files文件模块

职责:文件附件 CRUD + 批量删除 + 统计。

导出函数

  • Data-accessgetAllFileAttachments / getFileAttachmentsByOwner / getFileAttachmentById / createFileAttachment / updateFileAttachment / deleteFileAttachment / batchDeleteFileAttachments / getFileStats P2 已修复7 个读函数使用 React.cache() 包装实现请求级 memoizationgetFileAttachment / getFileAttachmentsByTarget / getFileAttachmentsByUploader / getAllFileAttachments / getFileAttachmentsWithFilters / getFileStats / getFileAttachmentsByIds

依赖关系

  • 依赖:shared/*@/auth
  • 被依赖:app/api/upload / app/api/files/[id] / app/api/files/batch-delete

已知问题

  • P2-13 已修复:所有函数 try-catch 吞错误返回空数组/null 所有 catch 块已添加 console.error 输出错误上下文
  • P2 已修复:getFileAttachmentsWithFiltersor(...)! 非空断言清理为安全守卫
  • P2 已修复:getFileAttachmentsWithFiltersconditions 隐式 any[] 改为显式 SQL[] 类型标注
  • ⚠️ 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 无独立模块,可接受)
  • P2 已修复:data-access.ts 中 3 处 catch 块添加 console.error 输出错误上下文getCoursePlans/getCoursePlanById/getSubjectOptions
  • 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 / getParentDashboardData / verifyParentChildRelation / getChildNameList v4 新增:用于详情页头部多子女切换器,一次批量查询避免 N+1
  • ComponentsParentDashboard / ChildCard / ChildDetailHeader / ChildDetailPanel / SiblingSwitcher / ChildHomeworkSummary / ChildHomeworkDetailv4 新增)/ ChildGradeSummary / ChildGradeDetailv4 新增)/ ChildScheduleCard / ParentChildrenDataPage / ParentNoChildrenPage / ParentAttentionBannerv4 新增)/ ParentAttendanceWarningv4 新增)/ ParentAttendanceRateCardv4 新增)/ ParentAttendanceCalendarv4 新增)/ ParentExportButtonv4 新增)

v4 修复(产品/UX 维度)

  • FEAT-G01新增 /parent/leave 请假申请占位页(含 loading.tsx
  • FEAT-G02详情页 Schedule Tab 支持完整周课表(新增 weeklySchedule 字段 + ChildWeeklyScheduleItem 类型 + buildWeeklySchedule 函数)
  • FEAT-G03详情页 Grades Tab 新增 ChildGradeDetail 按科目分组展示(平均分、趋势、最近成绩)
  • FEAT-G04详情页 Homework Tab 新增 ChildHomeworkDetail 展示完整作业信息(状态、截止、提交时间、尝试次数)
  • FEAT-G05考勤页新增 ParentAttendanceWarning 异常预警横幅(聚合缺勤/迟到/低出勤率)
  • FEAT-G06详情页底部新增"Contact Teacher"快捷入口
  • FEAT-G07详情页头部新增 SiblingSwitcher 多子女切换器
  • LAYOUT-P01仪表盘新增 ParentAttentionBanner 待办事项横幅
  • LAYOUT-P02ChildCard 突出 Overdue 异常(红色边框 + AlertTriangle 图标)
  • LAYOUT-P03仪表盘快捷入口改为 4 宫格大图标卡片
  • LAYOUT-P04详情页改为 Tab 布局Overview/Homework/Grades/Schedule/Attendance/Diagnostic
  • LAYOUT-P05详情页新增面包屑导航
  • LAYOUT-P07成绩趋势图 X 轴改用序号,避免日期重叠
  • LAYOUT-P08成绩页新增 ParentExportButton 导出按钮(占位)
  • LAYOUT-P09考勤页新增 ParentAttendanceCalendar 月历视图(按状态着色,支持按月切换)
  • LAYOUT-P10考勤异常高亮与 FEAT-G05 同步实现)
  • NAV-P02Grades/Attendance 页面描述明确职责(多子女对比 vs 单子女详情)
  • NAV-P03详情页实现 ?tab= 参数支持
  • NAV-P04所有 parent 路由新增 loading.tsx 骨架屏 + error.tsx 错误边界
  • DATA-P02成绩卡片新增 TrendIcon 进步/退步/持平标识
  • DATA-P03排名展示新增"Top X%"百分比
  • DATA-P04作业列表新增科目标识 Badge
  • DATA-P05作业分数显示新增"pts"单位
  • DATA-P06考勤页新增 ParentAttendanceRateCard 出勤率汇总卡片
  • HABIT-P01仪表盘"一眼定位异常"能力AttentionBanner 聚合)
  • HABIT-P02待办横幅作业项直接跳转详情页 homework tab1 次点击到达)
  • HABIT-P03多子女切换无需返回仪表盘
  • HABIT-P06仪表盘展示未读/待办数量
  • A11Y-P02Overdue 状态增加 AlertTriangle 图标辅助
  • A11Y-P04成绩图表容器新增 aria-label
  • PERF-P01/P02骨架屏 + 错误边界
  • PERF-P03空状态新增"Contact support"引导按钮
  • PERF-P04ChildCard Link 添加 prefetch
  • MOBILE-P03移动端子女卡片改为水平滑动 Carouselsnap-x
  • MOBILE-P04作业/成绩列表项 min-h-[44px] 触摸区域

依赖关系

  • 依赖:shared/*@/authclasses(合理)、homework(合理)、grades(合理)、users(合理)、school(合理)、attendancev4 新增:考勤页复用 StudentAttendanceView
  • 被依赖:无

已知问题

  • P1 已修复:app/(dashboard)/parent/children/[studentId]/page.tsx 直接访问 DB违反三层架构 改为调用 verifyParentChildRelation data-access 函数
  • P1 已修复:权限校验未加 parentId 条件,存在信息泄露风险 verifyParentChildRelation 同时按 parentId + studentId 过滤
  • P2 已修复:getChildBasicInfo 多次串行查询 改为 Promise.all 并行化,并使用 getStudentActiveClass 一次 JOIN
  • P2 已修复:getGradeOptions 全量查询效率低 改为 getGradeNameById 按 ID 查询
  • P2 已修复:buildHomeworkSummary[...assignments].sort() 不必要拷贝 改为 toSorted()
  • P2 已修复:in7Days 死代码 已删除
  • ⚠️ v4 保留:/parent/leave 为占位页,待后端实现请假审批流后接入
  • ⚠️ v4 保留:ParentExportButton 为占位,待后端实现成绩导出 Server Action 后接入
  • ⚠️ v4 保留:详情页 Attendance/Diagnostic Tab 为占位提示,待对应功能实现后填充
  • 职责单一,正确复用其他模块 data-access

文件清单

文件 行数 职责
data-access.ts 243 子女关系 + 仪表盘数据聚合 + 关系校验 + 子女姓名列表v4 新增 getChildNameList + buildWeeklySchedule
types.ts 79 类型定义(含 JSDocv4 新增 ChildWeeklyScheduleItem
components/parent-dashboard.tsx 110 仪表盘v4 重构:待办横幅 + 宫格快捷入口 + 移动端水平滑动)
components/parent-attention-banner.tsx 128 v4 新增:待办事项/异常聚合横幅(作业项直接跳转详情页 homework tab
components/parent-attendance-warning.tsx 89 v4 新增:考勤异常预警
components/parent-attendance-rate-card.tsx 105 v4 新增:考勤出勤率汇总卡片
components/parent-attendance-calendar.tsx 175 v4 新增考勤月历视图use client
components/parent-export-button.tsx 50 v4 新增:成绩导出按钮(占位)
components/child-card.tsx 148 子女卡片v4 增强:异常突出 + 趋势图标)
components/child-detail-header.tsx 78 详情页头部v4 增强:面包屑)
components/child-detail-panel.tsx 200 详情页 Tab 面板 + SiblingSwitcherv4 重写,集成 Homework/Grade Detail
components/child-homework-summary.tsx 147 作业摘要v4 增强:科目标识 + 触摸区域 + pts 单位)
components/child-homework-detail.tsx 145 v4 新增:作业详情视图(完整作业信息)
components/child-grade-summary.tsx 159 成绩趋势v4 增强:趋势图标 + aria-label
components/child-grade-detail.tsx 165 v4 新增:成绩详情视图(按科目分组分析)
components/child-schedule-card.tsx 119 课表卡片v4 增强:周课表视图)
components/parent-children-data-page.tsx 92 共享数据页v4 增强headerExtra

路由清单

路由 文件 说明
/parent/dashboard dashboard/page.tsx + loading.tsx 家长仪表盘
/parent/grades grades/page.tsx + loading.tsx 多子女成绩聚合
/parent/attendance attendance/page.tsx + loading.tsx 多子女考勤聚合v4 新增预警横幅)
/parent/leave leave/page.tsx + loading.tsx v4 新增:请假申请(占位)
/parent/children/[studentId] children/[studentId]/page.tsx + loading.tsx 子女详情页v4 重构Tab 布局 + 多子女切换)
error.tsx error.tsx v4 新增:错误边界

2.20 elective选课模块

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

导出函数

  • ActionsgetElectiveCoursesAction / createElectiveCourseAction / updateElectiveCourseAction / deleteElectiveCourseAction / getStudentSelectionsAction / selectCourseAction / dropCourseAction / runLotteryAction / getAvailableCoursesForStudentAction
  • Data-accessgetElectiveCourses / getElectiveCourseById / createElectiveCourse / updateElectiveCourse / deleteElectiveCourse / openSelection / closeSelection / buildCourseSelect / mapCourseRow / resolveCourseDisplayNames / CourseCoreRowP3 新增导出,供 data-access-selections 复用)
  • Data-access-operationsselectCourse / dropCourse / runLottery
  • Data-access-selectionsgetCourseSelections / getStudentSelections / getStudentGradeId / getAvailableCoursesForStudent

依赖关系

  • 依赖:shared/*@/authschool P3 已修复:通过 school data-access.getSubjectOptions/getGradeOptions 获取科目/年级名称,不再直查 subjects/grades 表)、users P3 已修复:通过 users data-access.getUserNamesByIds 获取教师姓名,不再直查 users 表)、classes(通过 classes data-access.getStudentActiveGradeId 获取学生年级)
  • 被依赖:无

已知问题

  • P1 已修复:buildCourseSelect 跨模块 join users/subjects/grades 表 改为只查 electiveCourses 表,通过 resolveCourseDisplayNames 调用 school/users data-access 获取显示名称
  • P1 已修复:getSubjectOptions 本地直查 subjects 表且与 school 模块重复 删除本地实现,改用 school/data-access.getSubjectOptions
  • P1 已修复:selectCourse/dropCourse 缺事务包裹 改为 db.transaction 包裹FCFS 模式下使用 FOR UPDATE 行锁防止并发超卖
  • P2 已修复:mapCourseRow 在 data-access.ts 与 data-access-selections.ts 重复定义 抽取到 data-access.ts 统一导出data-access-selections.ts 复用
  • P2 已修复:runLottery 使用 sort(() => Math.random() - 0.5) 有偏 shuffle 改为 Fisher-Yates 无偏洗牌算法
  • P2 已修复:selectCourse FCFS 并发超卖风险 使用 db.transaction + .for("update") 行锁
  • 权限校验完整ELECTIVE_MANAGE/SELECT/READ

文件清单

文件 行数 职责
actions.ts 304 11 个 Server Action
data-access.ts 250 课程 CRUD + scope 过滤 + 共享映射函数P3 重构:移除跨模块 join通过 school/users data-access 获取显示名称)
data-access-operations.ts 245 选课操作select/drop/lotteryP3 重构:事务包裹 + FOR UPDATE 锁 + Fisher-Yates 洗牌)
data-access-selections.ts 189 选课记录查询
schema.ts 132 Zod 校验
types.ts 108 类型定义 + 标签常量

2.21 proctoring监考模块

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

导出函数

  • ActionsrecordProctoringEventAction / getProctoringDashboardAction
  • Data-accessrecordProctoringEvent / getExamSubmissionForProctoring / getExamForProctoring / getExamProctoringSummary / getStudentProctoringStatuses / getRecentProctoringEvents P2 已修复:getExamProctoringSummary 使用 Promise.all 并行化考试信息与提交记录查询、事件类型统计与学生事件统计查询;合并两次 filter 为单次循环统计 started/submitted

依赖关系

  • 依赖:shared/*@/authexams P1-1 已修复:通过 exams data-access.getExamForProctoringCrossModule/getExamSubmissionForProctoringCrossModule/getExamSubmissionsForExam/getExamTitleByIdusers P1-1 已修复:通过 users data-access.getUserNamesByIds
  • 被依赖:无

已知问题

  • P0exam-mode-config.tsx 未集成到考试表单(死代码,监考功能无法启用)
  • P0-6 已修复:事件上报存在 Server Action 与 REST API 双通道重复 删除 /api/proctoring/event REST 路由(移至 deletes/Server Action recordProctoringEventAction 为唯一规范路径
  • P1-1 已修复:跨模块直查 exams/examSubmissions/users 改为通过 exams/users data-access 函数获取数据
  • P2 已修复:actions.ts 不再直接 import dbexamSubmissionssubmission 归属校验已下沉到 data-accessrecordProctoringEventAction 改用 requirePermission(EXAM_SUBMIT) 并增加 revalidatePath
  • P2 已修复:getStudentProctoringStatuses 串行查询getUserNamesByIds 后再查事件) 改为 Promise.all 并行拉取学生姓名与事件记录

文件清单

文件 行数 职责
data-access.ts 409 事件记录 + 查询 + 摘要统计 + submission 归属校验
actions.ts 139 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 P2 已修复:getDiagnosticReportsgetDiagnosticReportById 使用 React.cache() 包装实现请求级 memoization
  • SchemaGenerateStudentReportSchema / GenerateClassReportSchema / PublishReportSchema / DeleteReportSchema / GetDiagnosticReportsSchema / GetDiagnosticReportByIdSchema

依赖关系

  • 依赖:shared/*@/authexams P1-1 已修复:通过 exams data-access.getExamSubmissionWithAnswersquestions P1-1 已修复:通过 questions data-access.getKnowledgePointsForQuestionsclasses P1-1 已修复:通过 classes data-access.getClassExists/getClassNameById/getActiveStudentIdsByClassIdusers P1-1 已修复:通过 users data-access.getUserNamesByIds/getUserIdsByGradeId
  • 被依赖:无

已知问题

  • P1-1 已修复:updateMasteryFromSubmission 跨模块直查 4 张表(与 exams/homework/questions 紧耦合) 改为调用 exams/data-access.getExamSubmissionWithAnswersquestions/data-access.getKnowledgePointsForQuestions
  • P2 已修复:data-access-reports.ts 有未使用代码(round2 + void round2 已删除死代码
  • P2 已修复:updateMasteryFromSubmission 循环内串行 await upsert 改为 Promise.all 并行执行所有 upsert
  • P2 已修复:getClassMasterySummary 串行查询className → studentIds → userMap → masteryRows 改为两组 Promise.all 并行className+studentIdsuserMap+masteryRows
  • P2 已修复:getDiagnosticReportsconditions 隐式 any[] 改为显式 SQL[] 类型标注
  • ⚠️ P2班级报告将生成者 ID 存入 studentId 字段schema 设计缺陷 workaround
  • 与 grades 模块无职责重叠grades 管分数diagnostic 管知识点掌握度)

文件清单

文件 行数 职责
data-access.ts 254 知识点掌握度查询 + 更新
data-access-reports.ts 202 诊断报告 CRUD
actions.ts 172 6 个 Server Action使用 Zod schema 校验)
schema.ts 56 Zod 校验6 个 schema生成/发布/删除/查询报告)
types.ts 97 类型定义
components/* 4 文件 学生/班级诊断视图 + 雷达图

2.23 settings设置模块

职责:系统设置(学校信息/安全策略/文件上传/通知配置)+ AI Provider 管理 + 密码修改 + 个人资料 + 主题偏好 + 通知偏好。

导出函数

  • ActionsgetAiProvidersAction / createAiProviderAction / updateAiProviderAction / deleteAiProviderAction / testAiProviderAction
  • Actions-passwordchangePasswordAction P1 已修复:使用 requirePermission(USER_PROFILE_UPDATE) + Zod 校验 + DB 操作下沉到 data-access
  • Data-accessgetAiProviderSummaries / countDefaultAiProviders / getAiProviderForUpdate / updateAiProvider / createAiProvider / getUserPasswordHash / getPasswordSecurityByUserId / updateUserPassword / upsertPasswordSecurityOnPasswordChangeP1 新增,从 actions 下沉)
  • ComponentsSettingsViewP2-a 新增:统一设置页布局,消除 admin/teacher/student/parent 四个设置视图的重复布局5 标签页 General/Notifications/Appearance/Security/AI角色差异通过 description / backHref / generalExtra 三个 props 注入Tab 通过 URL ?tab= 参数持久化AI 标签页条件渲染需 AI_CONFIGURE 权限;登出按钮使用 AlertDialog 二次确认4 个消费方admin/teacher/student/parent 设置页)、ParentSettingsView家长设置视图backHref 指向 /parent/dashboard,含家长专属快捷链接)、AdminSettingsView系统设置视图4 个 Card学校信息/安全策略/文件上传/通知配置;消费方:/admin/settings 页面,权限 SETTINGS_ADMIN
  • TypesAiProviderSummary / AiProviderName / AiProviderExistingP1 新增,从 actions.ts 迁出)

依赖关系

  • 依赖:shared/*(含 shared/lib/bcrypt-utils P2 已修复:actions-password.ts 删除本地 normalizeBcryptHash,统一复用 shared/lib/bcrypt-utils.normalizeBcryptHash)、@/authmessaging(通知偏好表单调用 messaging Action
  • 被依赖:无

已知问题

  • ⚠️ P2混合 5 类职责AI Provider + 密码 + 资料 + 主题 + 通知偏好)
  • P1 已修复:data-access.tsactions.ts 直接使用 db 新建 data-access.ts,所有 DB 操作已下沉
  • P1 已修复:changePasswordAction 使用 requireAuth() 无 Zod 校验 改为 requirePermission(USER_PROFILE_UPDATE) + ChangePasswordSchema Zod 校验 + 并行查询优化
  • P2 已修复:actions-password.ts 删除本地 normalizeBcryptHash,统一复用 shared/lib/bcrypt-utils.normalizeBcryptHash,消除重复代码
  • P2-a 已修复:admin/teacher/student 三个设置视图重复布局 新增 SettingsView 统一设置页布局5 标签页 + 角色差异通过 props 注入4 个设置页改为消费 SettingsView
  • parent 角色路由已修复:parent 用户被错误渲染为 TeacherSettingsView 新增 ParentSettingsView/settings 页面增加 parent 角色分支
  • Tab URL 持久化已修复:SettingsView 改为受控模式,通过 useSearchParams 读取 tab 参数,router.push 更新 URL
  • 登出二次确认已修复:SettingsView 的 Log out 按钮使用 AlertDialog 包裹,点击时弹出确认对话框
  • AiProviderSettingsCard 已集成:SettingsView 新增 AI 标签页,条件渲染需 AI_CONFIGURE 权限
  • password-change-form 任意值 Tailwind 类已修复:[&>div]:bg-red-500 等任意值类 Progress 组件新增 indicatorClassName prop使用标准颜色类
  • ⚠️ P2notification-preferences-form.tsx 跨模块 UI 依赖
  • 密码修改有速率限制
  • AI Provider 操作有 AI_CONFIGURE 权限校验

文件清单

文件 行数 职责
actions.ts 178 AI Provider CRUD + 测试P1 已修复,无直接 DB 操作)
actions-password.ts 107 修改密码P1 已修复requirePermission + Zod + data-access
data-access.ts 175 AI Provider CRUD + 密码修改 DB 操作P1 新增)
types.ts 16 类型定义P1 新增AiProviderSummary 等)
components/settings-view.tsx 196 SettingsView 统一设置页布局P2-a 新增5 标签页 + props 注入角色差异 + Tab URL 持久化 + 登出二次确认 + AI 标签页)
components/admin-settings-view.tsx 195 AdminSettingsView 系统设置视图4 个 Card学校信息/安全策略/文件上传/通知配置,模拟保存)
components/parent-settings-view.tsx 70 ParentSettingsView 家长设置视图(新增,复用 SettingsView 布局)
components/* 9 文件 通用设置 + AI 配置 + 密码 + 主题 + 通知偏好 + 4 角色设置视图

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(通知下拉)、shared/components/ui/select(角色切换下拉)
  • 被依赖:app/(dashboard)/layout.tsx

已知问题

  • P2 已修复:用权限反推角色 app-sidebar.tsx 改用 hasRole() 判断角色,并新增多角色切换机制(SidebarContext.currentRole/setCurrentRolenull 表示自动检测;当用户拥有多个角色时在侧边栏底部显示 Select 下拉切换)
  • navigation.ts 无幽灵路由13 个已修复)

文件清单

文件 职责
components/app-sidebar.tsx 侧边栏(根据权限渲染 + 多角色切换下拉)
components/sidebar-provider.tsx 侧边栏状态 ContextcurrentRole/setCurrentRole
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 获取
  • 认证模式已统一:所有 student 页面使用 getCurrentStudentUser()users 模块)或 getAuthContext()shared 模块),不再直接调用 auth()getDemoStudentUser()

文件清单

文件 职责
components/student-courses-view.tsx 学生课程视图(含 ClassCard memo 组件 + 加入班级表单,使用 useTransition
components/student-schedule-filters.tsx 课表筛选器
components/student-schedule-view.tsx 学生课表视图

路由文件清单app/(dashboard)/student/

文件 职责
dashboard/page.tsx + loading.tsx 学生仪表盘 + 骨架屏
attendance/page.tsx + loading.tsx 学生考勤 + 骨架屏
diagnostic/page.tsx + loading.tsx 学情诊断 + 骨架屏
elective/page.tsx + loading.tsx 选课中心 + 骨架屏
grades/page.tsx + loading.tsx 我的成绩 + 骨架屏
learning/assignments/page.tsx + loading.tsx 作业列表(含 AssignmentCard 组件)+ 骨架屏
learning/assignments/[assignmentId]/page.tsx + loading.tsx 作业作答/复习 + 骨架屏
learning/courses/page.tsx + loading.tsx 课程列表 + 骨架屏
learning/textbooks/page.tsx + loading.tsx 教材列表 + 骨架屏
learning/textbooks/[id]/page.tsx + loading.tsx 教材阅读 + 骨架屏
schedule/page.tsx + loading.tsx 课表 + 骨架屏
error.tsx 路由组错误边界(提供"重试"按钮)

2.27 lesson-preparation备课模块

职责:教师备课,基于教材章节创建课案(节点图编辑器 React Flow),支持模板、版本管理、知识点标注、题目创建/拉取、作业发布。

架构变更2026-06-21编辑器从列表式BlockRenderer + @dnd-kit升级为节点图式NodeEditor + @xyflow/react。数据结构从 v1blocks 数组)升级到 v2nodes + edges 节点图),旧数据通过 migrateV1ToV2() 自动迁移。

数据结构

  • v1已废弃仅向后兼容读取{ version: 1, blocks: Block[] }
  • v2当前{ version: 2, nodes: LessonPlanNode[]; edges: LessonPlanEdge[] }
    • LessonPlanNodeBlock + position: { x, y }(画布坐标)
    • LessonPlanEdge{ id, source, target, sourceHandle?, targetHandle? }(节点间连线)

导出函数

  • Data-accessdata-access.tsgetLessonPlans / getLessonPlanById / createLessonPlan / updateLessonPlanContent / softDeleteLessonPlan / duplicateLessonPlan / getTemplateById / buildInitialContent / migrateV1ToV2v1→v2 迁移blocks 数组转换为 nodes + 线性 edges/ normalizeDocument(规范化:确保 content 为 v2 格式,兼容旧数据)
  • Data-access-versionsdata-access-versions.tsgetLessonPlanVersions / createLessonPlanVersion / getVersionContent / revertToVersion / pruneAutoVersions
  • Data-access-templatesdata-access-templates.tsgetLessonPlanTemplates / saveAsTemplate / deletePersonalTemplate
  • Data-access-knowledgedata-access-knowledge.tsgetLessonPlansByKnowledgePoint / getLessonPlansByQuestion
  • Publish-servicepublish-service.tspublishLessonPlanHomework
  • AI-suggestai-suggest.tssuggestKnowledgePoints
  • ActionsgetLessonPlansAction / getLessonPlanByIdAction / createLessonPlanAction / updateLessonPlanAction / saveLessonPlanVersionAction / getLessonPlanVersionsAction / revertLessonPlanVersionAction / deleteLessonPlanAction / duplicateLessonPlanAction / getLessonPlanTemplatesAction / saveAsTemplateAction / deleteTemplateAction / suggestKnowledgePointsAction / publishLessonPlanHomeworkAction / getKnowledgePointOptionsAction

依赖关系

  • 依赖:shared/*@/authshared/lib/ai@xyflow/react(节点图编辑器)、textbooks(只读章节/知识点树)、questions(创建/查询题目)、exams(创建 exam 草稿)、homework(创建作业下发)、classes(查询教师班级)、files(附件)
  • 被依赖:无

已知问题

  • 通过对方 data-access 调用跨模块数据,无直查跨模块表
  • data-access 按职责拆分为 4 个文件data-access/data-access-versions/data-access-templates/data-access-knowledge
  • actions 按职责拆分为 4 个文件actions/actions-publish/actions-ai/actions-kp
  • 编辑器架构升级NodeEditorReact Flow 画布)+ NodeEditPanel侧边内容编辑面板+ LessonNode自定义节点组件支持节点拖拽、连线、画布缩放
  • ⚠️ block-renderer.tsx 标记为 @deprecated已被 NodeEditor 替代,保留用于向后兼容)

文件清单

文件 职责
types.ts 类型定义(含 v1/v2 文档类型、LessonPlanNode、LessonPlanEdge
constants.ts 常量定义
schema.ts Zod 验证
data-access.ts 课案 CRUD + 模板查询 + 初始内容构建 + v1→v2 迁移migrateV1ToV2 / normalizeDocument
data-access-versions.ts 版本管理(创建/查询/回滚/清理)
data-access-templates.ts 个人模板 CRUD
data-access-knowledge.ts 按知识点/题目反查课案
actions.ts 课案 CRUD/版本/模板 Server Actions
actions-publish.ts 发布作业 Server Action
actions-ai.ts AI 知识点建议 Server Action
actions-kp.ts 知识点选项 Server Action
publish-service.ts 发布作业服务(编排 homework/exams/classes
ai-suggest.ts AI 知识点建议服务
seed-templates.ts 模板种子数据
hooks/use-lesson-plan-editor.ts 课案编辑器 Hook基于 zustand支持 nodes/edges 操作addNode/updateNode/updateNodePosition/removeNode/connect/disconnect/setEdges/selectNode
components/lesson-plan-list.tsx 课案列表
components/lesson-plan-card.tsx 课案卡片
components/lesson-plan-filters.tsx 课案筛选器
components/lesson-plan-editor.tsx 课案编辑器(编排 NodeEditor + NodeEditPanel
components/node-editor.tsx 节点图画布React Flow自定义 LessonNode支持拖拽/连线/缩放)
components/node-edit-panel.tsx 侧边内容编辑面板(选中节点后编辑标题/数据)
components/nodes/lesson-node.tsx 自定义节点组件(按 BlockType 显示图标/颜色,含 Handle 连接点)
components/block-renderer.tsx ⚠️ @deprecated Block 渲染器(已被 NodeEditor 替代,保留向后兼容)
components/template-picker.tsx 模板选择器
components/version-history-drawer.tsx 版本历史抽屉
components/knowledge-point-picker.tsx 知识点选择器
components/question-bank-picker.tsx 题库选择器
components/inline-question-editor.tsx 内联题目编辑器
components/publish-homework-dialog.tsx 发布作业对话框
components/blocks/rich-text-block.tsx 富文本 Block被 NodeEditPanel 复用)
components/blocks/text-study-block.tsx 课文研读 Block被 NodeEditPanel 复用)
components/blocks/exercise-block.tsx 练习 Block被 NodeEditPanel 复用)
components/blocks/reflection-block.tsx 反思 Block被 NodeEditPanel 复用)

第三部分:已知架构问题和技术债

3.1 P0 严重问题(必须立即修复)

P0-1文件超 1000 行硬上限3 个文件)

文件 行数 问题 拆分建议
classes/data-access.ts 2104 → 548 混入 homework/scheduling/grades 逻辑 已拆分 已拆为 5 个文件data-access.ts(548行) + data-access-stats.ts(531行) + data-access-schedule.ts(194行) + data-access-students.ts(244行) + data-access-admin.ts(406行),通过 re-export 保持向后兼容
homework/data-access.ts 1038 → 598 混入排名计算业务逻辑 已拆分 已拆为 data-access.ts(598行) + stats-service.ts(425行),统计函数迁移至 stats-service.ts
shared/db/schema.ts 1111 54 张表混合 按业务域拆分为 schema/auth.ts + schema/academic.ts + schema/exam.ts + ...,通过 index.ts 聚合

P0-2shared/lib ↔ auth 循环依赖 已修复

shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*

影响shared 层无法独立测试/复用;架构上基础设施不应反向依赖应用层。

修复方案(已实施):

  • 创建 shared/lib/session.ts 封装 session 获取(getSession()server-only
  • session.ts 内部使用 dynamic import("@/auth") 打破模块级静态循环
  • audit-logger.ts / change-logger.ts / auth-guard.ts 改为 import { getSession } from "@/shared/lib/session",不再直接依赖 @/auth
  • 运行时调用链保持不变,模块加载图无环

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 原直接调用 createNotificationmessageNotifications 表,导致用户通知偏好失效、多渠道通知无效。notifications/data-access.tsin-app-channel.ts 反向依赖 messaging 模块。

修复方案(已实施):

  • messageNotifications 表的 CRUD 函数(createNotification / getNotifications / markNotificationAsRead / markAllNotificationsAsRead / getUnreadNotificationCount)从 messaging/data-access.ts 迁移到 notifications/data-access.ts
  • notificationPreferences 表的 CRUD 函数(getNotificationPreferences / upsertNotificationPreferences)从 messaging/notification-preferences.ts 迁移到新文件 notifications/preferences.ts
  • NotificationType / Notification / NotificationPreferences / UpdateNotificationPreferencesInput / CreateNotificationInput / GetNotificationsParams / PaginatedResult 类型从 messaging/types.ts 迁移到 notifications/types.ts
  • notifications/channels/in-app-channel.ts 改为静态导入本地 createNotification(不再动态 import messaging
  • notifications/dispatcher.ts 改为从 notifications/preferences.ts 导入 getNotificationPreferences(不再通过 getUserNotificationPreferences 包装器反向依赖 messaging
  • messaging 模块通过 re-export 保持向后兼容:messaging/data-access.ts re-export 通知 CRUDmessaging/notification-preferences.ts 转为 re-export shimmessaging/types.ts re-export 通知类型
  • 依赖方向变为单向messaging → notificationsmessaging 调用 sendNotification dispatcher 发送通知)

P0-5classSchedule 表三处写入口 已修复

  • classes/data-access.tscreateClassScheduleItem 等)
  • scheduling/actions.tsapplyAutoScheduleAction 直接 transaction 写入)
  • scheduling/data-access.ts(间接)

影响:数据完整性高风险。

修复方案(已实施):

  • 将 classSchedule 写函数(createClassScheduleItem / updateClassScheduleItem / deleteClassScheduleItem)从 classes/data-access-schedule.ts 迁移到新文件 scheduling/data-access-class-schedule.ts
  • classes 模块仅保留 READ 函数(getStudentSchedule / getClassSchedule),不再有任何 classSchedule 写入口
  • scheduling 模块通过 classes/data-access.verifyTeacherOwnsClass 跨模块校验教师班级归属(合理依赖)
  • classes/actions.ts 改为从 @/modules/scheduling/data-access-class-schedule 导入写函数
  • 类型 CreateClassScheduleItemInput / UpdateClassScheduleItemInputclasses/types.ts 迁移到 scheduling/types.ts
  • 所有 classSchedule DB 写入统一由 scheduling 模块管理(insertClassScheduleItem / updateClassScheduleItemById / deleteClassScheduleItemById / replaceClassSchedule

P0-6proctoring 死代码与重复实现

  • exam-mode-config.tsx 未集成到考试表单(监考功能无法启用)
  • 事件上报存在 Server Action 与 REST API 双通道重复 已修复

修复方案(已实施):

  • src/app/api/proctoring/event/route.ts 移至 deletes/api/proctoring/event/route.ts,消除事件上报的 REST API 重复通道
  • Server Action recordProctoringEventActionproctoring/actions.ts)为唯一规范路径
  • exam-mode-config.tsx 暂保留原位(集成到考试表单属于功能新增,不在本次修复范围)

3.2 P1 较严重问题(短期执行)

P1-1跨模块直接 DB 查询普遍存在 已修复

被访问表 访问次数 应归属模块 主要违规者
classes 8+ classes exams/homework/grades/dashboard 已改为通过 classes data-access
classEnrollments 6+ classes homework/grades/attendance/users 已改为通过 classes data-access
users 6+ users 多个模块已改为通过 users data-access
subjects 6+ school exams/homework/questions/grades 已改为通过 school data-access
exams 5+ exams homework/grades/dashboard/classes 已改为通过 exams data-access
homeworkAssignments 5+ homework classes反向直查已改为通过 homework/data-access-classes

修复方案(已实施):

  • 各模块 data-access 暴露查询接口:
    • classes/data-accessgetClassGradeIdsByClassIds 已实现 / getClassStudentsByClassId / getActiveClassStudents / getClassExists / getClassNameById / getClassNamesByIds / getActiveStudentIdsByClassId / getStudentActiveClassId / getClassesByGradeId / verifyTeacherOwnsClass / getTeacherIdForMutations
    • exams/data-accessgetExamForHomeworkCreation 已实现(getExamIdsByGradeIds / getExamSubjectIdMap / getExamWithQuestionsForHomework / getExamSubmissionWithAnswers / getExamForProctoringCrossModule / getExamSubmissionForProctoringCrossModule / getExamSubmissionsForExam / getExamTitleById
    • school/data-accessgetSubjectOptions / getGradeOptions 已实现
    • users/data-accessgetUserNameByIds / getStudentInfo 已实现(getUserNamesByIds / getUserWithRole / getUserBasicInfo / getUserIdsByGradeId / getCurrentStudentUser
    • textbooks/data-accessgetKnowledgePointOptions 已实现
    • questions/data-accessinsertQuestionWithRelations 已通过 createQuestionWithRelations 供 exams 调用 / getKnowledgePointsForQuestions
    • homework/data-access-classes 新增 7 个函数供 classes 模块跨模块调用

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

已完成修复2026-06-17commit 84d66364 个模块的 actions 层 DB 操作全部下沉到 data-access

模块 问题 Action 修复内容
exams updateExamAction / deleteExamAction / duplicateExamAction / getExamPreviewAction / getSubjectsAction / getGradesAction 新增 7 个 data-access 函数getExamCreatorId/updateExamWithQuestions/deleteExamById/duplicateExam/getExamPreview/getExamSubjects/getExamGradesactions.ts 831→691 行data-access.ts 374→471 行
homework createHomeworkAssignmentAction157 行)/ startHomeworkSubmissionAction / saveHomeworkAnswerAction / submitHomeworkAction / gradeHomeworkSubmissionAction 新建 data-access-write.ts285 行10 个写函数actions.ts 387→239 行
questions createQuestionAction / updateQuestionAction / deleteQuestionAction / getKnowledgePointOptionsAction 新增 4 个 data-access 函数createQuestionWithRelations/updateQuestionById/deleteQuestionByIdRecursive/getKnowledgePointOptionsactions.ts 294→149 行data-access.ts 138→260 行
announcements 所有写操作 Action 新增 5 个 data-access 函数insertAnnouncement/updateAnnouncementById/deleteAnnouncementById/publishAnnouncementById/archiveAnnouncementByIdactions.ts 242→197 行data-access.ts 120→171 行

剩余未修复模块(不在本次 P1-2 范围):

  • usersupdateUserProfileAction 直接 db.update 已下沉到 data-accessP1-1 修复)
  • schedulingapplyAutoScheduleAction / autoScheduleAction 直接 db.transaction + db.select 已改为调用 replaceClassSchedule 统一写入口;autoScheduleAction 直查 users 表已改为通过 users data-accessP0-5 / P1-1 修复)

P1-3auth.ts 混合 5 类职责 已完成

src/auth.ts 原 293 行混合NextAuth 配置 + 密码安全 DB 操作 + 角色规范化 + IP 解析 + 回调函数。

已完成拆分auth.ts 现 193 行,仅保留 NextAuth 配置):

  • 密码安全 DB 操作 → shared/lib/password-security-service.tsgetOrCreatePasswordSecurity / recordFailedLogin / resetFailedLoginserver-only
  • 角色规范化 → shared/lib/role-utils.tsnormalizeRole / resolvePrimaryRole纯函数
  • bcrypt 哈希规范化 → shared/lib/bcrypt-utils.tsnormalizeBcryptHash纯函数
  • IP 解析 → shared/lib/http-utils.tsresolveClientIpserver-only

后续可选优化(未执行,需保持 NextAuth 配置不变原则下评估):

  • authorize 回调可进一步拆分为 checkRateLimit / checkAccountLockout / verifyPassword / loadUserRoles,使 auth.ts 降至 ≤150 行

P1-4users/import-export.ts 四重职责 已完成

users/import-export.ts 原 291 行混合:导入解析 + 导出 + 用户创建(含密码哈希)+ 班级注册(跨模块写 classEnrollments

已完成拆分import-export.ts 现 157 行,仅保留文件解析/生成):

  • 用户创建(含密码哈希、角色分配)→ user-service.tsbatchImportUsers82 行server-only
  • 班级注册 → class-registration.tsregisterStudentByInvitationCode21 行server-only
  • batchImportUsers 不再直写 classEnrollments,改为调用 classes/data-access.enrollStudentByInvitationCode
  • import-export.ts 通过 re-export batchImportUsers / UserImportResult 保持向后兼容(actions.tsapp/api/export/route.ts 无需修改)

P1-5notifications 反向依赖 messaging 已完成

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

已完成修复(与 P0-4 一并解决):

  • messageNotificationsnotificationPreferences 表所有权移交 notifications 模块
  • notifications/data-access.ts 不再 import messaging 模块
  • notifications/channels/in-app-channel.ts 改为静态导入本地 createNotification(不再动态 import messaging
  • notifications/dispatcher.ts 改为从本地 preferences.ts 导入偏好函数
  • messaging 模块通过 re-export 保持向后兼容

P1-6三个 logger 重复实现 IP/Header 提取 已修复

audit-logger.ts / change-logger.ts / login-logger.ts / auth.ts 四处重复实现 IP/User-Agent 提取逻辑,且实现略有差异。

修复方案(已实施):

  • shared/lib/http-utils.ts 新增 getUserAgent() 函数(与已有 resolveClientIp() 配套)
  • audit-logger.ts / change-logger.ts / login-logger.ts 改为从 @/shared/lib/http-utils 导入 resolveClientIpgetUserAgent,删除本地重复实现
  • auth.ts 已在 P1-3 中改用 resolveClientIp
  • 四处实现统一,消除不一致风险(resolveClientIpx-forwarded-for 第一段,更准确)

3.3 P2 代码质量问题(机会修复)

序号 问题 模块
P2-1 exams/ai-pipeline.ts 857 行,混合 4 类职责 exams
P2-2 exams/actions.ts 832 行(超 800 建议) 已修复P1-2 后降至 691 行) exams
P2-3 shared/lib/ai.ts 218 行,混合 5 类职责 已修复P2-2 已拆分为 ai/ 目录) shared
P2-4 onboarding-gate.tsx 业务逻辑泄漏到 shared 已修复(迁移至 modules/onboarding/,改用独立路由 + Server Action + middleware 重定向) shared/onboarding
P2-5 global-search.tsx 业务类型硬编码在 shared shared
P2-6 proxy.ts 硬编码权限字符串,未复用 Permissions 常量 已修复(改用 Permissions 常量) proxy
P2-7 useA11yId Hook 错放在 lib/ 而非 hooks/ 已修复(文件已不存在;use-aria-live.ts 已在 hooks/ 目录) shared
P2-8 schema.ts 分节编号混乱section 12 出现在 14b 之后) 已修复(重新编号为连续 1-24 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 吞错误 已修复(所有 catch 块已添加 console.errorconditions 隐式 any[] 改为 SQL[] files
P2-14 elective runLottery 使用 Math.random 已修复(改为 Fisher-Yates 无偏洗牌) elective
P2-15 elective selectCourse FCFS 并发超卖风险 已修复db.transaction + FOR UPDATE 行锁) elective
P2-16 diagnostic 班级报告 studentId 字段复用 diagnostic
P2-17 layout 用权限反推角色 已修复(app-sidebar.tsx 改用 hasRole() 判断角色N3 新增多角色切换机制:SidebarContext.currentRole/setCurrentRole + 侧边栏底部 Select 下拉) layout
P2-18 scheduling/actions.ts 末尾 re-export data-access 已修复(移除 re-export4 个页面改为从 data-access 导入) scheduling
P2-19 ExamAssembly / ExamPreviewQuestionEditor 10 个 props exams
P2-20 homework/data-access.getDemoStudentUser 使用 auth() 而非 auth-guard 已修复(已迁移至 users/data-access.getCurrentStudentUser6 个 student 页面改用 users 模块;elective 页面改用 getAuthContext()homework 保留 re-export 向后兼容) homework

3.4 解耦优先级路线图

立即执行P0

  1. 拆分 classes/data-access.ts2104 行 → 按职责拆 3-4 个文件) 已完成(拆为 5 个文件data-access.ts 548行 + data-access-stats.ts 531行 + data-access-schedule.ts 194行 + data-access-students.ts 244行 + data-access-admin.ts 406行
  2. 拆分 homework/data-access.ts1038 行 → 分离排名逻辑) 已完成(拆为 data-access.ts 598行 + stats-service.ts 425行
  3. 修复 shared/libauth 循环依赖 已完成(新增 shared/lib/session.ts 单一入口3 个 shared/lib 文件改为通过 getSession 获取 sessiondynamic import 打破静态循环)
  4. dashboard 改为通过各模块 data-access 获取数据 已完成P0-3 修复:并行调用各模块 dashboard stats 函数)
  5. messaging 写通知改为通过 notifications dispatcher 已完成P0-4 / P1-5 修复:通知 CRUD 和偏好迁移至 notifications 模块messaging 通过 dispatcher 发送通知)
  6. 统一 classSchedule 写入口到 scheduling 模块 已完成P0-5 修复classSchedule 写函数从 classes/data-access-schedule.ts 迁移至 scheduling/data-access-class-schedule.tsclasses 模块仅保留读函数)
  7. 集成 proctoring/exam-mode-config 到考试表单 部分完成P0-6 修复:删除重复的 /api/proctoring/event REST 路由Server Action 为唯一规范路径exam-mode-config.tsx 集成属于功能新增,暂保留原位)

短期执行P1

  1. actions 层移除直接 DB 操作exams/homework/questions/announcements/users/scheduling 已完成(全部 6 个模块均已修复)
  2. 拆分 auth.ts 已完成4 个辅助函数组迁移至 shared/libauth.ts 保留 NextAuth 配置)
  3. 拆分 users/import-export.ts 已完成(拆为 import-export.ts 157行 + user-service.ts 82行 + class-registration.ts 21行班级注册改为调用 classes/data-access
  4. 消除 notifications → messaging 反向依赖 已完成P0-4 / P1-5 修复:通知表所有权迁移至 notificationsin-app-channel 改为静态导入)
  5. 提取 shared/lib/http-utils.ts 统一 IP 提取 已完成(新增 getUserAgent,三个 logger 统一复用 resolveClientIp / getUserAgent
  6. 各模块暴露跨模块查询接口(见 P1-1 已完成(所有跨模块直查已改为通过对方 data-access 接口)

中期执行P2

  1. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数) 已完成P1-1 修复)
  2. schema.ts 按业务域分节 已完成P2-8 修复:重新编号为连续 1-24消除 8b/14b/乱序问题)
  3. 拆分 exams/ai-pipeline.ts
  4. 拆分 shared/lib/ai.ts 已完成P2-2commit 6588f74拆分为 ai/ 目录 6 个文件,原 ai.ts 保留为重导出)
  5. shared 层业务逻辑下沉到 modules 层
  6. 代码质量问题逐项修复( 大部分已修复React.cache 包装、Promise.all 并行化、错误吞没清理、非空断言清理、函数返回类型补齐、重复代码提取、合并 filter 遍历、Set/Map 优化、P2-6 proxy.ts 权限常量复用、P2-11 announcements 死代码清理、P2-17 layout 角色判断、P2-18 scheduling re-export 移除)

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模块间依赖矩阵

行表示使用方,列表示被使用方。 合理依赖, 违规直查, 循环依赖。 P1-1 已修复:所有跨模块直查已改为通过对方 data-access 接口。

↓ 使用 → shared auth exams homework questions textbooks classes school dashboard users grades messaging notifications lesson-prep 其他
shared - 已修复 - - - - - - - - - - - - -
auth(root) db/lib - - - - - - - - - - - - - -
exams - - data-access - data-access data-access - - - - - - -
homework data-access - 关系 - data-access data-access - data-access - - - - -
questions - - - data-access - - - - - - - - -
textbooks - - UI - - - - - - - - - -
classes data-access data-access - - - data-access - - - - - - schedulingP0-5data-access-class-schedule 写函数)
school - - - - - - - ⚠️可接受 - - - - -
grades 外键 外键 - - data-access data-access - data-access - - - - -
dashboard data-access data-access data-access data-access data-access - - data-access - - - - -
users - - - - data-access - - - - - - - -
messaging - - - - data-access - - - - - dispatcher - -
notifications - - - - data-access - - - - - - - -
attendance - - - - data-access - - - - - - - -
scheduling - - - - data-access - - data-access - - - - -
proctoring data-access - - - - - - data-access - - - - -
diagnostic data-access - data-access - data-access - - data-access - - - - -
parent - data-access - - data-access data-access - data-access data-access - - - -
elective - - - - data-access data-access - data-access - - - - -
course-plans - - - - - - - - - -
audit - - - - - - - - - - - - -
announcements - - - - - - - - - - - -
files - - - - - - - - - - - - -
settings - - - - - - - - - - - -
layout - - - - - - - - - - - -
lesson-preparation data-access data-access data-access data-access data-access - - - - - - - files/ai

附录 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) 读取作业洞察( P0-7 已修复:通过 homework/data-access-classes 获取数据)
  5. homework/data-access.getHomeworkAssignments({ classId }) 过滤作业列表
  6. auth-guard.ts 中通过 classSubjectTeachers 查询教师关联的 classIds构建 DataScope.class_taught

permission

  1. shared/types/permissions.tsPermissions 常量定义61 个权限点)
  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/session.ts (P0-2 新增session 获取单一入口)
getSession(): Promise<AppSession>

// shared/lib/http-utils.ts (P1-6 完成,统一 IP/UA 提取)
resolveClientIp(): Promise<string>
getUserAgent(): Promise<string>

// shared/lib/ai/ (P2-2 已拆分,原 ai.ts 保留为重导出)
// ai/client.ts
createAiChatCompletion(input: AiChatRequest): Promise<{ content, usage }>
// ai/payload-parser.ts
parseAiChatPayload(body: unknown): AiChatRequest
// ai/api-key-crypto.ts
encryptAiApiKey(value: string): string
decryptAiApiKey(value: string): string

// shared/lib/password-policy.ts
validatePassword(password: string): { valid: boolean; errors: string[] }
getPasswordStrength(password: string): "weak" | "medium" | "strong"
isAccountLocked(failedAttempts: number, lastFailedAt: Date | null): boolean

// shared/lib/rate-limit.ts
rateLimit(params: { key: string; limit: number; windowMs: number }): RateLimitResult
rateLimitKey(prefix: string, identifier: string): string
rateLimitHeaders(result: RateLimitResult): Record<string, string>

// shared/lib/excel.ts
exportToExcel(params: { sheets: ExcelSheet[] }): Promise<Buffer>
parseExcel(buffer: Buffer): Promise<ParsedSheet[]>
generateTemplate(params: { sheets: TemplateSheet[] }): Promise<Buffer>

// shared/lib/file-storage.ts
isAllowedMimeType(mimeType: string): boolean
generateStoragePath(originalName: string): string
formatFileSize(bytes: number): string

// shared/lib/utils.ts
cn(...inputs: ClassValue[]): string
formatDate(date: string | Date, locale?: string): string
getSearchParam(params: SearchParams, key: string): string | undefined
formatNumber(v: number | null | undefined, digits?: number): string

// shared/lib/search-params.ts (re-export from utils.ts)
getParam(params: SearchParams, key: string): string | undefined  // = getSearchParam

业务模块核心 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>  // ✅ P0-7 已修复:通过 homework/data-access-classes 获取数据

// 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