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