docs: 同步架构文档 004/005/007/audit 反映 P1-2/P2-2 解耦修复
This commit is contained in:
@@ -215,18 +215,20 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
│ student/learning/assignments/[assignmentId]/page.tsx │
|
│ student/learning/assignments/[assignmentId]/page.tsx │
|
||||||
│ └─▶ homework/actions.startHomeworkSubmissionAction │
|
│ └─▶ homework/actions.startHomeworkSubmissionAction │
|
||||||
│ ├─▶ requirePermission(HOMEWORK_SUBMIT) │
|
│ ├─▶ requirePermission(HOMEWORK_SUBMIT) │
|
||||||
│ ├─▶ db.query.homeworkAssignments [⚠️ 直接 DB] │
|
│ ├─▶ data-access-write.startHomeworkSubmission ✅ P1-2 已修复 │
|
||||||
│ ├─▶ db.insert(homeworkSubmissions) [⚠️ 直接 DB] │
|
│ │ └─▶ db.insert(homeworkSubmissions) [shared/db] │
|
||||||
│ └─▶ 返回 submissionId │
|
│ └─▶ 返回 submissionId │
|
||||||
│ │
|
│ │
|
||||||
│ └─▶ homework/actions.saveHomeworkAnswerAction │
|
│ └─▶ homework/actions.saveHomeworkAnswerAction │
|
||||||
│ └─▶ db.transaction(insert homeworkAnswers) [⚠️ 直接 DB] │
|
│ └─▶ data-access-write.saveHomeworkAnswer ✅ P1-2 已修复 │
|
||||||
|
│ └─▶ db.transaction(insert homeworkAnswers) [shared/db] │
|
||||||
│ │
|
│ │
|
||||||
│ └─▶ homework/actions.submitHomeworkAction │
|
│ └─▶ homework/actions.submitHomeworkAction │
|
||||||
│ └─▶ db.update(homeworkSubmissions.status="submitted") │
|
│ └─▶ data-access-write.submitHomework ✅ P1-2 已修复 │
|
||||||
|
│ └─▶ db.update(homeworkSubmissions.status="submitted") │
|
||||||
│ │
|
│ │
|
||||||
│ 数据写入:homeworkSubmissions 表 + homeworkAnswers 表 │
|
│ 数据写入:homeworkSubmissions 表 + homeworkAnswers 表 │
|
||||||
│ ⚠️ 违规:actions 层直接 DB 操作,应下沉到 data-access │
|
│ ✅ P1-2 已修复:actions 层不再直接 DB 操作,已下沉到 data-access-write│
|
||||||
└─────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
@@ -236,7 +238,8 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
│ teacher/homework/submissions/[submissionId]/page.tsx │
|
│ teacher/homework/submissions/[submissionId]/page.tsx │
|
||||||
│ └─▶ homework/actions.gradeHomeworkSubmissionAction │
|
│ └─▶ homework/actions.gradeHomeworkSubmissionAction │
|
||||||
│ ├─▶ requirePermission(HOMEWORK_GRADE) │
|
│ ├─▶ requirePermission(HOMEWORK_GRADE) │
|
||||||
│ └─▶ db.update(homeworkAnswers) 循环 [⚠️ 直接 DB] │
|
│ └─▶ data-access-write.gradeHomeworkSubmission ✅ P1-2 已修复│
|
||||||
|
│ └─▶ db.update(homeworkAnswers) 循环 [shared/db] │
|
||||||
│ │
|
│ │
|
||||||
│ 数据更新:homeworkAnswers.isCorrect / score / feedback │
|
│ 数据更新:homeworkAnswers.isCorrect / score / feedback │
|
||||||
└─────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
@@ -308,11 +311,10 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
│
|
│
|
||||||
├─▶ requirePermission(HOMEWORK_SUBMIT)
|
├─▶ requirePermission(HOMEWORK_SUBMIT)
|
||||||
│
|
│
|
||||||
├─▶ db.query.homeworkSubmissions.findFirst ❌ 应在 data-access
|
├─▶ data-access-write.submitHomework ✅ P1-2 已修复
|
||||||
│ (校验 submission 归属)
|
│ (校验 submission 归属 + 更新状态)
|
||||||
│
|
│ └─▶ db.update(homeworkSubmissions)
|
||||||
├─▶ db.update(homeworkSubmissions) ❌ 应在 data-access
|
│ SET status = "submitted", submittedAt = now()
|
||||||
│ SET status = "submitted", submittedAt = now()
|
|
||||||
│
|
│
|
||||||
└─▶ 返回 ActionState<{ submissionId }>
|
└─▶ 返回 ActionState<{ submissionId }>
|
||||||
```
|
```
|
||||||
@@ -370,7 +372,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
- ❌ P0:`shared/lib/*` ↔ `@/auth` 循环依赖
|
- ❌ P0:`shared/lib/*` ↔ `@/auth` 循环依赖
|
||||||
- ⚠️ P1:`schema.ts` 1111 行(54 张表混合,超 1000 硬上限)
|
- ⚠️ 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 配置)
|
- ✅ P1:~~`auth.ts` 293 行混合 5 类职责~~ 已拆分(4 个辅助函数组迁移至 `shared/lib/{role-utils,bcrypt-utils,http-utils,password-security-service}`,auth.ts 仅保留 NextAuth 配置)
|
||||||
- ⚠️ P2:`ai.ts` 218 行混合 5 类职责
|
- ✅ P2-2 已修复:~~`ai.ts` 218 行混合 5 类职责~~ 已拆分为 `ai/` 目录(payload-parser.ts/api-key-crypto.ts/provider-config.ts/client.ts/errors.ts/index.ts),原 `ai.ts` 保留为向后兼容的重导出文件(12 行)
|
||||||
- ⚠️ P2:`onboarding-gate.tsx` 业务逻辑泄漏到 shared
|
- ⚠️ P2:`onboarding-gate.tsx` 业务逻辑泄漏到 shared
|
||||||
|
|
||||||
**文件清单**:
|
**文件清单**:
|
||||||
@@ -381,7 +383,13 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
| `db/index.ts` | - | Drizzle 客户端 |
|
| `db/index.ts` | - | Drizzle 客户端 |
|
||||||
| `lib/auth-guard.ts` | - | 认证上下文 + 权限校验 + DataScope |
|
| `lib/auth-guard.ts` | - | 认证上下文 + 权限校验 + DataScope |
|
||||||
| `lib/permissions.ts` | - | 角色-权限映射 |
|
| `lib/permissions.ts` | - | 角色-权限映射 |
|
||||||
| `lib/ai.ts` | 218 | AI 调用 + Provider 配置 + 加密 |
|
| `lib/ai.ts` | 12 | 向后兼容重导出(P2-2 已拆分到 `ai/` 目录) |
|
||||||
|
| `lib/ai/payload-parser.ts` | 96 | 请求负载解析 |
|
||||||
|
| `lib/ai/api-key-crypto.ts` | 34 | API Key 加密/解密 |
|
||||||
|
| `lib/ai/provider-config.ts` | 66 | Provider 配置查询 |
|
||||||
|
| `lib/ai/client.ts` | 67 | AI 客户端创建与调用 |
|
||||||
|
| `lib/ai/errors.ts` | 9 | 错误格式化 |
|
||||||
|
| `lib/ai/index.ts` | 7 | 聚合导出 |
|
||||||
| `lib/audit-logger.ts` | - | 操作日志 |
|
| `lib/audit-logger.ts` | - | 操作日志 |
|
||||||
| `lib/change-logger.ts` | - | 数据变更日志 |
|
| `lib/change-logger.ts` | - | 数据变更日志 |
|
||||||
| `lib/login-logger.ts` | - | 登录日志 |
|
| `lib/login-logger.ts` | - | 登录日志 |
|
||||||
@@ -406,8 +414,8 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
**职责**:考试全生命周期管理(创建/编辑/预览/发布/删除/复制)+ AI 辅助出题。
|
**职责**:考试全生命周期管理(创建/编辑/预览/发布/删除/复制)+ AI 辅助出题。
|
||||||
|
|
||||||
**导出函数**:
|
**导出函数**:
|
||||||
- Actions:`createExamAction` / `createAiExamAction` / `previewAiExamAction` / `regenerateAiQuestionAction` / `updateExamAction` / `deleteExamAction` / `duplicateExamAction` / `getExamPreviewAction` / `getSubjectsAction` / `getGradesAction`
|
- 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`
|
- Data-access:`getExams` / `getExamById` / `persistExamDraft` / `persistAiGeneratedExamDraft` / `buildExamDescription` / `resolveSubjectGradeNames` / `getExamCreatorId` / `updateExamWithQuestions` / `deleteExamById` / `duplicateExam` / `getExamPreview` / `getExamSubjects` / `getExamGrades`(后 7 个为 P1-2 新增)
|
||||||
- AI Pipeline:`generateAiCreateDraftFromSource` / `generateAiPreviewData` / `regenerateAiQuestionByInstruction`
|
- AI Pipeline:`generateAiCreateDraftFromSource` / `generateAiPreviewData` / `regenerateAiQuestionByInstruction`
|
||||||
|
|
||||||
**依赖关系**:
|
**依赖关系**:
|
||||||
@@ -418,15 +426,15 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
- ❌ P0:`persistAiGeneratedExamDraft` 直接 insert 到 `questions` 表
|
- ❌ P0:`persistAiGeneratedExamDraft` 直接 insert 到 `questions` 表
|
||||||
- ❌ P0:`getExams`/`getExamById` 直查 `classes` 表
|
- ❌ P0:`getExams`/`getExamById` 直查 `classes` 表
|
||||||
- ❌ P1:`getSubjectsAction`/`getGradesAction` 直查 `subjects`/`grades` 表(应属 school 模块)
|
- ❌ P1:`getSubjectsAction`/`getGradesAction` 直查 `subjects`/`grades` 表(应属 school 模块)
|
||||||
- ❌ P1:`actions.ts` 832 行(超 800 建议),多处直接 DB 操作
|
- ✅ P1-2 已修复:~~`actions.ts` 832 行(超 800 建议),多处直接 DB 操作~~ DB 操作已下沉到 data-access,actions.ts 现 766 行
|
||||||
- ⚠️ P1:`ai-pipeline.ts` 912 行(超 800 建议),混合 4 类职责
|
- ⚠️ P1:`ai-pipeline.ts` 912 行(超 800 建议),混合 4 类职责
|
||||||
|
|
||||||
**文件清单**:
|
**文件清单**:
|
||||||
| 文件 | 行数 | 职责 |
|
| 文件 | 行数 | 职责 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `actions.ts` | 832 | 10 个 Server Action(超限) |
|
| `actions.ts` | 766 | 10 个 Server Action(P1-2 已修复,无直接 DB 操作) |
|
||||||
| `ai-pipeline.ts` | 912 | AI 出题管线(超限) |
|
| `ai-pipeline.ts` | 912 | AI 出题管线(超限) |
|
||||||
| `data-access.ts` | 339 | 考试 CRUD |
|
| `data-access.ts` | 524 | 考试 CRUD(含 P1-2 新增 7 个写/查询函数) |
|
||||||
| `types.ts` | 31 | 类型定义 |
|
| `types.ts` | 31 | 类型定义 |
|
||||||
| `hooks/use-exam-preview.ts` | 295 | 预览 Hook |
|
| `hooks/use-exam-preview.ts` | 295 | 预览 Hook |
|
||||||
| `components/*` | 18 文件 | 考试表单/组卷/预览组件 |
|
| `components/*` | 18 文件 | 考试表单/组卷/预览组件 |
|
||||||
@@ -438,8 +446,9 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
**职责**:作业全生命周期(创建/发布/作答/批改/分析)。
|
**职责**:作业全生命周期(创建/发布/作答/批改/分析)。
|
||||||
|
|
||||||
**导出函数**:
|
**导出函数**:
|
||||||
- Actions:`createHomeworkAssignmentAction` / `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction`
|
- 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:`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 以保持向后兼容)
|
- Stats-service:`getTeacherGradeTrends` / `getHomeworkAssignmentAnalytics` / `getStudentDashboardGrades`(从 data-access.ts re-export 以保持向后兼容)
|
||||||
|
|
||||||
**依赖关系**:
|
**依赖关系**:
|
||||||
@@ -451,14 +460,15 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
- ✅ P0 已解决:`getStudentDashboardGrades` 排名计算逻辑迁移至 `stats-service.ts`
|
- ✅ P0 已解决:`getStudentDashboardGrades` 排名计算逻辑迁移至 `stats-service.ts`
|
||||||
- ✅ P0 已解决:`getHomeworkAssignmentAnalytics` 错误率统计逻辑迁移至 `stats-service.ts`
|
- ✅ P0 已解决:`getHomeworkAssignmentAnalytics` 错误率统计逻辑迁移至 `stats-service.ts`
|
||||||
- ❌ P1:5 处直查 `exams` 表
|
- ❌ P1:5 处直查 `exams` 表
|
||||||
- ❌ P1:`actions.ts` 多处直接 DB 操作(`createHomeworkAssignmentAction` 157 行)
|
- ✅ P1-2 已修复:~~`actions.ts` 多处直接 DB 操作(`createHomeworkAssignmentAction` 157 行)~~ DB 操作已下沉到 `data-access-write.ts`,actions.ts 现 239 行
|
||||||
|
|
||||||
**文件清单**:
|
**文件清单**:
|
||||||
| 文件 | 行数 | 职责 |
|
| 文件 | 行数 | 职责 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `data-access.ts` | 596 | 作业 CRUD + 学生视角 + 批改(含 re-export stats 函数) |
|
| `data-access.ts` | 596 | 作业 CRUD + 学生视角 + 批改(含 re-export stats 函数) |
|
||||||
|
| `data-access-write.ts` | 285 | 作业写操作(P1-2 新增,10 个写函数从 actions 下沉) |
|
||||||
| `stats-service.ts` | 346 | 统计分析(教师趋势/作业分析/学生仪表盘成绩) |
|
| `stats-service.ts` | 346 | 统计分析(教师趋势/作业分析/学生仪表盘成绩) |
|
||||||
| `actions.ts` | 387 | 5 个 Server Action |
|
| `actions.ts` | 239 | 5 个 Server Action(P1-2 已修复,无直接 DB 操作) |
|
||||||
| `types.ts` | 186 | 类型定义 |
|
| `types.ts` | 186 | 类型定义 |
|
||||||
| `schema.ts` | 29 | Zod 校验 |
|
| `schema.ts` | 29 | Zod 校验 |
|
||||||
|
|
||||||
@@ -469,23 +479,23 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
**职责**:题库管理(题目 CRUD、知识点关联、题型支持)。
|
**职责**:题库管理(题目 CRUD、知识点关联、题型支持)。
|
||||||
|
|
||||||
**导出函数**:
|
**导出函数**:
|
||||||
- Actions:`getQuestionsAction` / `createQuestionAction` / `updateQuestionAction` / `deleteQuestionAction` / `getKnowledgePointOptionsAction`
|
- Actions:`getQuestionsAction` / `createQuestionAction` / `updateQuestionAction` / `deleteQuestionAction` / `getKnowledgePointOptionsAction`(✅ P1-2 已修复:actions 层不再直接访问 DB,全部下沉到 data-access)
|
||||||
- Data-access:`getQuestions` / `insertQuestionWithRelations`(错放 actions)/ `deleteQuestionRecursive`(错放 actions)
|
- Data-access:`getQuestions` / `createQuestionWithRelations` / `updateQuestionById` / `deleteQuestionByIdRecursive` / `getKnowledgePointOptions`(后 4 个为 P1-2 新增/迁移)
|
||||||
|
|
||||||
**依赖关系**:
|
**依赖关系**:
|
||||||
- 依赖:`shared/*`、`@/auth`、`textbooks`(❌ actions 直查 knowledgePoints/chapters/textbooks)
|
- 依赖:`shared/*`、`@/auth`、`textbooks`(❌ actions 直查 knowledgePoints/chapters/textbooks)
|
||||||
- 被依赖:`exams`(通过类型导入,合理)、`textbooks`(UI 组合,合理)
|
- 被依赖:`exams`(通过类型导入,合理)、`textbooks`(UI 组合,合理)
|
||||||
|
|
||||||
**已知问题**:
|
**已知问题**:
|
||||||
- ❌ P1:写操作函数错放在 `actions.ts`(`insertQuestionWithRelations` / `deleteQuestionRecursive`)
|
- ✅ P1-2 已修复:~~写操作函数错放在 `actions.ts`(`insertQuestionWithRelations` / `deleteQuestionRecursive`)~~ 已下沉到 data-access(`createQuestionWithRelations` / `updateQuestionById` / `deleteQuestionByIdRecursive` / `getKnowledgePointOptions`)
|
||||||
- ❌ P1:`getKnowledgePointOptionsAction` 直查 textbooks 模块表
|
- ❌ P1:`getKnowledgePointOptionsAction` 直查 textbooks 模块表
|
||||||
- ⚠️ P2:`data-access.ts` 仅 129 行,写操作缺失
|
- ✅ P2 已解决:~~`data-access.ts` 仅 129 行,写操作缺失~~ P1-2 后 data-access.ts 扩充至 299 行
|
||||||
|
|
||||||
**文件清单**:
|
**文件清单**:
|
||||||
| 文件 | 行数 | 职责 |
|
| 文件 | 行数 | 职责 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `actions.ts` | 294 | 5 个 Server Action(含错放的 data-access 函数) |
|
| `actions.ts` | 177 | 5 个 Server Action(P1-2 已修复,无直接 DB 操作) |
|
||||||
| `data-access.ts` | 129 | 仅读查询 |
|
| `data-access.ts` | 299 | 题目 CRUD + 知识点选项(含 P1-2 新增 4 个写/查询函数) |
|
||||||
| `schema.ts` | 18 | Zod 校验 |
|
| `schema.ts` | 18 | Zod 校验 |
|
||||||
| `types.ts` | 34 | 类型定义 |
|
| `types.ts` | 34 | 类型定义 |
|
||||||
|
|
||||||
@@ -820,23 +830,23 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
|||||||
**职责**:公告 CRUD + 发布/归档。
|
**职责**:公告 CRUD + 发布/归档。
|
||||||
|
|
||||||
**导出函数**:
|
**导出函数**:
|
||||||
- Actions:`getAnnouncementsAction` / `createAnnouncementAction` / `updateAnnouncementAction` / `deleteAnnouncementAction` / `publishAnnouncementAction` / `archiveAnnouncementAction`
|
- Actions:`getAnnouncementsAction` / `createAnnouncementAction` / `updateAnnouncementAction` / `deleteAnnouncementAction` / `publishAnnouncementAction` / `archiveAnnouncementAction`(✅ P1-2 已修复:actions 层不再直接访问 DB,全部下沉到 data-access)
|
||||||
- Data-access:`getAnnouncements` / `getAnnouncementById`
|
- Data-access:`getAnnouncements` / `getAnnouncementById` / `insertAnnouncement` / `updateAnnouncementById` / `deleteAnnouncementById` / `publishAnnouncementById` / `archiveAnnouncementById`(后 5 个为 P1-2 新增)
|
||||||
|
|
||||||
**依赖关系**:
|
**依赖关系**:
|
||||||
- 依赖:`shared/*`、`@/auth`、`school`(合理,获取年级列表)
|
- 依赖:`shared/*`、`@/auth`、`school`(合理,获取年级列表)
|
||||||
- 被依赖:无
|
- 被依赖:无
|
||||||
|
|
||||||
**已知问题**:
|
**已知问题**:
|
||||||
- ❌ P1:所有写操作直接在 actions 层 `db.insert/update/delete`,未下沉到 data-access
|
- ✅ P1-2 已修复:~~所有写操作直接在 actions 层 `db.insert/update/delete`,未下沉到 data-access~~ 写操作已下沉到 data-access(5 个新函数)
|
||||||
- ⚠️ P2:死代码 `void wasPublished`
|
- ⚠️ P2:死代码 `void wasPublished`
|
||||||
- ⚠️ P2:`getAnnouncementsAction` 使用 `requireAuth()` 而非 `requirePermission(ANNOUNCEMENT_READ)`
|
- ⚠️ P2:`getAnnouncementsAction` 使用 `requireAuth()` 而非 `requirePermission(ANNOUNCEMENT_READ)`
|
||||||
|
|
||||||
**文件清单**:
|
**文件清单**:
|
||||||
| 文件 | 行数 | 职责 |
|
| 文件 | 行数 | 职责 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `actions.ts` | 242 | 6 个 Server Action(含直接 DB 写) |
|
| `actions.ts` | 231 | 6 个 Server Action(P1-2 已修复,无直接 DB 操作) |
|
||||||
| `data-access.ts` | 120 | 仅 2 个只读函数 |
|
| `data-access.ts` | 186 | 公告 CRUD + 发布/归档(含 P1-2 新增 5 个写函数) |
|
||||||
| `schema.ts` | - | Zod 校验 |
|
| `schema.ts` | - | Zod 校验 |
|
||||||
| `types.ts` | - | 类型定义 |
|
| `types.ts` | - | 类型定义 |
|
||||||
|
|
||||||
@@ -1195,18 +1205,20 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
|
|||||||
- `textbooks/data-access`:`getKnowledgePointOptions`
|
- `textbooks/data-access`:`getKnowledgePointOptions`
|
||||||
- `questions/data-access`:`insertQuestionWithRelations` / `deleteQuestionRecursive`
|
- `questions/data-access`:`insertQuestionWithRelations` / `deleteQuestionRecursive`
|
||||||
|
|
||||||
### P1-2:actions 层混入数据访问逻辑
|
### P1-2:actions 层混入数据访问逻辑 ✅ 已修复
|
||||||
|
|
||||||
| 模块 | 问题 Action | 违规 |
|
**已完成修复**(2026-06-17,commit 84d6636):4 个模块的 actions 层 DB 操作全部下沉到 data-access:
|
||||||
|------|------------|------|
|
|
||||||
| exams | `updateExamAction` / `deleteExamAction` / `duplicateExamAction` / `getExamPreviewAction` | 直接 db.query + db.insert/update/delete |
|
|
||||||
| homework | `createHomeworkAssignmentAction`(157 行)/ `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction` | 直接 DB 操作 |
|
|
||||||
| questions | `createQuestionAction` / `updateQuestionAction` / `deleteQuestionAction` | 内联 db.transaction |
|
|
||||||
| announcements | 所有写操作 Action | 直接 db.insert/update/delete |
|
|
||||||
| users | `updateUserProfileAction` | 直接 db.update |
|
|
||||||
| scheduling | `applyAutoScheduleAction` / `autoScheduleAction` | 直接 db.transaction + db.select |
|
|
||||||
|
|
||||||
**解耦建议**:actions 层仅做"权限校验 → 解析 → 调用 data-access → revalidatePath → 返回",所有 DB 操作下沉到 data-access。
|
| 模块 | 问题 Action | 修复内容 |
|
||||||
|
|------|------------|---------|
|
||||||
|
| exams | `updateExamAction` / `deleteExamAction` / `duplicateExamAction` / `getExamPreviewAction` / `getSubjectsAction` / `getGradesAction` | ✅ 新增 7 个 data-access 函数(getExamCreatorId/updateExamWithQuestions/deleteExamById/duplicateExam/getExamPreview/getExamSubjects/getExamGrades),actions.ts 831→766 行,data-access.ts 374→524 行 |
|
||||||
|
| 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→177 行,data-access.ts 138→299 行 |
|
||||||
|
| announcements | 所有写操作 Action | ✅ 新增 5 个 data-access 函数(insertAnnouncement/updateAnnouncementById/deleteAnnouncementById/publishAnnouncementById/archiveAnnouncementById),actions.ts 242→231 行,data-access.ts 120→186 行 |
|
||||||
|
|
||||||
|
**剩余未修复模块**(不在本次 P1-2 范围):
|
||||||
|
- users:`updateUserProfileAction` 直接 db.update
|
||||||
|
- scheduling:`applyAutoScheduleAction` / `autoScheduleAction` 直接 db.transaction + db.select
|
||||||
|
|
||||||
### P1-3:auth.ts 混合 5 类职责 ✅ 已完成
|
### P1-3:auth.ts 混合 5 类职责 ✅ 已完成
|
||||||
|
|
||||||
@@ -1250,8 +1262,8 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
|
|||||||
| 序号 | 问题 | 模块 |
|
| 序号 | 问题 | 模块 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| P2-1 | `exams/ai-pipeline.ts` 912 行,混合 4 类职责 | exams |
|
| P2-1 | `exams/ai-pipeline.ts` 912 行,混合 4 类职责 | exams |
|
||||||
| P2-2 | `exams/actions.ts` 832 行(超 800 建议) | exams |
|
| ~~P2-2~~ | ~~`exams/actions.ts` 832 行(超 800 建议)~~ ✅ 已修复(P1-2 后降至 766 行) | exams |
|
||||||
| P2-3 | `shared/lib/ai.ts` 218 行,混合 5 类职责 | shared |
|
| ~~P2-3~~ | ~~`shared/lib/ai.ts` 218 行,混合 5 类职责~~ ✅ 已修复(P2-2 已拆分为 `ai/` 目录) | shared |
|
||||||
| P2-4 | `onboarding-gate.tsx` 业务逻辑泄漏到 shared | shared |
|
| P2-4 | `onboarding-gate.tsx` 业务逻辑泄漏到 shared | shared |
|
||||||
| P2-5 | `global-search.tsx` 业务类型硬编码在 shared | shared |
|
| P2-5 | `global-search.tsx` 业务类型硬编码在 shared | shared |
|
||||||
| P2-6 | `proxy.ts` 硬编码权限字符串,未复用 Permissions 常量 | proxy |
|
| P2-6 | `proxy.ts` 硬编码权限字符串,未复用 Permissions 常量 | proxy |
|
||||||
@@ -1284,7 +1296,7 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
|
|||||||
7. 集成 proctoring/exam-mode-config 到考试表单
|
7. 集成 proctoring/exam-mode-config 到考试表单
|
||||||
|
|
||||||
### 短期执行(P1)
|
### 短期执行(P1)
|
||||||
8. actions 层移除直接 DB 操作(exams/homework/questions/announcements/users/scheduling)
|
8. ~~actions 层移除直接 DB 操作(exams/homework/questions/announcements/users/scheduling)~~ ✅ 部分完成(exams/homework/questions/announcements 已修复,users/scheduling 待处理)
|
||||||
9. ~~拆分 `auth.ts`~~ ✅ 已完成(4 个辅助函数组迁移至 shared/lib,auth.ts 保留 NextAuth 配置)
|
9. ~~拆分 `auth.ts`~~ ✅ 已完成(4 个辅助函数组迁移至 shared/lib,auth.ts 保留 NextAuth 配置)
|
||||||
10. ~~拆分 `users/import-export.ts`~~ ✅ 已完成(拆为 import-export.ts 177行 + user-service.ts 96行 + class-registration.ts 30行,班级注册改为调用 classes/data-access)
|
10. ~~拆分 `users/import-export.ts`~~ ✅ 已完成(拆为 import-export.ts 177行 + user-service.ts 96行 + class-registration.ts 30行,班级注册改为调用 classes/data-access)
|
||||||
11. 消除 notifications → messaging 反向依赖
|
11. 消除 notifications → messaging 反向依赖
|
||||||
@@ -1295,8 +1307,9 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
|
|||||||
14. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
|
14. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
|
||||||
15. `schema.ts` 按业务域分节
|
15. `schema.ts` 按业务域分节
|
||||||
16. 拆分 `exams/ai-pipeline.ts`
|
16. 拆分 `exams/ai-pipeline.ts`
|
||||||
17. shared 层业务逻辑下沉到 modules 层
|
17. ~~拆分 `shared/lib/ai.ts`~~ ✅ 已完成(P2-2,commit 6588f74,拆分为 `ai/` 目录 6 个文件,原 ai.ts 保留为重导出)
|
||||||
18. 代码质量问题逐项修复
|
18. shared 层业务逻辑下沉到 modules 层
|
||||||
|
19. 代码质量问题逐项修复
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1422,9 +1435,12 @@ logLoginEvent(params: LogLoginEventParams): Promise<void>
|
|||||||
// shared/lib/change-logger.ts
|
// shared/lib/change-logger.ts
|
||||||
logDataChange(params: LogDataChangeParams): Promise<void>
|
logDataChange(params: LogDataChangeParams): Promise<void>
|
||||||
|
|
||||||
// shared/lib/ai.ts
|
// shared/lib/ai/ (P2-2 已拆分,原 ai.ts 保留为重导出)
|
||||||
|
// ai/client.ts
|
||||||
createAiChatCompletion(input: AiChatRequest): Promise<{ content, usage }>
|
createAiChatCompletion(input: AiChatRequest): Promise<{ content, usage }>
|
||||||
|
// ai/payload-parser.ts
|
||||||
parseAiChatPayload(body: unknown): AiChatRequest
|
parseAiChatPayload(body: unknown): AiChatRequest
|
||||||
|
// ai/api-key-crypto.ts
|
||||||
encryptAiApiKey(value: string): string
|
encryptAiApiKey(value: string): string
|
||||||
decryptAiApiKey(value: string): string
|
decryptAiApiKey(value: string): string
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"generatedAt": "2026-06-17",
|
"generatedAt": "2026-06-17",
|
||||||
"formatVersion": "1.1",
|
"formatVersion": "1.1",
|
||||||
"rule": "每次文件修改后须同步更新本文件",
|
"rule": "每次文件修改后须同步更新本文件",
|
||||||
"lastUpdate": "补充架构概览、模块依赖图、已知问题、数据库表清单;补全 EXAM_PROCTOR 权限与 proctoring 依赖矩阵"
|
"lastUpdate": "P1-2 已修复:exams/homework/questions/announcements actions 层 DB 操作下沉到 data-access;P2-2 已修复:ai.ts 拆分为 ai/ 目录"
|
||||||
},
|
},
|
||||||
"architectureOverview": {
|
"architectureOverview": {
|
||||||
"layers": [
|
"layers": [
|
||||||
@@ -354,7 +354,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "parseAiChatPayload",
|
"name": "parseAiChatPayload",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/payload-parser.ts",
|
||||||
"signature": "parseAiChatPayload(body: unknown): AiChatRequest",
|
"signature": "parseAiChatPayload(body: unknown): AiChatRequest",
|
||||||
"purpose": "解析并校验AI聊天请求负载",
|
"purpose": "解析并校验AI聊天请求负载",
|
||||||
"deps": [
|
"deps": [
|
||||||
@@ -366,7 +366,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "encryptAiApiKey",
|
"name": "encryptAiApiKey",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/api-key-crypto.ts",
|
||||||
"signature": "encryptAiApiKey(value: string): string",
|
"signature": "encryptAiApiKey(value: string): string",
|
||||||
"purpose": "AES加密AI Provider API Key",
|
"purpose": "AES加密AI Provider API Key",
|
||||||
"deps": [
|
"deps": [
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "decryptAiApiKey",
|
"name": "decryptAiApiKey",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/api-key-crypto.ts",
|
||||||
"signature": "decryptAiApiKey(value: string): string",
|
"signature": "decryptAiApiKey(value: string): string",
|
||||||
"purpose": "AES解密AI Provider API Key",
|
"purpose": "AES解密AI Provider API Key",
|
||||||
"deps": [
|
"deps": [
|
||||||
@@ -386,12 +386,12 @@
|
|||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"settings/actions.ts",
|
"settings/actions.ts",
|
||||||
"ai.ts内部"
|
"ai/api-key-crypto.ts内部"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "testAiProviderConfig",
|
"name": "testAiProviderConfig",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/client.ts",
|
||||||
"signature": "testAiProviderConfig(input: { apiKey: string; baseUrl?: string; model: string }): Promise<boolean>",
|
"signature": "testAiProviderConfig(input: { apiKey: string; baseUrl?: string; model: string }): Promise<boolean>",
|
||||||
"purpose": "测试AI Provider连通性(直接配置)",
|
"purpose": "测试AI Provider连通性(直接配置)",
|
||||||
"deps": [
|
"deps": [
|
||||||
@@ -403,7 +403,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "testAiProviderById",
|
"name": "testAiProviderById",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/client.ts",
|
||||||
"signature": "testAiProviderById(providerId: string, overrides?: { baseUrl?: string; model?: string }): Promise<boolean>",
|
"signature": "testAiProviderById(providerId: string, overrides?: { baseUrl?: string; model?: string }): Promise<boolean>",
|
||||||
"purpose": "测试AI Provider连通性(按ID)",
|
"purpose": "测试AI Provider连通性(按ID)",
|
||||||
"deps": [
|
"deps": [
|
||||||
@@ -416,12 +416,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createAiChatCompletion",
|
"name": "createAiChatCompletion",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/client.ts",
|
||||||
"signature": "createAiChatCompletion(input: AiChatRequest): Promise<{ content: string; usage: unknown }>",
|
"signature": "createAiChatCompletion(input: AiChatRequest): Promise<{ content: string; usage: unknown }>",
|
||||||
"purpose": "调用AI模型生成聊天回复",
|
"purpose": "调用AI模型生成聊天回复",
|
||||||
"deps": [
|
"deps": [
|
||||||
"openai",
|
"openai",
|
||||||
"shared/db"
|
"shared/db",
|
||||||
|
"ai/provider-config.ts"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exams/ai-pipeline.ts",
|
"exams/ai-pipeline.ts",
|
||||||
@@ -430,7 +431,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getAiErrorMessage",
|
"name": "getAiErrorMessage",
|
||||||
"file": "lib/ai.ts",
|
"file": "lib/ai/errors.ts",
|
||||||
"signature": "getAiErrorMessage(v: unknown): string",
|
"signature": "getAiErrorMessage(v: unknown): string",
|
||||||
"purpose": "从AI错误中提取可读消息",
|
"purpose": "从AI错误中提取可读消息",
|
||||||
"deps": [],
|
"deps": [],
|
||||||
@@ -2045,7 +2046,8 @@
|
|||||||
"purpose": "更新考试(含资源归属校验)",
|
"purpose": "更新考试(含资源归属校验)",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getExamCreatorId",
|
||||||
|
"data-access.updateExamWithQuestions"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exam-form.tsx"
|
"exam-form.tsx"
|
||||||
@@ -2058,7 +2060,8 @@
|
|||||||
"purpose": "删除考试(含资源归属校验)",
|
"purpose": "删除考试(含资源归属校验)",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getExamCreatorId",
|
||||||
|
"data-access.deleteExamById"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exam-actions.tsx"
|
"exam-actions.tsx"
|
||||||
@@ -2071,7 +2074,8 @@
|
|||||||
"purpose": "复制考试",
|
"purpose": "复制考试",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getExamCreatorId",
|
||||||
|
"data-access.duplicateExam"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exam-actions.tsx"
|
"exam-actions.tsx"
|
||||||
@@ -2084,7 +2088,7 @@
|
|||||||
"purpose": "获取考试预览数据",
|
"purpose": "获取考试预览数据",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getExamPreview"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exam-viewer.tsx"
|
"exam-viewer.tsx"
|
||||||
@@ -2097,7 +2101,7 @@
|
|||||||
"purpose": "获取科目列表",
|
"purpose": "获取科目列表",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getExamSubjects"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exam-form.tsx"
|
"exam-form.tsx"
|
||||||
@@ -2110,7 +2114,7 @@
|
|||||||
"purpose": "获取年级列表",
|
"purpose": "获取年级列表",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getExamGrades"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"exam-form.tsx"
|
"exam-form.tsx"
|
||||||
@@ -2183,6 +2187,64 @@
|
|||||||
"exams/data-access内部"
|
"exams/data-access内部"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getExamCreatorId",
|
||||||
|
"signature": "(examId: string) => Promise<string | null>",
|
||||||
|
"purpose": "获取考试创建者ID(用于权限校验)",
|
||||||
|
"usedBy": [
|
||||||
|
"updateExamAction",
|
||||||
|
"deleteExamAction",
|
||||||
|
"duplicateExamAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "updateExamWithQuestions",
|
||||||
|
"signature": "(input: { examId, title, subjectId, gradeId, difficulty, totalScore, durationMin, scheduledAt?, description?, structure }) => Promise<void>",
|
||||||
|
"purpose": "更新考试及题目关联(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"updateExamAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "deleteExamById",
|
||||||
|
"signature": "(examId: string) => Promise<void>",
|
||||||
|
"purpose": "按ID删除考试(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"deleteExamAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "duplicateExam",
|
||||||
|
"signature": "(examId: string, creatorId: string) => Promise<{ newExamId: string }>",
|
||||||
|
"purpose": "复制考试(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"duplicateExamAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getExamPreview",
|
||||||
|
"signature": "(examId: string) => Promise<{ structure: unknown; questions: Array<{ id: string }> } | null>",
|
||||||
|
"purpose": "获取考试预览数据(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"getExamPreviewAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getExamSubjects",
|
||||||
|
"signature": "() => Promise<Array<{ id: string; name: string }>>",
|
||||||
|
"purpose": "获取科目列表(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"getSubjectsAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getExamGrades",
|
||||||
|
"signature": "() => Promise<Array<{ id: string; name: string }>>",
|
||||||
|
"purpose": "获取年级列表(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"getGradesAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "GetExamsParams",
|
"name": "GetExamsParams",
|
||||||
"type": "type",
|
"type": "type",
|
||||||
@@ -2585,7 +2647,7 @@
|
|||||||
"purpose": "从已有考试创建作业",
|
"purpose": "从已有考试创建作业",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db",
|
"data-access-write.createHomeworkAssignment",
|
||||||
"exams/data-access.getExams"
|
"exams/data-access.getExams"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
@@ -2599,7 +2661,7 @@
|
|||||||
"purpose": "学生开始作答",
|
"purpose": "学生开始作答",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access-write.startHomeworkSubmission"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"homework-take-view.tsx"
|
"homework-take-view.tsx"
|
||||||
@@ -2612,7 +2674,7 @@
|
|||||||
"purpose": "保存单题答案",
|
"purpose": "保存单题答案",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access-write.saveHomeworkAnswer"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"homework-take-view.tsx"
|
"homework-take-view.tsx"
|
||||||
@@ -2625,7 +2687,7 @@
|
|||||||
"purpose": "提交作业",
|
"purpose": "提交作业",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access-write.submitHomework"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"homework-take-view.tsx"
|
"homework-take-view.tsx"
|
||||||
@@ -2638,7 +2700,7 @@
|
|||||||
"purpose": "教师批改作业",
|
"purpose": "教师批改作业",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access-write.gradeHomeworkSubmission"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"homework-grading-view.tsx"
|
"homework-grading-view.tsx"
|
||||||
@@ -2708,6 +2770,53 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"dataAccessWrite": [
|
||||||
|
{
|
||||||
|
"name": "createHomeworkAssignment",
|
||||||
|
"file": "data-access-write.ts",
|
||||||
|
"signature": "(input: { examId, classId, title, description, dueAt, allowLate?, lateDueAt?, maxAttempts? }) => Promise<{ assignmentId: string }>",
|
||||||
|
"purpose": "创建作业(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"createHomeworkAssignmentAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "startHomeworkSubmission",
|
||||||
|
"file": "data-access-write.ts",
|
||||||
|
"signature": "(assignmentId: string, studentId: string) => Promise<{ submissionId: string }>",
|
||||||
|
"purpose": "学生开始作答(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"startHomeworkSubmissionAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "saveHomeworkAnswer",
|
||||||
|
"file": "data-access-write.ts",
|
||||||
|
"signature": "(submissionId: string, questionId: string, answer: string) => Promise<void>",
|
||||||
|
"purpose": "保存单题答案(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"saveHomeworkAnswerAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "submitHomework",
|
||||||
|
"file": "data-access-write.ts",
|
||||||
|
"signature": "(submissionId: string, studentId: string) => Promise<void>",
|
||||||
|
"purpose": "提交作业(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"submitHomeworkAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gradeHomeworkSubmission",
|
||||||
|
"file": "data-access-write.ts",
|
||||||
|
"signature": "(submissionId: string, grades: Array<{ answerId: string; isCorrect: boolean; score: number; feedback?: string }>) => Promise<void>",
|
||||||
|
"purpose": "教师批改作业(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"gradeHomeworkSubmissionAction"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"statsService": [
|
"statsService": [
|
||||||
{
|
{
|
||||||
"name": "getTeacherGradeTrends",
|
"name": "getTeacherGradeTrends",
|
||||||
@@ -3013,7 +3122,7 @@
|
|||||||
"purpose": "创建题目(含嵌套)",
|
"purpose": "创建题目(含嵌套)",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.createQuestionWithRelations"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"create-question-dialog.tsx"
|
"create-question-dialog.tsx"
|
||||||
@@ -3026,7 +3135,7 @@
|
|||||||
"purpose": "更新题目",
|
"purpose": "更新题目",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.updateQuestionById"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"question-actions.tsx"
|
"question-actions.tsx"
|
||||||
@@ -3039,7 +3148,7 @@
|
|||||||
"purpose": "删除题目",
|
"purpose": "删除题目",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.deleteQuestionByIdRecursive"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"question-actions.tsx"
|
"question-actions.tsx"
|
||||||
@@ -3065,7 +3174,7 @@
|
|||||||
"purpose": "获取知识点选项",
|
"purpose": "获取知识点选项",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.getKnowledgePointOptions"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"create-question-dialog.tsx"
|
"create-question-dialog.tsx"
|
||||||
@@ -3091,6 +3200,38 @@
|
|||||||
"dashboard/data-access.getAdminDashboardData"
|
"dashboard/data-access.getAdminDashboardData"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "createQuestionWithRelations",
|
||||||
|
"signature": "(input: CreateQuestionInput) => Promise<{ questionId: string }>",
|
||||||
|
"purpose": "创建题目(含嵌套子题目、知识点关联)(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"createNestedQuestion"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "updateQuestionById",
|
||||||
|
"signature": "(questionId: string, input: Partial<CreateQuestionInput>) => Promise<void>",
|
||||||
|
"purpose": "按ID更新题目(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"updateQuestionAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "deleteQuestionByIdRecursive",
|
||||||
|
"signature": "(questionId: string) => Promise<void>",
|
||||||
|
"purpose": "递归删除题目(含子题目、知识点关联)(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"deleteQuestionAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getKnowledgePointOptions",
|
||||||
|
"signature": "() => Promise<KnowledgePointOption[]>",
|
||||||
|
"purpose": "获取知识点选项(含章节/教材信息)(P1-2 新增,从 actions 下沉)",
|
||||||
|
"usedBy": [
|
||||||
|
"getKnowledgePointOptionsAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "GetQuestionsParams",
|
"name": "GetQuestionsParams",
|
||||||
"type": "type",
|
"type": "type",
|
||||||
@@ -5351,7 +5492,7 @@
|
|||||||
"purpose": "创建公告(草稿/已发布)",
|
"purpose": "创建公告(草稿/已发布)",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.insertAnnouncement"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"announcement-form.tsx"
|
"announcement-form.tsx"
|
||||||
@@ -5364,7 +5505,7 @@
|
|||||||
"purpose": "更新公告",
|
"purpose": "更新公告",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.updateAnnouncementById"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"announcement-form.tsx"
|
"announcement-form.tsx"
|
||||||
@@ -5377,7 +5518,7 @@
|
|||||||
"purpose": "删除公告",
|
"purpose": "删除公告",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.deleteAnnouncementById"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"announcement-detail.tsx"
|
"announcement-detail.tsx"
|
||||||
@@ -5390,7 +5531,7 @@
|
|||||||
"purpose": "发布公告",
|
"purpose": "发布公告",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.publishAnnouncementById"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"announcement-detail.tsx"
|
"announcement-detail.tsx"
|
||||||
@@ -5403,7 +5544,7 @@
|
|||||||
"purpose": "归档公告",
|
"purpose": "归档公告",
|
||||||
"deps": [
|
"deps": [
|
||||||
"requirePermission",
|
"requirePermission",
|
||||||
"shared/db"
|
"data-access.archiveAnnouncementById"
|
||||||
],
|
],
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"announcement-detail.tsx"
|
"announcement-detail.tsx"
|
||||||
@@ -5448,6 +5589,71 @@
|
|||||||
"usedBy": [
|
"usedBy": [
|
||||||
"admin/announcements/[id]/page.tsx"
|
"admin/announcements/[id]/page.tsx"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "insertAnnouncement",
|
||||||
|
"signature": "(input: { title, content, type?, status?, targetGradeId?, targetClassId?, publishedAt?, authorId }) => Promise<{ announcementId: string }>",
|
||||||
|
"file": "data-access.ts",
|
||||||
|
"purpose": "插入公告(P1-2 新增,从 actions 下沉)",
|
||||||
|
"deps": [
|
||||||
|
"shared.db",
|
||||||
|
"shared.db.schema.announcements"
|
||||||
|
],
|
||||||
|
"usedBy": [
|
||||||
|
"createAnnouncementAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "updateAnnouncementById",
|
||||||
|
"signature": "(id: string, input: Partial<{ title, content, type?, status?, targetGradeId?, targetClassId?, publishedAt? }>) => Promise<void>",
|
||||||
|
"file": "data-access.ts",
|
||||||
|
"purpose": "按ID更新公告(P1-2 新增,从 actions 下沉)",
|
||||||
|
"deps": [
|
||||||
|
"shared.db",
|
||||||
|
"shared.db.schema.announcements"
|
||||||
|
],
|
||||||
|
"usedBy": [
|
||||||
|
"updateAnnouncementAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "deleteAnnouncementById",
|
||||||
|
"signature": "(id: string) => Promise<void>",
|
||||||
|
"file": "data-access.ts",
|
||||||
|
"purpose": "按ID删除公告(P1-2 新增,从 actions 下沉)",
|
||||||
|
"deps": [
|
||||||
|
"shared.db",
|
||||||
|
"shared.db.schema.announcements"
|
||||||
|
],
|
||||||
|
"usedBy": [
|
||||||
|
"deleteAnnouncementAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "publishAnnouncementById",
|
||||||
|
"signature": "(id: string) => Promise<void>",
|
||||||
|
"file": "data-access.ts",
|
||||||
|
"purpose": "发布公告(P1-2 新增,从 actions 下沉)",
|
||||||
|
"deps": [
|
||||||
|
"shared.db",
|
||||||
|
"shared.db.schema.announcements"
|
||||||
|
],
|
||||||
|
"usedBy": [
|
||||||
|
"publishAnnouncementAction"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "archiveAnnouncementById",
|
||||||
|
"signature": "(id: string) => Promise<void>",
|
||||||
|
"file": "data-access.ts",
|
||||||
|
"purpose": "归档公告(P1-2 新增,从 actions 下沉)",
|
||||||
|
"deps": [
|
||||||
|
"shared.db",
|
||||||
|
"shared.db.schema.announcements"
|
||||||
|
],
|
||||||
|
"usedBy": [
|
||||||
|
"archiveAnnouncementAction"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": [
|
||||||
@@ -11072,7 +11278,10 @@
|
|||||||
"title": "actions 层混入数据访问逻辑",
|
"title": "actions 层混入数据访问逻辑",
|
||||||
"file": "src/modules/{exams,homework,questions,announcements}/actions.ts",
|
"file": "src/modules/{exams,homework,questions,announcements}/actions.ts",
|
||||||
"problem": "actions.ts 中存在直接 db.insert/update/delete,应通过 data-access 层",
|
"problem": "actions.ts 中存在直接 db.insert/update/delete,应通过 data-access 层",
|
||||||
"suggestion": "将 DB 操作下沉到 data-access 层"
|
"suggestion": "将 DB 操作下沉到 data-access 层",
|
||||||
|
"status": "resolved",
|
||||||
|
"resolvedAt": "2026-06-17",
|
||||||
|
"resolution": "4 个模块的 actions 层 DB 操作全部下沉到 data-access:exams 新增 7 个 data-access 函数(actions.ts 831→766 行,data-access.ts 374→524 行);homework 新建 data-access-write.ts(285 行,10 个写函数,actions.ts 387→239 行);questions 新增 4 个 data-access 函数(actions.ts 294→177 行,data-access.ts 138→299 行);announcements 新增 5 个 data-access 函数(actions.ts 242→231 行,data-access.ts 120→186 行)。users/scheduling 待后续处理"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "P1-3",
|
"id": "P1-3",
|
||||||
@@ -11108,6 +11317,18 @@
|
|||||||
"lines": 1111,
|
"lines": 1111,
|
||||||
"problem": "所有表定义混合在单文件,虽可接受但需分节",
|
"problem": "所有表定义混合在单文件,虽可接受但需分节",
|
||||||
"suggestion": "按业务域分节(加注释分隔)或拆分为多文件"
|
"suggestion": "按业务域分节(加注释分隔)或拆分为多文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "P2-2",
|
||||||
|
"severity": "P2",
|
||||||
|
"title": "ai.ts 混合 5 类职责(218 行)",
|
||||||
|
"file": "src/shared/lib/ai.ts",
|
||||||
|
"lines": 218,
|
||||||
|
"problem": "AI 调用 + Provider 配置 + API Key 加密 + 错误格式化 + 负载解析混合在单文件",
|
||||||
|
"suggestion": "按职责拆分为 ai/ 目录多文件",
|
||||||
|
"status": "resolved",
|
||||||
|
"resolvedAt": "2026-06-17",
|
||||||
|
"resolution": "已拆分为 src/shared/lib/ai/ 目录:payload-parser.ts(96 行,请求负载解析) + api-key-crypto.ts(34 行,API Key 加密/解密) + provider-config.ts(66 行,Provider 配置查询) + client.ts(67 行,AI 客户端创建与调用) + errors.ts(9 行,错误格式化) + index.ts(7 行,聚合导出)。原 ai.ts 保留为向后兼容的重导出文件(12 行)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"routes": {
|
"routes": {
|
||||||
|
|||||||
@@ -281,7 +281,7 @@
|
|||||||
| 序号 | 问题 | 说明 |
|
| 序号 | 问题 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 8 | 跨模块直接 DB 查询普遍 | classes(8+)/classEnrollments(6+)/users(6+)/subjects(6+)/exams(5+) 被跨模块直接访问 |
|
| 8 | 跨模块直接 DB 查询普遍 | classes(8+)/classEnrollments(6+)/users(6+)/subjects(6+)/exams(5+) 被跨模块直接访问 |
|
||||||
| 9 | actions 层混入数据访问 | exams/homework/questions/announcements 的 actions.ts 直接 db.insert/update/delete |
|
| ~~9~~ | ~~actions 层混入数据访问~~ ✅ 已修复 | ~~exams/homework/questions/announcements 的 actions.ts 直接 db.insert/update/delete~~ P1-2 已修复(2026-06-17,commit 84d6636):4 个模块 DB 操作全部下沉到 data-access,users/scheduling 待处理 |
|
||||||
| 10 | auth.ts 混合 5 类职责 | NextAuth 配置 + 密码安全 DB + 角色规范化 + IP 解析 + 回调函数 |
|
| 10 | auth.ts 混合 5 类职责 | NextAuth 配置 + 密码安全 DB + 角色规范化 + IP 解析 + 回调函数 |
|
||||||
| 11 | users/import-export.ts 四重职责 | 导入解析 + 导出 + 用户创建 + 班级注册(跨模块写) |
|
| 11 | users/import-export.ts 四重职责 | 导入解析 + 导出 + 用户创建 + 班级注册(跨模块写) |
|
||||||
| 12 | proctoring 死代码 | exam-mode-config.tsx 未集成到考试表单 |
|
| 12 | proctoring 死代码 | exam-mode-config.tsx 未集成到考试表单 |
|
||||||
@@ -310,11 +310,15 @@
|
|||||||
|
|
||||||
**短期执行(P1):**
|
**短期执行(P1):**
|
||||||
6. 统一 classSchedule 写入口到 scheduling 模块
|
6. 统一 classSchedule 写入口到 scheduling 模块
|
||||||
7. actions 层移除直接 DB 操作
|
7. ~~actions 层移除直接 DB 操作~~ ✅ 部分完成(P1-2 已修复 exams/homework/questions/announcements,users/scheduling 待处理)
|
||||||
8. 拆分 auth.ts
|
8. 拆分 auth.ts
|
||||||
9. 集成 proctoring/exam-mode-config 到考试表单
|
9. 集成 proctoring/exam-mode-config 到考试表单
|
||||||
10. 拆分 users/import-export.ts
|
10. 拆分 users/import-export.ts
|
||||||
|
|
||||||
|
**中期执行(P2):**
|
||||||
|
11. ~~拆分 `shared/lib/ai.ts`~~ ✅ 已完成(P2-2,commit 6588f74,拆分为 `ai/` 目录 6 个文件,原 ai.ts 保留为重导出)
|
||||||
|
12. schema.ts 按业务域分节
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 五、优先补齐路线图
|
## 五、优先补齐路线图
|
||||||
|
|||||||
@@ -72,9 +72,17 @@ shared/lib/{audit-logger, change-logger, auth-guard}
|
|||||||
| `subjects` | 6+ | school | exams, homework, questions |
|
| `subjects` | 6+ | school | exams, homework, questions |
|
||||||
| `exams` | 5+ | exams | homework, grades, dashboard |
|
| `exams` | 5+ | exams | homework, grades, dashboard |
|
||||||
|
|
||||||
### 7. actions 层混入数据访问逻辑
|
### 7. actions 层混入数据访问逻辑 ✅ 已修复
|
||||||
|
|
||||||
exams/homework/questions/announcements 的 actions.ts 中存在直接 `db.insert/update/delete`,应该通过 data-access 层。
|
~~exams/homework/questions/announcements 的 actions.ts 中存在直接 `db.insert/update/delete`,应该通过 data-access 层。~~
|
||||||
|
|
||||||
|
**已完成修复**(2026-06-17,commit 84d6636):4 个模块的 actions 层 DB 操作全部下沉到 data-access:
|
||||||
|
- exams:新增 7 个 data-access 函数,actions.ts 831→766 行,data-access.ts 374→524 行
|
||||||
|
- homework:新建 data-access-write.ts(285 行,10 个写函数),actions.ts 387→239 行
|
||||||
|
- questions:新增 4 个 data-access 函数,actions.ts 294→177 行,data-access.ts 138→299 行
|
||||||
|
- announcements:新增 5 个 data-access 函数,actions.ts 242→231 行,data-access.ts 120→186 行
|
||||||
|
|
||||||
|
剩余未修复:users(updateUserProfileAction)、scheduling(applyAutoScheduleAction/autoScheduleAction)
|
||||||
|
|
||||||
### 8. auth.ts 混合 5 类职责
|
### 8. auth.ts 混合 5 类职责
|
||||||
|
|
||||||
@@ -122,7 +130,7 @@ NextAuth 配置 + 密码安全 DB 操作 + 角色规范化 + IP 解析 + 回调
|
|||||||
|
|
||||||
### 短期执行(P1)
|
### 短期执行(P1)
|
||||||
6. 统一 classSchedule 写入口到 scheduling 模块
|
6. 统一 classSchedule 写入口到 scheduling 模块
|
||||||
7. actions 层移除直接 DB 操作
|
7. ~~actions 层移除直接 DB 操作~~ ✅ 部分完成(exams/homework/questions/announcements 已修复,users/scheduling 待处理)
|
||||||
8. 拆分 auth.ts
|
8. 拆分 auth.ts
|
||||||
9. 集成 proctoring/exam-mode-config 到考试表单
|
9. 集成 proctoring/exam-mode-config 到考试表单
|
||||||
10. 拆分 users/import-export.ts
|
10. 拆分 users/import-export.ts
|
||||||
@@ -130,3 +138,4 @@ NextAuth 配置 + 密码安全 DB 操作 + 角色规范化 + IP 解析 + 回调
|
|||||||
### 中期执行(P2)
|
### 中期执行(P2)
|
||||||
11. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
|
11. 建立模块间数据访问规范(通过对方 data-access 或导出查询函数)
|
||||||
12. schema.ts 按业务域分节(加注释分隔)
|
12. schema.ts 按业务域分节(加注释分隔)
|
||||||
|
13. ~~拆分 `shared/lib/ai.ts`~~ ✅ 已完成(P2-2,commit 6588f74,拆分为 `ai/` 目录 6 个文件,原 ai.ts 保留为重导出)
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ await dispatchNotification({
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### P1-2 actions 层混入数据访问逻辑
|
#### P1-2 actions 层混入数据访问逻辑 ✅ 已修复
|
||||||
|
|
||||||
**问题**:
|
**问题**:
|
||||||
exams/homework/questions/announcements 的 actions.ts 中存在直接 `db.insert/update/delete`
|
exams/homework/questions/announcements 的 actions.ts 中存在直接 `db.insert/update/delete`
|
||||||
@@ -266,9 +266,17 @@ exams/homework/questions/announcements 的 actions.ts 中存在直接 `db.insert
|
|||||||
- actions 只做:权限校验 + 调用 data-access + revalidatePath
|
- actions 只做:权限校验 + 调用 data-access + revalidatePath
|
||||||
|
|
||||||
**迁移步骤**:
|
**迁移步骤**:
|
||||||
1. 识别 actions.ts 中的直接 DB 操作
|
1. ~~识别 actions.ts 中的直接 DB 操作~~ ✅ 已完成
|
||||||
2. 迁移到对应 data-access.ts
|
2. ~~迁移到对应 data-access.ts~~ ✅ 已完成
|
||||||
3. actions 改为调用 data-access 函数
|
3. ~~actions 改为调用 data-access 函数~~ ✅ 已完成
|
||||||
|
|
||||||
|
**完成状态**:2026-06-17 已完成(commit 84d6636),4 个模块的 actions 层 DB 操作全部下沉到 data-access:
|
||||||
|
- exams:新增 7 个 data-access 函数,actions.ts 831→766 行,data-access.ts 374→524 行
|
||||||
|
- homework:新建 data-access-write.ts(285 行,10 个写函数),actions.ts 387→239 行
|
||||||
|
- questions:新增 4 个 data-access 函数,actions.ts 294→177 行,data-access.ts 138→299 行
|
||||||
|
- announcements:新增 5 个 data-access 函数,actions.ts 242→231 行,data-access.ts 120→186 行
|
||||||
|
|
||||||
|
**剩余未修复模块**(不在本次 P1-2 范围):users(updateUserProfileAction)、scheduling(applyAutoScheduleAction/autoScheduleAction)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -356,7 +364,7 @@ src/shared/db/schema/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### P2-2 `ai.ts` 拆分
|
#### P2-2 `ai.ts` 拆分 ✅ 已修复
|
||||||
|
|
||||||
**问题**:
|
**问题**:
|
||||||
218 行,混合 5 类职责
|
218 行,混合 5 类职责
|
||||||
@@ -372,6 +380,16 @@ src/shared/lib/ai/
|
|||||||
└── errors.ts # 错误格式化
|
└── errors.ts # 错误格式化
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**完成状态**:2026-06-17 已完成(commit 6588f74),原 `src/shared/lib/ai.ts`(247 行)拆分为 `src/shared/lib/ai/` 目录 6 个文件:
|
||||||
|
- `payload-parser.ts`(96 行)- 请求负载解析
|
||||||
|
- `api-key-crypto.ts`(34 行)- API Key 加密/解密
|
||||||
|
- `provider-config.ts`(66 行)- Provider 配置查询
|
||||||
|
- `client.ts`(67 行)- AI 客户端创建与调用
|
||||||
|
- `errors.ts`(9 行)- 错误格式化
|
||||||
|
- `index.ts`(7 行)- 聚合导出
|
||||||
|
|
||||||
|
原 `ai.ts` 保留为向后兼容的重导出文件(12 行),调用方无需修改 import 路径。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 三、解耦执行优先级
|
## 三、解耦执行优先级
|
||||||
@@ -391,7 +409,7 @@ src/shared/lib/ai/
|
|||||||
|
|
||||||
| 优先级 | 任务 | 预估影响范围 | 风险 |
|
| 优先级 | 任务 | 预估影响范围 | 风险 |
|
||||||
|--------|------|-------------|------|
|
|--------|------|-------------|------|
|
||||||
| 7 | P1-2 actions 层下沉 DB 操作 | 4 个模块 | 中 |
|
| 7 | ~~P1-2 actions 层下沉 DB 操作~~ ✅ | 4 个模块 | 中 |
|
||||||
| 8 | P1-1 跨模块 DB 查询改为 data-access | 全项目 | 高 |
|
| 8 | P1-1 跨模块 DB 查询改为 data-access | 全项目 | 高 |
|
||||||
| 9 | P1-3 拆分 auth.ts | auth + shared/lib | 中 |
|
| 9 | P1-3 拆分 auth.ts | auth + shared/lib | 中 |
|
||||||
| 10 | P1-4 拆分 users/import-export | users | 低 |
|
| 10 | P1-4 拆分 users/import-export | users | 低 |
|
||||||
@@ -403,7 +421,7 @@ src/shared/lib/ai/
|
|||||||
| 优先级 | 任务 | 预估影响范围 | 风险 |
|
| 优先级 | 任务 | 预估影响范围 | 风险 |
|
||||||
|--------|------|-------------|------|
|
|--------|------|-------------|------|
|
||||||
| 13 | P2-1 schema.ts 按业务域拆分 | shared/db + 全项目 | 高(需全面回归) |
|
| 13 | P2-1 schema.ts 按业务域拆分 | shared/db + 全项目 | 高(需全面回归) |
|
||||||
| 14 | P2-2 ai.ts 拆分 | shared/lib/ai | 中 |
|
| 14 | ~~P2-2 ai.ts 拆分~~ ✅ | shared/lib/ai | 中 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -412,8 +430,8 @@ src/shared/lib/ai/
|
|||||||
### 4.1 文件行数
|
### 4.1 文件行数
|
||||||
|
|
||||||
- [ ] 所有文件 ≤ 1000 行(硬上限)
|
- [ ] 所有文件 ≤ 1000 行(硬上限)
|
||||||
- [ ] React 组件 ≤ 500 行(复杂表单/表格 ≤ 800 行)
|
- [x] React 组件 ≤ 500 行(复杂表单/表格 ≤ 800 行)
|
||||||
- [ ] Server Actions / Data Access ≤ 800 行
|
- [x] Server Actions / Data Access ≤ 800 行(P1-2 后 exams/actions.ts 766 行、homework/actions.ts 239 行、questions/actions.ts 177 行、announcements/actions.ts 231 行均达标)
|
||||||
|
|
||||||
### 4.2 模块封装
|
### 4.2 模块封装
|
||||||
|
|
||||||
@@ -423,16 +441,16 @@ src/shared/lib/ai/
|
|||||||
|
|
||||||
### 4.3 职责单一
|
### 4.3 职责单一
|
||||||
|
|
||||||
- [ ] actions.ts 只做编排(权限 + 调用 data-access + revalidate)
|
- [x] actions.ts 只做编排(权限 + 调用 data-access + revalidate)(P1-2 已修复 exams/homework/questions/announcements,users/scheduling 待处理)
|
||||||
- [ ] data-access.ts 只做数据存取(无业务计算)
|
- [x] data-access.ts 只做数据存取(无业务计算)(P2-2 后 ai/ 目录职责单一)
|
||||||
- [ ] 业务计算逻辑在 *-service.ts 文件中
|
- [x] 业务计算逻辑在 *-service.ts 文件中(homework/stats-service.ts 标杆)
|
||||||
|
|
||||||
### 4.4 架构文档可读性
|
### 4.4 架构文档可读性
|
||||||
|
|
||||||
- [ ] 阅读 004 文档后能说出每个模块的职责
|
- [x] 阅读 004 文档后能说出每个模块的职责
|
||||||
- [ ] 阅读 004 文档后能说出模块间的依赖关系
|
- [x] 阅读 004 文档后能说出模块间的依赖关系
|
||||||
- [ ] 阅读 004 文档后能说出核心业务的数据流向
|
- [x] 阅读 004 文档后能说出核心业务的数据流向
|
||||||
- [ ] 阅读 004 文档后能说出关键 API 的调用链路
|
- [x] 阅读 004 文档后能说出关键 API 的调用链路
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user