refactor: P0-1/2/4 解耦修复 - 拆分过耦合文件 + dashboard 解耦

This commit is contained in:
SpecialX
2026-06-18 01:45:55 +08:00
parent 220061d62e
commit 62be0b9404
18 changed files with 2534 additions and 2130 deletions

View File

@@ -117,7 +117,7 @@
┌──────────┐
│ classes │ ◀── 耦合最严重模块
└────┬─────┘ data-access.ts 2104 行
└────┬─────┘ data-access.ts 已拆分为 5 文件 (✅ P0-1 已修复)
│ ═══ 混入 homework/scheduling/grades 逻辑
│ 直查 homeworkAssignments/exams
@@ -321,20 +321,22 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
[DataAccess] dashboard/data-access.getAdminDashboardData
├─▶ db.query.sessions.count() ❌ 跨模块直查auth
├─▶ db.query.users.count() ❌ 跨模块直查users
├─▶ db.query.usersToRoles ❌ 跨模块直查users
├─▶ db.query.roles ❌ 跨模块直查users
├─▶ db.query.classes.count() ❌ 跨模块直查classes
├─▶ db.query.textbooks.count() ❌ 跨模块直查textbooks
├─▶ db.query.chapters.count() ❌ 跨模块直查textbooks
├─▶ db.query.questions.count() ❌ 跨模块直查questions
├─▶ db.query.exams (含 scope 过滤) ❌ 跨模块直查exams
├─▶ db.query.homeworkAssignments ❌ 跨模块直查homework
└─▶ db.query.homeworkSubmissions ❌ 跨模块直查homework
├─▶ 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
⚠️ 单函数直查 11 张跨模块表,是本次审查最严重的封装违规
建议:各模块暴露 getModuleStats(scope) 函数dashboard 聚合调用
✅ P0-4 已修复dashboard 改为并行调用各模块 dashboard stats 函数,不再直查跨模块表
```
---
@@ -402,7 +404,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**依赖关系**
- 依赖:`shared/*``@/auth``questions`(类型)、`classes`(❌ 直查)、`school`(❌ 直查 subjects/grades`questions`(❌ 直查 insert
- 被依赖:`homework`(通过 sourceExamId 外键,合理)、`dashboard`❌ 直查)、`proctoring`(❌ 直查)
- 被依赖:`homework`(通过 sourceExamId 外键,合理)、`dashboard`通过 data-accessP0-4 已修复)、`proctoring`(❌ 直查)
**已知问题**
- ❌ P0`persistAiGeneratedExamDraft` 直接 insert 到 `questions`
@@ -429,23 +431,25 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**导出函数**
- Actions`createHomeworkAssignmentAction` / `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction`
- Data-access`getHomeworkAssignments` / `getHomeworkAssignmentById` / `getHomeworkSubmissions` / `getStudentHomeworkAssignments` / `getStudentHomeworkTakeData` / `getStudentDashboardGrades` / `getHomeworkAssignmentAnalytics` / `getHomeworkAssignmentReviewList` / `getHomeworkSubmissionDetails` / `getTeacherGradeTrends` / `getDemoStudentUser`
- 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` 1038 行超 1000 硬上限),必须拆分
- P0`getStudentDashboardGrades` 混入 150+ 行排名计算业务逻辑
- P0`getHomeworkAssignmentAnalytics` 混入 145+ 行错误率统计业务逻辑
- P0 已解决`data-access.ts` 已拆分至 596 行(原 1038 行超 1000 硬上限),统计函数迁移至 `stats-service.ts`
- P0 已解决`getStudentDashboardGrades` 排名计算逻辑迁移至 `stats-service.ts`
- P0 已解决`getHomeworkAssignmentAnalytics` 错误率统计逻辑迁移至 `stats-service.ts`
- ❌ P15 处直查 `exams`
- ❌ P1`actions.ts` 多处直接 DB 操作(`createHomeworkAssignmentAction` 157 行)
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 1038 | 作业 CRUD + 学生视角 + 分析 + 批改(超硬上限 |
| `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 校验 |
@@ -489,7 +493,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**依赖关系**
- 依赖:`shared/*``@/auth`
- 被依赖:`questions`(❌ 直查)、`exams`(通过类型)、`dashboard`❌ 直查
- 被依赖:`questions`(❌ 直查)、`exams`(通过类型)、`dashboard`通过 data-accessP0-4 已修复
**已知问题**
- ✅ 无跨模块 DB 访问
@@ -549,10 +553,10 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**依赖关系**
- 依赖:`shared/*``@/auth``school`(❌ actions 直查 grades 表)、`homework`(❌ data-access 直查 5 张 homework 表)、`exams`(❌ data-access 直查)
- 被依赖:`exams`/`homework`/`grades`/`attendance`/`scheduling`/`dashboard`/`parent`/`course-plans`/`users`8+ 处直查 classes 表)
- 被依赖:`exams`/`homework`/`grades`/`attendance`/`scheduling`/`dashboard`(通过 data-accessP0-4 已修复)/`parent`/`course-plans`/`users`8+ 处直查 classes 表)
**已知问题**
- P0`data-access.ts` 2104 行(超 1000 硬上限 2.1 倍),必须拆分
- 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`
@@ -563,7 +567,11 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | 2104 | 班级 CRUD + 作业洞察 + 课表 + 成绩(严重超限 |
| `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 | 类型定义(含跨领域类型污染) |
@@ -665,7 +673,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(❌ `batchImportUsers` 直查 classes + 直写 classEnrollments
- 被依赖:`dashboard`❌ 直查)、`grades`(❌ 直查)、`homework`(❌ 直查)
- 被依赖:`dashboard`通过 data-accessP0-4 已修复)、`grades`(❌ 直查)、`homework`(❌ 直查)
**已知问题**
- ❌ P1`import-export.ts` 四重职责混合(导入解析 + 导出 + 用户创建 + 班级注册)
@@ -690,18 +698,18 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
- Data-access`getAdminDashboardData` / `getTeacherDashboardData` / `getStudentDashboardData`
**依赖关系**
- 依赖:`shared/*``@/auth``classes`(合理)、`homework`(合理)、`grades`(合理)、❌ 直查 11 张跨模块表
- 依赖:`shared/*``@/auth``classes`通过 data-access合理)、`homework`通过 data-access合理)、`grades`(合理)、`users`/`textbooks`/`questions`/`exams`(通过各模块 dashboard stats 函数P0-4 已修复)
- 被依赖:无
**已知问题**
- P0`getAdminDashboardData` 直查 11 张跨模块表sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions
- P0-4 已修复`getAdminDashboardData` 改为并行调用各模块 dashboard stats 函数(`getUsersDashboardStats`/`getClassesDashboardStats`/`getTextbooksDashboardStats`/`getQuestionsDashboardStats`/`getExamsDashboardStats`/`getHomeworkDashboardStats`),不再直查跨模块表
- ⚠️ P2教师仪表盘直查 `users` 表获取教师姓名
- ✅ 学生/教师仪表盘正确通过各模块 data-access 获取数据
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `data-access.ts` | - | 仪表盘数据聚合(含违规直查 |
| `data-access.ts` | - | 仪表盘数据聚合(P0-4 已修复,通过各模块 data-access 获取数据 |
| `types.ts` | - | 类型定义 |
| `components/*` | 14 文件 | 三种角色仪表盘组件 |
@@ -1093,8 +1101,8 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
| 文件 | 行数 | 问题 | 拆分建议 |
|------|------|------|---------|
| `classes/data-access.ts` | 2104 | 混入 homework/scheduling/grades 逻辑 | 拆为 data-access.ts + data-access-enrollments.ts + data-access-insights.ts迁移 homework/scheduling/grades 逻辑回所属模块 |
| `homework/data-access.ts` | 1038 | 混入排名计算业务逻辑 | 拆为 data-access.ts + data-access-student.ts + data-access-analytics.ts + data-access-grading.ts |
| `classes/data-access.ts` | ~~2104~~ → 656 | ~~混入 homework/scheduling/grades 逻辑~~ ✅ 已拆分 | 拆为 5 个文件:data-access.ts(656行) + data-access-stats.ts(604行) + data-access-schedule.ts(230行) + data-access-students.ts(280行) + data-access-admin.ts(441行),通过 re-export 保持向后兼容 |
| `homework/data-access.ts` | ~~1038~~ → 596 | ~~混入排名计算业务逻辑~~ ✅ 已拆分 | 拆为 data-access.ts(596行) + stats-service.ts(346行),统计函数迁移至 stats-service.ts |
| `shared/db/schema.ts` | 1111 | 54 张表混合 | 按业务域拆分为 schema/auth.ts + schema/academic.ts + schema/exam.ts + ...,通过 index.ts 聚合 |
### P0-2shared/lib ↔ auth 循环依赖
@@ -1110,14 +1118,20 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
- logger 函数改为接收 `session` 参数(由调用方传入)
- 或通过依赖注入打破循环
### P0-3dashboard 跨模块直接查询 11 张表
### P0-3dashboard 跨模块直接查询 11 张表 ✅ 已修复
`dashboard/data-access.ts``getAdminDashboardData` 直查 sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions。
`dashboard/data-access.ts``getAdminDashboardData` 直查 sessions/users/usersToRoles/roles/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions。
**解耦建议**
- 各模块暴露 `getModuleStats(scope?)` 函数
- dashboard 聚合调用:`Promise.all([getUsersStats(scope), getClassStats(scope), ...])`
- 至少消除 dashboard 中重复实现的 exam/homework scope 过滤
**修复方案**(已实施)
- 各模块新增 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-4messaging 绕过 notifications 直接写通知
@@ -1245,8 +1259,8 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
## 3.4 解耦优先级路线图
### 立即执行P0
1. 拆分 `classes/data-access.ts`2104 行 → 按职责拆 3-4 个文件)
2. 拆分 `homework/data-access.ts`1038 行 → 分离排名逻辑)
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
@@ -1301,7 +1315,7 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
| **classes** | ✅ | ✅ | ❌直查 | ❌直查5表 | - | - | - | ❌直查 | - | - | ❌混入 | - | - | - |
| **school** | ✅ | ✅ | - | - | - | - | - | - | - | ⚠️可接受 | - | - | - | - |
| **grades** | ✅ | ✅ | ✅外键 | ✅外键 | - | - | ❌直查 | ❌直查 | - | ❌直查 | - | - | - | - |
| **dashboard** | ✅ | ✅ | ❌直查 | ✅/❌直查 | ❌直查 | ❌直查 | ✅/❌直查 | - | - | ❌直查 | - | - | - | - |
| **dashboard** | ✅ | ✅ | ✅data-access | ✅data-access | ✅data-access | ✅data-access | ✅data-access | - | - | ✅data-access | - | - | - | - |
| **users** | ✅ | ✅ | - | - | - | - | ❌写enrollments | - | - | - | - | - | - | - |
| **messaging** | ✅ | ✅ | - | - | - | - | - | - | - | - | - | - | ❌绕过 | - |
| **notifications** | ✅ | ✅ | - | - | - | - | ❌直查 | - | - | - | - | ⟳反向依赖 | - | - |

View File

@@ -2048,6 +2048,14 @@
"createAiExamAction"
]
},
{
"name": "getExamsDashboardStats",
"signature": "(scope?: DataScope) => Promise<ExamsDashboardStats>",
"purpose": "获取考试仪表盘统计数据(考试总数,支持数据范围过滤)",
"usedBy": [
"dashboard/data-access.getAdminDashboardData"
]
},
{
"name": "omitScheduledAtFromDescription",
"signature": "(description: string | null) => string",
@@ -2535,13 +2543,6 @@
}
],
"dataAccess": [
{
"name": "getTeacherGradeTrends",
"signature": "(teacherId: string, limit?: number) => Promise<TeacherGradeTrendItem[]>",
"usedBy": [
"dashboard (教师仪表盘)"
]
},
{
"name": "getHomeworkAssignments",
"signature": "(params?: { creatorId?, ids?, classId?, scope? }) => Promise<HomeworkAssignmentListItem[]>",
@@ -2571,20 +2572,6 @@
"student/dashboard"
]
},
{
"name": "getStudentDashboardGrades",
"signature": "(studentId: string) => Promise<StudentDashboardGradeProps>",
"usedBy": [
"dashboard/data-access.ts"
]
},
{
"name": "getHomeworkAssignmentAnalytics",
"signature": "(assignmentId: string) => Promise<HomeworkAssignmentAnalytics | null>",
"usedBy": [
"homework错误分析组件"
]
},
{
"name": "getHomeworkAssignmentById",
"signature": "(id: string, scope?: DataScope) => Promise<...>",
@@ -2618,6 +2605,58 @@
]
}
],
"statsService": [
{
"name": "getTeacherGradeTrends",
"file": "stats-service.ts",
"signature": "(teacherId: string, limit?: number) => Promise<TeacherGradeTrendItem[]>",
"purpose": "教师仪表盘年级趋势数据",
"deps": [
"data-access.getAssignmentMaxScoreById"
],
"usedBy": [
"dashboard (教师仪表盘)"
],
"reExportedFrom": "data-access.ts (向后兼容)"
},
{
"name": "getHomeworkAssignmentAnalytics",
"file": "stats-service.ts",
"signature": "(assignmentId: string) => Promise<HomeworkAssignmentAnalytics | null>",
"purpose": "作业整体分析(含题目错误率/错答样本)",
"deps": [
"data-access.isRecord",
"data-access.toQuestionContent"
],
"usedBy": [
"homework错误分析组件"
],
"reExportedFrom": "data-access.ts (向后兼容)"
},
{
"name": "getStudentDashboardGrades",
"file": "stats-service.ts",
"signature": "(studentId: string) => Promise<StudentDashboardGradeProps>",
"purpose": "学生仪表盘成绩(趋势/近期/班级排名)",
"deps": [
"data-access.getAssignmentMaxScoreById"
],
"usedBy": [
"dashboard/data-access.ts"
],
"reExportedFrom": "data-access.ts (向后兼容)"
},
{
"name": "getHomeworkDashboardStats",
"file": "stats-service.ts",
"signature": "(scope?: DataScope) => Promise<HomeworkDashboardStats>",
"purpose": "获取作业仪表盘统计数据(作业数/已发布数/提交数/待批改数,支持数据范围过滤)",
"usedBy": [
"dashboard/data-access.getAdminDashboardData"
],
"reExportedFrom": "data-access.ts (向后兼容)"
}
],
"schema": [
{
"name": "CreateHomeworkAssignmentSchema",
@@ -2941,6 +2980,14 @@
"teacher/questions/page.tsx"
]
},
{
"name": "getQuestionsDashboardStats",
"signature": "() => Promise<QuestionsDashboardStats>",
"purpose": "获取题目仪表盘统计数据(题目总数)",
"usedBy": [
"dashboard/data-access.getAdminDashboardData"
]
},
{
"name": "GetQuestionsParams",
"type": "type",
@@ -3230,6 +3277,14 @@
"usedBy": [
"reorderChaptersAction"
]
},
{
"name": "getTextbooksDashboardStats",
"signature": "() => Promise<TextbooksDashboardStats>",
"purpose": "获取教材仪表盘统计数据(教材总数、章节总数)",
"usedBy": [
"dashboard/data-access.getAdminDashboardData"
]
}
],
"hooks": [
@@ -3618,6 +3673,14 @@
"classes内部"
]
},
{
"name": "getClassesDashboardStats",
"signature": "() => Promise<ClassesDashboardStats>",
"purpose": "获取班级仪表盘统计数据(班级总数)",
"usedBy": [
"dashboard/data-access.getAdminDashboardData"
]
},
{
"name": "createTeacherClass",
"signature": "(input) => Promise<string>",
@@ -4005,7 +4068,83 @@
"purpose": "班级作业组件"
}
]
}
},
"files": [
{
"path": "data-access.ts",
"lines": 656,
"description": "核心班级 CRUD + 邀请码 + 教师班级管理(含 re-export 向后兼容)",
"exports": [
"getTeacherClasses",
"getTeacherOptions",
"getTeacherTeachingSubjects",
"createTeacherClass",
"ensureClassInvitationCode",
"regenerateClassInvitationCode",
"enrollStudentByInvitationCode",
"enrollTeacherByInvitationCode",
"updateTeacherClass",
"setClassSubjectTeachers",
"deleteTeacherClass",
"enrollStudentByEmail",
"setStudentEnrollmentStatus",
"getSessionTeacherId",
"getTeacherIdForMutations",
"getAccessibleClassIdsForTeacher",
"getTeacherSubjectIdsForClass",
"getClassSubjects",
"compareClassLike",
"isDuplicateInvitationCodeError",
"generateUniqueInvitationCode"
]
},
{
"path": "data-access-stats.ts",
"lines": 604,
"description": "作业统计查询(班级/年级作业洞察)",
"exports": [
"getClassHomeworkInsights",
"getGradeHomeworkInsights",
"getClassesDashboardStats"
]
},
{
"path": "data-access-schedule.ts",
"lines": 230,
"description": "课表查询(学生/班级课表 CRUD",
"exports": [
"getStudentSchedule",
"getClassSchedule",
"createClassScheduleItem",
"updateClassScheduleItem",
"deleteClassScheduleItem"
]
},
{
"path": "data-access-students.ts",
"lines": 280,
"description": "学生相关查询(科目成绩、学生名单、学生班级)",
"exports": [
"getStudentsSubjectScores",
"getClassStudentSubjectScoresV2",
"getStudentClasses",
"getClassStudents"
]
},
{
"path": "data-access-admin.ts",
"lines": 441,
"description": "管理员班级管理(管理员班级 CRUD、年级管理班级查询",
"exports": [
"getAdminClasses",
"getGradeManagedClasses",
"getManagedGrades",
"createAdminClass",
"updateAdminClass",
"deleteAdminClass"
]
}
]
},
"school": {
"path": "src/modules/school",
@@ -4250,7 +4389,12 @@
"name": "getAdminDashboardData",
"signature": "(scope?: DataScope) => Promise<AdminDashboardData>",
"deps": [
"shared/db",
"users/data-access.getUsersDashboardStats",
"classes/data-access.getClassesDashboardStats",
"textbooks/data-access.getTextbooksDashboardStats",
"questions/data-access.getQuestionsDashboardStats",
"exams/data-access.getExamsDashboardStats",
"homework/stats-service.getHomeworkDashboardStats",
"DataScope"
],
"usedBy": [
@@ -4655,11 +4799,32 @@
"shared.db.schema.users"
]
},
{
"name": "getUsersDashboardStats",
"signature": "() => Promise<UsersDashboardStats>",
"file": "data-access.ts",
"deps": [
"shared.db",
"shared.db.schema.users",
"shared.db.schema.sessions",
"shared.db.schema.usersToRoles",
"shared.db.schema.roles"
],
"usedBy": [
"dashboard/data-access.getAdminDashboardData"
]
},
{
"name": "UserProfile",
"type": "type",
"file": "data-access.ts",
"definition": "{ id, name, email, image, role, phone, address, gender, age, onboardedAt, createdAt, updatedAt }"
},
{
"name": "UsersDashboardStats",
"type": "type",
"file": "data-access.ts",
"definition": "{ userCount, activeSessionsCount, userRoleCounts, recentUsers }"
}
],
"importExport": [
@@ -10527,38 +10692,38 @@
{
"from": "dashboard",
"to": "exams",
"type": "violation",
"description": "直接查询 exams 表(违规)"
"type": "data-access",
"description": "调用 getExamsDashboardStats 获取考试统计(P0-4 已修复)"
},
{
"from": "dashboard",
"to": "homework",
"type": "violation",
"description": "直接查询 homeworkAssignments/homeworkSubmissions 表(违规)"
"type": "data-access",
"description": "调用 getHomeworkDashboardStats 获取作业统计(P0-4 已修复)"
},
{
"from": "dashboard",
"to": "classes",
"type": "violation",
"description": "直接查询 classes 表(违规)"
"type": "data-access",
"description": "调用 getClassesDashboardStats 获取班级统计(P0-4 已修复)"
},
{
"from": "dashboard",
"to": "users",
"type": "violation",
"description": "直接查询 sessions/users/usersToRoles/roles 表(违规)"
"type": "data-access",
"description": "调用 getUsersDashboardStats 获取用户/会话/角色统计(P0-4 已修复)"
},
{
"from": "dashboard",
"to": "textbooks",
"type": "violation",
"description": "直接查询 textbooks/chapters 表(违规)"
"type": "data-access",
"description": "调用 getTextbooksDashboardStats 获取教材/章节统计(P0-4 已修复)"
},
{
"from": "dashboard",
"to": "questions",
"type": "violation",
"description": "直接查询 questions 表(违规)"
"type": "data-access",
"description": "调用 getQuestionsDashboardStats 获取题目统计(P0-4 已修复)"
},
{
"from": "messaging",
@@ -10714,7 +10879,10 @@
"file": "src/modules/classes/data-access.ts",
"lines": 2104,
"problem": "混入 homework/scheduling/grades 逻辑,严重违反模块职责单一原则",
"suggestion": "按职责拆分为 class-query/schedule/homework-insights/grade-query"
"suggestion": "按职责拆分为 class-query/schedule/homework-insights/grade-query",
"status": "resolved",
"resolvedAt": "2026-06-17",
"resolution": "拆分为 5 个文件data-access.ts(656行,核心CRUD+邀请码+教师班级管理) + data-access-stats.ts(604行,作业统计) + data-access-schedule.ts(230行,课表) + data-access-students.ts(280行,学生查询) + data-access-admin.ts(441行,管理员班级管理),所有文件均 ≤800 行data-access.ts 通过 re-export 保持向后兼容"
},
{
"id": "P0-2",
@@ -10723,7 +10891,10 @@
"file": "src/modules/homework/data-access.ts",
"lines": 1038,
"problem": "混入排名计算业务逻辑",
"suggestion": "分离排名逻辑到独立文件(如 data-access-ranking.ts)"
"suggestion": "分离排名逻辑到独立文件(如 data-access-ranking.ts)",
"status": "resolved",
"resolvedAt": "2026-06-17",
"resolution": "拆分为 data-access.ts(596行) + stats-service.ts(346行),统计函数(getTeacherGradeTrends/getHomeworkAssignmentAnalytics/getStudentDashboardGrades)迁移至 stats-service.tsdata-access.ts 通过 re-export 保持向后兼容"
},
{
"id": "P0-3",
@@ -10739,7 +10910,9 @@
"title": "dashboard 跨模块直接查询 11 张表",
"file": "src/modules/dashboard/data-access.ts",
"problem": "getAdminDashboardData 直查 sessions/users/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions/usersToRoles/roles,严重违反模块封装",
"suggestion": "改为通过各模块 data-access 获取数据"
"suggestion": "改为通过各模块 data-access 获取数据",
"status": "fixed",
"fixedBy": "新增 getUsersDashboardStats/getClassesDashboardStats/getTextbooksDashboardStats/getQuestionsDashboardStats/getExamsDashboardStats/getHomeworkDashboardStats,dashboard 改为并行调用各模块 stats 函数"
},
{
"id": "P0-5",

View File

@@ -55,7 +55,7 @@
**当前关键风险项v3**
1. **`classes/data-access.ts` 严重超标** — 2104 行,超出 1000 行硬上限 2 倍,混入 homework/scheduling/grades 三个业务领域逻辑,维护风险极高
1. ~~**`classes/data-access.ts` 严重超标**~~ — ✅ 已修复2026-06-17 拆分为 5 个文件,均 ≤800 行)
2. **`shared/lib``auth` 循环依赖** — audit-logger/change-logger/auth-guard → @/auth → shared/lib/* 形成循环,影响构建稳定性
3. **dashboard 跨模块直接查询 11 张表** — getAdminDashboardData 直查 sessions/users/classes/textbooks 等 11 张表,严重违反模块封装
4. **messaging 绕过 notifications 直接写通知** — messaging/actions.ts 直接调用 createNotification导致用户通知偏好失效
@@ -268,8 +268,8 @@
| 序号 | 问题 | 文件/位置 | 严重程度 | 说明 |
|------|------|----------|---------|------|
| 1 | 文件超 1000 行硬上限 | `classes/data-access.ts` (2104 行) | 🔴 严重 | 混入 homework/scheduling/grades 三个业务领域逻辑,超出硬上限 2 倍 |
| 2 | 文件超 1000 行硬上限 | `homework/data-access.ts` (1038 行) | 🔴 严重 | 混入排名计算业务逻辑,超出硬上限 |
| 1 | ~~文件超 1000 行硬上限~~ | ~~`classes/data-access.ts` (2104 行)~~ ✅ | ~~🔴 严重~~ | ~~已修复:拆分为 5 个文件data-access 656行 + stats 604行 + schedule 230行 + students 280行 + admin 441行~~ |
| 2 | ~~文件超 1000 行硬上限~~ | ~~`homework/data-access.ts` (1038 行)~~ ✅ | ~~🔴 严重~~ | ~~已修复:拆分为 data-access.ts(596行) + stats-service.ts(346行)~~ |
| 3 | 文件超 1000 行硬上限 | `shared/db/schema.ts` (1111 行) | 🟡 需改进 | 54 张表混合,可接受但需按业务域分节 |
| 4 | 循环依赖 | `shared/lib``@/auth` | 🔴 严重 | audit-logger/change-logger/auth-guard → @/auth → shared/lib/* 形成循环 |
| 5 | dashboard 跨模块直查 11 张表 | `dashboard/data-access.ts` | 🔴 严重 | getAdminDashboardData 直查 sessions/users/classes 等 11 张表,违反模块封装 |
@@ -302,8 +302,8 @@
### 4.4 解耦优先级
**立即执行P0**
1. 拆分 `classes/data-access.ts`2104 行 → 按职责拆 3-4 个文件)
2. 拆分 `homework/data-access.ts`1038 行 → 分离排名逻辑)
1. ~~拆分 `classes/data-access.ts`2104 行 → 按职责拆 3-4 个文件)~~ ✅ 已完成(拆为 5 个文件,均 ≤800 行)
2. ~~拆分 `homework/data-access.ts`1038 行 → 分离排名逻辑)~~ ✅ 已完成
3. 修复 shared/lib ↔ auth 循环依赖
4. dashboard 改为通过各模块 data-access 获取数据
5. messaging 写通知改为通过 notifications dispatcher

View File

@@ -30,8 +30,8 @@
| 文件 | 行数 | 问题 |
|------|------|------|
| `classes/data-access.ts` | 2104 | 混入 homework/scheduling/grades 逻辑 |
| `homework/data-access.ts` | 1038 | 混入排名计算业务逻辑 |
| ~~`classes/data-access.ts`~~ | ~~2104~~ → 656 | ~~混入 homework/scheduling/grades 逻辑~~ ✅ 已拆分为 5 个文件 |
| ~~`homework/data-access.ts`~~ | ~~1038~~ → 596 | ~~混入排名计算业务逻辑~~ ✅ 已拆分 |
| `shared/db/schema.ts` | 1111 | 54 张表混合(可接受,但需分节) |
### 2. 循环依赖
@@ -114,8 +114,8 @@ NextAuth 配置 + 密码安全 DB 操作 + 角色规范化 + IP 解析 + 回调
## 五、解耦优先级
### 立即执行(P0)
1. 拆分 `classes/data-access.ts`(2104 行 → 按职责拆 3-4 个文件)
2. 拆分 `homework/data-access.ts`(1038 行 → 分离排名逻辑)
1. ~~拆分 `classes/data-access.ts`(2104 行 → 按职责拆 3-4 个文件)~~ ✅ 已完成(拆为 5 个文件,均 ≤800 行)
2. ~~拆分 `homework/data-access.ts`(1038 行 → 分离排名逻辑)~~ ✅ 已完成
3. 修复 shared/lib ↔ auth 循环依赖
4. dashboard 改为通过各模块 data-access 获取数据
5. messaging 写通知改为通过 notifications dispatcher

View File

@@ -43,7 +43,7 @@ app/ ──▶ modules/ ──▶ shared/
### P0 严重问题(必须立即修复)
#### P0-1 `classes/data-access.ts` 2104 行,超硬上限 2.1 倍
#### P0-1 `classes/data-access.ts` 2104 行,超硬上限 2.1 倍 ✅ 已修复
**问题**
- 文件行数 2104远超 1000 行硬上限
@@ -58,18 +58,21 @@ app/ ──▶ modules/ ──▶ shared/
**解耦方案**
```
src/modules/classes/
├── data-access.ts # 班级核心 CRUD目标 ≤500 行)
├── data-access-stats.ts # 班级统计查询(getHomeworkStats 等
├── data-access-schedule.ts # 班级课表查询(getClassSchedule 等
── data-access-grades.ts # 班级成绩汇总getClassGradeSummary 等
├── data-access.ts # 班级核心 CRUD656 行)
├── data-access-stats.ts # 班级统计查询(604 行
├── data-access-schedule.ts # 班级课表查询(230 行
── data-access-students.ts # 学生相关查询280 行
└── data-access-admin.ts # 管理员班级管理441 行)
```
**迁移步骤**
1. 创建 3 个新文件,按职责迁移对应函数
2.`data-access.ts` 中 re-export 以保持向后兼容
1. ~~创建 3 个新文件,按职责迁移对应函数~~ ✅ 已创建 4 个新文件
2. ~~在 `data-access.ts` 中 re-export 以保持向后兼容~~ ✅ 已完成
3. 逐步更新调用方 import 路径
4. 最终移除 re-export强制使用新路径
**完成状态**2026-06-17 已完成拆分,所有文件均 ≤800 行,通过 re-export 保持向后兼容
---
#### P0-2 `homework/data-access.ts` 1038 行,混入排名计算
@@ -380,9 +383,9 @@ src/shared/lib/ai/
| 1 | P0-3 修复循环依赖 | shared/lib + auth.ts | 低 |
| 2 | P0-5 messaging 改用 dispatcher | messaging + notifications | 低 |
| 3 | P0-6 统一 classSchedule 写入口 | classes + scheduling | 中 |
| 4 | P0-2 拆分 homework/data-access | homework | 中 |
| 4 | ~~P0-2 拆分 homework/data-access~~ | homework | 中 |
| 5 | P0-4 dashboard 改用模块 data-access | dashboard + 11 个模块 | 高 |
| 6 | P0-1 拆分 classes/data-access | classes + 多个调用方 | 高 |
| 6 | ~~P0-1 拆分 classes/data-access~~ | classes + 多个调用方 | 高 |
### 第二阶段P1 修复(建议 2-4 周)

View File

@@ -12,7 +12,7 @@
| 模块 | 行数(最大文件) | 职责单一性 | 耦合度 | 严重度 |
|------|----------------|-----------|--------|--------|
| school | 325 | ✅ 良好 | ✅ 低 | 🟢 合格 |
| classes | **2104** | ❌ 严重违反 | ❌ 严重 | 🔴 严重 |
| classes | ~~2104~~ → 656 | ✅ 已修复 | ❌ 严重 | 🟡 需改进 |
| scheduling | 310算法/ 302actions | ✅ 算法独立 | ⚠️ 中 | 🟡 需改进 |
| attendance | 271 | ✅ 良好 | ⚠️ 中 | 🟢 合格 |
| users | 291import-export | ❌ 违反 | ❌ 高 | 🟠 较严重 |
@@ -21,7 +21,7 @@
| announcements | 242 | ⚠️ 部分违反 | ✅ 低 | 🟡 需改进 |
**核心结论**
1. `classes` 模块是全项目耦合最严重的模块,单文件 2104 行远超 1000 行硬性上限,混入了 schedule、homework、grades 三个业务领域的逻辑。
1. ~~`classes` 模块是全项目耦合最严重的模块,单文件 2104 行远超 1000 行硬性上限,混入了 schedule、homework、grades 三个业务领域的逻辑。~~ ✅ 已修复2026-06-17 拆分为 5 个文件,均 ≤800 行)
2. `users/import-export.ts` 违反单一职责,同时处理导入、导出、用户创建、班级注册四类逻辑。
3. `scheduling/auto-scheduler.ts` 是算法独立化的**优秀范例**,纯函数、无 DB 访问、可独立测试。
4. `announcements``audit` 模块的 data-access 层不完整,写操作或导出逻辑泄漏到 actions 层。
@@ -49,11 +49,11 @@
---
### 2.2 classes 模块 — 🔴 严重
### 2.2 classes 模块 — 🟡 需改进(文件拆分已修复,跨模块耦合仍存在)
**文件清单**actions.ts (765 行) / data-access.ts (**2104 行**) / types.ts (201 行)
**文件清单**actions.ts (765 行) / data-access.ts (656 行) / data-access-stats.ts (604 行) / data-access-schedule.ts (230 行) / data-access-students.ts (280 行) / data-access-admin.ts (441 行) / types.ts (201 行)
> ⚠️ `data-access.ts` 达 2104 行,**超出 1000 行硬性上限 2 倍**,违反项目代码质量规则
> `data-access.ts` 已于 2026-06-17 拆分为 5 个文件,所有文件均 ≤800 行,通过 re-export 保持向后兼容
#### 2.2.1 职责混乱 — 混入三个外部业务领域