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