Files
NextEdu/bugs/back_bug.md
SpecialX 49291fcc31 refactor: fix all P0/P1/P2 bugs and architecture issues
Bug fixes (from bugs/ directory):

- Fix cross-module DB queries in 9 modules (homework, grades, parent, diagnostic, elective, proctoring, notifications, scheduling, classes) by routing through data-access functions

- Fix shared/lib <-> auth circular dependency via new session.ts module

- Fix divide-by-zero guard in grades data-access

- Fix audit export data truncation (paginated fetch for full datasets)

- Fix missing transactions in homework grading and elective lottery

- Fix missing revalidatePath in course-plans actions

- Fix frontend permission checks using requirePermission instead of requireAuth

- Fix dashboard role routing using session.user.roles

- Fix student auth pattern (migrate getDemoStudentUser to users module)

- Fix ActionState return type handling in components

Code quality fixes:

- Remove 60+ as type assertions (replace with type guards)

- Remove non-null assertions (use optional chaining or explicit checks)

- Convert dynamic imports to static imports (grades, diagnostic)

- Add React.cache() wrapping for read functions

- Parallelize independent queries with Promise.all

- Add explicit return types to 30+ arrow functions

- Replace any with unknown + type guards

- Fix import type for type-only imports

- Add Zod validation schemas for classes and diagnostic modules

- Extract duplicate code (normalizeRoleName, normalizeBcryptHash, logger IP extraction)

- Add console.error to silent catch blocks

- Fix permission naming consistency (exam:proctor_read -> exam:proctor:read)

Architecture doc sync:

- Update 004_architecture_impact_map.md and 005_architecture_data.json

- Update management-modules-audit.md for P0-7 cross-module fix

Moved deleted proctoring event route to deletes/ folder.
2026-06-19 05:13:34 +08:00

89 KiB
Raw Permalink Blame History

后端模块规范核查报告

核查日期2026-06-18 核查范围:src/modules/ 下所有后端 .ts 文件actions / data-access / schema / types / services 等非 components、非 hooks 文件) 核查依据:

  • .trae/rules/project_rules.md 项目规则
  • docs/standards/coding-standards.md 编码规范
  • docs/architecture/004_architecture_impact_map.md 架构影响地图
  • Vercel React Best Practices 性能优化规则react-best-practices 技能)

严重程度定义:

  • P0:严重违规,破坏架构分层 / 安全漏洞 / 数据正确性问题,必须立即修复
  • P1:明确违规,影响可维护性 / 类型安全 / 性能,应尽快修复
  • P2:轻微违规或代码异味,可在迭代中优化

目录


一、汇总统计

1.1 按严重程度

严重程度 数量 典型问题
P0 14 跨模块直查/直写 DB 表、循环依赖、z.any()、N+1 查询、未返回 ActionState、无 Zod 验证、硬编码弱密码
P1 60+ as 断言滥用、requireAuth 替代 requirePermission、缺少 import type、动态 import、无事务、除零 bug、导出数据截断
P2 100+ 非空断言 !、未用 React.cache()、串行查询未并行化、重复 filter、静默吞异常、缺返回类型标注、文档不同步

1.2 按问题类别

问题类别 涉及文件数 关键发现
架构违规 25+ 跨模块直查 DB 是最普遍问题messaging↔notifications 循环依赖actions 层直接 DB 操作
TS 规范 30+ as 断言大量存在;z.any()import type 未用;非空断言 !;隐式 any[]
Server Action 规范 12+ requireAuth 替代 requirePermission;未返回 ActionState;无 Zod 验证;缺 revalidatePath
性能 20+ N+1 查询;动态 import未用 cache();串行 await 循环;重复 filter 遍历
安全 2 硬编码弱密码 "123456"as 断言掩盖类型不兼容
行数 1 exams/ai-pipeline.ts 912 行(超 800 建议,未超 1000 硬上限)

1.3 模块问题分布

模块 P0 P1 P2 总体评价
exams 3 5 6 跨模块直查/直写严重
homework 0 8 5 跨模块直查普遍
questions 2 2 3 z.any() + 未返回 ActionState
grades 1 6 7 N+1 查询 + 跨模块直查
textbooks 2 2 4 无 Zod 验证 + as 断言
classes 3 8 6 耦合最严重,混入多模块逻辑
school 1 1 2 actions 层直接 DB 操作
scheduling 0 4 3 缺返回类型标注
attendance 0 1 0 整体规范
course-plans 0 3 2 缺 revalidatePath
users 1 3 4 硬编码弱密码 + 无事务
messaging 1 6 6 循环依赖 + requireAuth
notifications 3 3 8 循环依赖 + as 断言类型不兼容
parent 0 2 2 跨模块直查
audit 0 4 6 导出数据截断
elective 0 3 5 无事务 + 串行更新
proctoring 1 6 3 actions 层直接 DB 操作
diagnostic 0 2 5 跨模块直查 + 性能问题
dashboard 0 0 0 标杆模块
files 0 2 3 隐式 any[] + 非空断言
announcements 0 1 5 as 断言 + 错误吞没
settings 0 3 9 缺 data-access 层 + 无 Zod
layout 0 0 2 类型松散

二、P0 严重问题清单(立即修复)

P0-1exams 模块直写 questions 表

  • 文件src/modules/exams/data-access.ts
  • 行号2, 318
  • 问题persistAiGeneratedExamDraft 直接 db.insert(questions) 写入 questions 表(属 questions 模块),破坏模块封装
  • 修复:改为调用 questions/data-access.createQuestionWithRelations() 或在 questions 模块暴露批量插入接口

P0-2exams 模块直查 classes 表

  • 文件src/modules/exams/data-access.ts
  • 行号2, 72-80, 156-163, 357-364
  • 问题getExams/getExamById/getExamsDashboardStats 直接查询 classes 表获取 gradeId
  • 修复:在 classes 模块暴露 getGradeIdsByClassIds(classIds) 接口

P0-3questions/schema.ts 使用 z.any()

  • 文件src/modules/questions/schema.ts
  • 行号6
  • 问题content: z.any() 违反"禁止 any"规则
  • 修复:改为 z.unknown()

P0-4questions/actions.ts 未返回 ActionState

  • 文件src/modules/questions/actions.ts
  • 行号154, 166-175
  • 问题getQuestionsActiongetKnowledgePointOptionsAction 直接返回原始结果,未包装为 ActionState<T>,错误时 throw 而非返回失败状态
  • 修复:改为 Promise<ActionState<...>> 返回 { success: true, data: result }

P0-5textbooks 模块无 Zod 验证 + 大量 as 断言

  • 文件src/modules/textbooks/actions.ts
  • 行号:全文件,特别 54-58, 92-98, 154, 219-221, 259-261
  • 问题:缺少 schema.ts 文件,所有 Action 均无 Zod 验证,使用手动 if (!rawData.title) 检查14 处 formData.get("title") as string 断言
  • 修复:新建 schema.ts,为每个 Action 定义 Zod schema改用 typeof 守卫或 getStringValue() 辅助函数

P0-6grades 模块 N+1 查询

  • 文件src/modules/grades/data-access-analytics.ts
  • 行号142-185
  • 问题getClassComparisonfor (const cls of classRows) { ... await db.select(...) } 循环内串行查询N+1 问题
  • 修复:用 inArray 一次性查询所有班级的成绩,再在内存分组

P0-7classes 模块跨模块直接查询 DB 表

  • 文件src/modules/classes/data-access-stats.tssrc/modules/classes/data-access-students.ts
  • 行号data-access-stats.ts: 11-18data-access-students.ts: 10-14
  • 问题:直接导入并查询 homeworkAssignmentshomeworkSubmissionshomeworkAssignmentTargetshomeworkAssignmentQuestionsexams 等其他模块的表
  • 修复:通过 homework 模块的 data-access 暴露的函数获取数据

P0-8school 模块 actions 层直接操作 DB

  • 文件src/modules/school/actions.ts
  • 行号7-8, 26-30, 53-59, 73, 96-108, 133-147, 161, 182-186, 211-217, 233, 261-268, 294-303, 317
  • 问题actions 层直接导入 db 和所有 schema所有 mutation 直接操作 DB未下沉到 data-access 层
  • 修复:在 data-access.ts 中新增 createDepartmentupdateDepartmentdeleteDepartmentcreateSchool 等函数

P0-9proctoring 模块 actions 层直接查询 DB

  • 文件src/modules/proctoring/actions.ts
  • 行号11-13, 79-84
  • 问题actions.ts编排层直接导入 dbexamSubmissions 并执行 DB 查询,违反三层架构
  • 修复:将 submission 归属校验逻辑移至 data-access.ts

P0-10messaging↔notifications 循环依赖

  • 文件src/modules/messaging/data-access.tssrc/modules/notifications/data-access.tssrc/modules/notifications/channels/in-app-channel.ts
  • 行号messaging/data-access.ts: 192-203notifications/data-access.ts: 20-21in-app-channel.ts: 50
  • 问题messaging 写 messageNotificationsnotifications 反向依赖 messaging形成循环依赖
  • 修复:将 messageNotificationsnotificationPreferences 表所有权移交 notifications 模块

P0-11notifications/in-app-channel.ts 非法 as 断言

  • 文件src/modules/notifications/channels/in-app-channel.ts
  • 行号54
  • 问题payload.type as "message" | "announcement" | "homework" | "grade" 源类型 "info"|"warning"|"error"|"success" 与目标类型不兼容as 断言非法
  • 修复:重新设计类型映射函数,或统一 messaging/notifications 的 type 定义

P0-12users 模块硬编码弱密码

  • 文件src/modules/users/user-service.ts
  • 行号13
  • 问题const DEFAULT_PASSWORD = "123456" 硬编码弱密码,批量导入用户使用极弱默认密码
  • 修复:改为随机生成密码或要求首次登录强制修改密码,至少使用 crypto.randomBytes 生成

P0-13users/actions.ts updateUserProfile 绕过权限校验

  • 文件src/modules/users/actions.ts
  • 行号29-51
  • 问题updateUserProfile 使用 requireAuth() 而非 requirePermission(),且在 actions 层直接执行 db.update(users),返回 Promise<void> 而非 ActionState<T>
  • 修复:改为 requirePermission(Permissions.USER_MANAGE) 或新增 USER_PROFILE_UPDATE 权限点DB 操作下沉到 data-access返回 ActionState<void>

P0-14scheduling/data-access.ts 缺返回类型标注

  • 文件src/modules/scheduling/data-access.ts
  • 行号239, 246, 255, 262
  • 问题getAdminClassesForScheduling()getTeachersForScheduling()getClassroomsForScheduling()getClassSubjectsForScheduling() 缺少返回类型标注,违反"函数返回值必须显式标注,特别是 Promise"
  • 修复:添加返回类型 : Promise<Array<{ id: string; name: string; grade: string }>>

三、按模块详细核查

3.1 exams考试模块

src/modules/exams/actions.ts767 行)

行号范围 问题类别 严重程度 问题描述 改进建议
270 TS规范 P1 formData.get("questionsJson") as string | null — 使用 as 断言,非从 unknown 转换 改用 typeof 守卫:const raw = formData.get("questionsJson"); const rawQuestions = typeof raw === "string" ? raw : null
349-351 TS规范 P1 三处 as string | null 断言(questionsJson/aiQuestionsJson/structureJson 统一使用 getStringValue() 辅助函数
4 TS规范 P2 import { ActionState } — 类型未使用 import type 改为 import type { ActionState }
564-565 Server Action规范 P2 JSON.parse(rawQuestions) 直接 parse 后传入 Zodparse 异常未捕获 用 try-catch 包裹或先 as unknown 再 safeParse
全文件 行数 P2 实际 767 行,架构文档记录为 691 行,文档与代码不同步 同步更新 004 和 005 架构文档

合规项:所有 10 个 Action 均调用 requirePermission() ✓;均使用 Zod 验证 ✓;均返回 ActionState<T> ✓;均使用 revalidatePath ✓。

src/modules/exams/ai-pipeline.ts912 行)

行号范围 问题类别 严重程度 问题描述 改进建议
全文件 行数 P2 912 行,超出 800 行建议(架构文档记录 857 行,已不同步)。混合 4 类职责 按职责拆分为 ai-json-parser.tsai-prompts.tsai-requests.tsai-preview-builder.ts
464 TS规范 P2 draft.sections!.forEach — 非空断言 改用 if (draft.sections) { draft.sections.forEach(...) }
657, 665, 666, 671 TS规范 P2 多处 aiParsed.sections!.flatMap / aiParsed.sections!.map — 非空断言 同上,用条件守卫替代
505, 508, 545, 879 TS规范 P2 as Record<string, unknown> — 虽然从 unknown 转换允许,但缺少注释说明原因 添加注释 // safe: validated by isRecord
557-558 代码质量 P2 catch {} 空捕获块,静默吞掉错误 至少记录 console.warn
503-524 代码质量 P2 normalizeQuestionCandidate 嵌套定义在 parseQuestionDetail 内部,每次调用都重新创建闭包 提取为模块级函数

合规项:使用 mapWithConcurrency 实现并发控制 ✓;使用 Promise.all ✓;env.AI_MODEL 服务端环境变量无 NEXT_PUBLIC_ 前缀 ✓。

src/modules/exams/data-access.ts524 行)

行号范围 问题类别 严重程度 问题描述 改进建议
2, 318 架构违规 P0 persistAiGeneratedExamDraft 直接 db.insert(questions) 写入 questions 表 改为调用 questions/data-access.createQuestionWithRelations()
2, 72-80, 156-163, 357-364 架构违规 P0 getExams/getExamById/getExamsDashboardStats 直接查询 classes 在 classes 模块暴露 getGradeIdsByClassIds(classIds) 接口
2, 206-226, 509-524 架构违规 P1 resolveSubjectGradeNames/getExamSubjects/getExamGrades 直接查询 subjects/grades 在 school 模块暴露 getSubjectOptions()/getGradeOptions() 接口
76, 160, 361 TS规范 P1 teacherGradeIds.map(g => g.gradeId).filter(Boolean) as string[]as 断言 使用类型守卫:.filter((id): id is string => Boolean(id))
108, 172 TS规范 P2 (exam.status as ExamStatus)as 断言从 string 转换 使用 z.enum() 验证或类型守卫函数
182 TS规范 P2 exam.structure as unknown — 转换到 unknown 允许,但无注释 添加注释说明

合规项:使用 cache() 包装查询函数 ✓;使用 Promise.all 并行查询 ✓;使用 Map 做 O(1) 查找 ✓。

src/modules/exams/types.ts31 行)

无违规问题。类型定义规范,接口命名 PascalCase 无 I 前缀 ✓。


3.2 homework作业模块

src/modules/homework/actions.ts282 行)

行号范围 问题类别 严重程度 问题描述 改进建议
247 TS规范 P1 formData.get("answersJson") as string | nullas 断言 改用 typeof 守卫
54 TS规范 P2 JSON.parse(targetStudentIdsJson) as unknown — 转换到 unknown 允许,但无注释 添加注释

合规项:所有 5 个 Action 均调用 requirePermission() ✓;使用 Zod 验证 ✓;返回 ActionState ✓;使用 revalidatePath ✓;使用 Set 做查找 ✓。

src/modules/homework/data-access.ts681 行)

行号范围 问题类别 严重程度 问题描述 改进建议
8-20, 101-105, 162-166, 283-287, 337-340, 518-519 架构违规 P1 直接查询 exams5 处),属 exams 模块 在 exams 模块暴露 getExamIdsByGradeIds(gradeIds) 接口
8-20, 66-77, 86-95, 149-158, 242-254, 275-281, 347-351 架构违规 P1 直接查询 classEnrollments 表(多处),属 classes 模块 在 classes 模块暴露 getStudentIdsByClassId(classId) / getStudentIdsByClassIds(classIds) 接口
8-20, 515-519 架构违规 P1 直接查询 subjects 表,属 school 模块 通过 school data-access 获取
8-20, 480-486 架构违规 P1 直接查询 users/roles/usersToRoles 表,属 users 模块 在 users 模块暴露 getUserWithRole(userId, roleName) 接口
475-490 架构违规 P2 getDemoStudentUser 使用 auth() 而非 getAuthContext(),绕过 auth-guard 标准模式 改用 getAuthContext() 获取 userId
39 TS规范 P1 return v as HomeworkQuestionContent — 从 Record<string, unknown> 断言 使用类型守卫或 z.safeParse() 验证
124, 226, 314, 392, 467, 645 TS规范 P2 多处 (status as HomeworkAssignmentStatus)as 断言 使用类型守卫函数或 Zod 验证
451-455 性能 P2 getHomeworkSubmissionDetails 获取全部 submissions 仅为计算 prev/next 导航 改用 SQL LAG/LEAD 窗口函数或仅查询相邻 ID

合规项:使用 cache() ✓;使用 Map/Set 聚合 ✓;"server-only" 导入 ✓。

src/modules/homework/data-access-write.ts317 行)

行号范围 问题类别 严重程度 问题描述 改进建议
8-17, 70-76, 125-130 架构违规 P1 直接查询 classes 表(getClassTeacherById 在 classes 模块暴露 getClassTeacherById(classId) 接口
8-17, 132-143 架构违规 P1 直接查询 classEnrollments 表(getActiveClassStudentIdsForHomework 在 classes 模块暴露 getActiveStudentIdsByClassId(classId) 接口
8-17, 107-116 架构违规 P1 直接查询 classSubjectTeachers 在 classes 模块暴露 getTeacherSubjectIdsByClass(classId, teacherId) 接口
8-17, 81-88 架构违规 P1 直接查询 exams 表(getExamWithQuestionsForHomework 在 exams 模块暴露 getExamForHomeworkCreation(examId) 接口
305-311 性能 P2 gradeHomeworkAnswersfor (const ans of answers) { await db.update(...) } — 循环内串行 await未使用事务 db.transaction 包裹,或用 Promise.all 并行化无依赖更新

合规项"server-only" 导入 ✓;所有函数显式标注返回类型 ✓;无 as/any ✓。

src/modules/homework/schema.ts29 行)

无违规问题。Zod 验证完整 ✓。

src/modules/homework/stats-service.ts483 行)

行号范围 问题类别 严重程度 问题描述 改进建议
8-16, 313-323, 320-323 架构违规 P1 直接查询 classEnrollments 通过 classes data-access 获取
8-16, 437-441 架构违规 P1 直接查询 classes 通过 classes data-access 获取
8-16, 425-429, 443-447 架构违规 P1 直接查询 exams 通过 exams data-access 获取
8-16, 366-369 架构违规 P1 直接查询 users 在 users 模块暴露 getUserNamesByIds(ids) 接口
220 TS规范 P2 (assignment.status as HomeworkAssignmentStatus)as 断言 使用类型守卫
346 性能 P2 limit: 5000 查询班级所有 graded submissions大班级可能性能问题 考虑分批查询或 SQL 聚合

合规项:使用 cache() ✓;使用 Promise.all 并行查询 ✓;使用 Map 聚合 ✓。

src/modules/homework/types.ts205 行)

无违规问题。类型定义规范 ✓。


3.3 questions题库模块

src/modules/questions/actions.ts176 行)

行号范围 问题类别 严重程度 问题描述 改进建议
154 Server Action规范 P0 getQuestionsAction 未返回 ActionState<T>,直接返回 getQuestions(params) 的原始结果 { data, meta },错误时 throw 改为 Promise<ActionState<...>> 返回 { success: true, data: result }
166-175 Server Action规范 P0 getKnowledgePointOptionsAction 未返回 ActionState<T>,直接返回 KnowledgePointOption[] 同上,包装为 ActionState
154 TS规范 P1 getQuestionsAction 缺少显式返回类型标注 添加 : Promise<ActionState<...>>
7 TS规范 P2 import { ActionState } — 类型导入未用 import type 改为 import type { ActionState }
158-163, 170-175 代码质量 P2 catch 块两个分支都 throw e,是死代码 简化为单个 throw e 或返回失败 ActionState
20 命名规范 P2 函数名 createNestedQuestion 与其他模块的 createXxxAction 命名模式不一致 改为 createQuestionAction

合规项:所有 Action 调用 requirePermission()create/update/delete 使用 Zod 验证 ✓;写操作使用 revalidatePath ✓。

src/modules/questions/data-access.ts299 行)

行号范围 问题类别 严重程度 问题描述 改进建议
4, 266-298 架构违规 P1 getKnowledgePointOptions 直接查询 knowledgePoints/chapters/textbooks 表,属 textbooks 模块 在 textbooks 模块暴露 getKnowledgePointOptions() 接口
108 代码质量 P2 局部变量名 knowledgePoints 与 import 的 knowledgePoints 表名冲突 重命名为 kpRowskps
151-184, 231-242 性能 P2 insertQuestionWithRelations / deleteQuestionRecursive 递归内串行 await 对于删除可改为先收集所有 ID 再批量删除

合规项:使用 cache() ✓;"server-only" 导入 ✓;无 as/any ✓;显式返回类型 ✓。

src/modules/questions/schema.ts18 行)

行号范围 问题类别 严重程度 问题描述 改进建议
6 TS规范 P0 content: z.any() — 使用 any,违反"禁止 any"规则 改为 z.unknown()

src/modules/questions/types.ts34 行)

无违规问题。content: unknown 正确使用 unknown ✓。


3.4 grades成绩模块

src/modules/grades/actions.ts312 行)

行号范围 问题类别 严重程度 问题描述 改进建议
93 代码质量 P2 JSON.parse(recordsJson) 未用 try-catch 包裹parse 失败会 500 用 try-catch 或先 as unknown 再 safeParse

合规项:所有 Action 调用 requirePermission() ✓;使用 Zod 验证 ✓;返回 ActionState<T> ✓;使用 revalidatePathscope 二次校验 ✓。

src/modules/grades/actions-analytics.ts133 行)

合规项:所有 Action 调用 requirePermission() ✓;返回 ActionState<T>scope 二次校验 ✓。无违规问题。

src/modules/grades/data-access.ts419 行)

行号范围 问题类别 严重程度 问题描述 改进建议
6-12, 100, 382-386 架构违规 P1 直接查询 classes 通过 classes data-access 获取
6-12, 365-368, 408-411 架构违规 P1 直接查询 classEnrollments 通过 classes data-access 获取
6-12, 102, 276, 280 架构违规 P1 直接查询 subjects 通过 school data-access 获取
6-12, 100, 109-112, 269, 342 架构违规 P1 直接查询 users 通过 users data-access 获取
148, 172 性能 P1 const { createId } = await import("@paralleldrive/cuid2") — 函数内动态 import每次调用都有开销 改为文件顶部静态 import { createId } from "@paralleldrive/cuid2"
249 代码质量/Bug P1 const ratio = scores[i] / fullScores[i]fullScores[i] 可能为 0导致 Infinity/NaN 添加 if (fullScores[i] <= 0) continue 守卫
全文件 性能 P2 查询函数未使用 React.cache() 包装 cache() 包装查询函数
248-252 性能 P2 for 循环内两次独立 if 判断遍历同一数组 合并为单次循环同时计算 passCount 和 excellentCount

合规项"server-only" 导入 ✓;使用 Map/Set ✓;无 as/any ✓;显式返回类型 ✓。

src/modules/grades/data-access-analytics.ts293 行)

行号范围 问题类别 严重程度 问题描述 改进建议
6-10, 79, 125-128 架构违规 P1 直接查询 classes 通过 classes data-access 获取
6-10, 80, 211 架构违规 P1 直接查询 subjects 通过 school data-access 获取
22, 27, 32 代码质量 P2 toNumber/normalize/buildScopeClassFilter 在 data-access.ts 和 data-access-ranking.ts 中重复定义 提取到 grades/utils.ts
142-185 性能 P0 getClassComparisonfor (const cls of classRows) { ... await db.select(...) } — 循环内串行查询N+1 问题 inArray 一次性查询所有班级的成绩,再在内存分组
133-136 性能 P2 classRows.filter((c) => scope.classIds.includes(c.id))includes 是 O(n) 查找 scope.classIds 转为 Set 后用 .has()
180-181, 238-239 性能 P2 normalized.filter((s) => s >= 60).lengthnormalized.filter((s) => s >= 85).length — 两次 filter 遍历同一数组 合并为单次 reduce 同时统计两个计数
全文件 性能 P2 查询函数未使用 React.cache() cache() 包装

合规项"server-only" ✓;无 as/any ✓;显式返回类型 ✓。

src/modules/grades/data-access-ranking.ts121 行)

行号范围 问题类别 严重程度 问题描述 改进建议
6-10, 44-53 架构违规 P1 直接查询 classEnrollments 通过 classes data-access 获取
6-10, 37-41 架构违规 P1 直接查询 users 通过 users data-access 获取
17, 22 代码质量 P2 toNumber/normalize 重复定义 提取到共享 utils
100, 102 性能 P2 sorted.findIndex(...)sorted.find(...) 两次 O(n) 查找同一元素 合并为一次遍历
全文件 性能 P2 查询函数未使用 React.cache() cache() 包装

src/modules/grades/export.ts214 行)

行号范围 问题类别 严重程度 问题描述 改进建议
6-11, 116-120 架构违规 P1 直接查询 classes 通过 classes data-access 获取
6-11, 124-132 架构违规 P1 直接查询 subjects 通过 school data-access 获取
6-11, 135-144 架构违规 P1 直接查询 users 通过 users data-access 获取
154 TS规范 P2 subjMap.get(r.studentId)! — 非空断言 改用 const subjMap = scoreMap.get(r.studentId); if (!subjMap) continue;

src/modules/grades/schema.ts52 行)& types.ts176 行)

无违规问题。Zod 验证完整,类型定义规范 ✓。


3.5 textbooks教材模块

src/modules/textbooks/actions.ts276 行)

行号范围 问题类别 严重程度 问题描述 改进建议
全文件 Server Action规范 P0 缺少 schema.ts 文件,所有 Action 均无 Zod 验证,使用手动 if (!rawData.title) 检查 新建 schema.ts,为每个 Action 定义 Zod schema
41-45 架构违规 P1 本地定义 export type ActionState,未使用 @/shared/types/action-state 的统一类型 删除本地定义,改用 import type { ActionState } from "@/shared/types/action-state"
18 TS规范 P1 import { CreateTextbookInput, UpdateTextbookInput } — 类型导入未用 import type 改为 import type { ... }
54-58, 92-98, 154, 219-221, 259-261 TS规范 P0 多处 formData.get("title") as stringas 断言(共 14 处) 改用 typeof 守卫或 getStringValue() 辅助函数
20, 47 代码质量 P2 // ... existing code ... 残留注释 删除
164 代码质量 P2 order: 0 // Default order 魔法数字 提取为常量 const DEFAULT_CHAPTER_ORDER = 0

合规项:所有 Action 调用 requirePermission() ✓;使用 revalidatePath ✓。

src/modules/textbooks/data-access.ts444 行)

行号范围 问题类别 严重程度 问题描述 改进建议
42 TS规范 P2 byId.get(pid)!.children.push(ch) — 非空断言 改用 const parent = byId.get(pid); if (parent) parent.children.push(ch)
51 TS规范 P1 sortRecursive(n.children as Array<Chapter & { children: Chapter[] }>)as 断言 使用类型守卫或在 Chapter 类型中明确 children 字段
71 TS规范 P2 or(...)! — 对 or() 返回值使用非空断言 改用条件判断
110, 128 代码质量 P2 getTextbookById 返回 Textbook | undefined,与其他模块返回 null 的模式不一致 统一返回 Textbook | null
368, 381 代码质量 P2 createKnowledgePoint/updateKnowledgePoint 参数使用内联类型 将输入类型移至 types.ts

合规项:使用 cache() ✓;使用 Promise.all ✓;"server-only" ✓;无 any ✓;显式返回类型 ✓。这是架构文档中的"标杆模块",无跨模块 DB 访问 ✓。

src/modules/textbooks/types.ts83 行)

行号范围 问题类别 严重程度 问题描述 改进建议
1-3 代码质量 P2 残留注释 // In a real app, we would infer these from the schema... 删除过时注释

3.6 classes班级模块

src/modules/classes/actions.ts765 行)

行号范围 问题类别 严重程度 问题描述 改进建议
8-9 架构违规 P0 actions 层直接导入 dbgrades, classes schema 并执行 DB 查询 将权限校验查询下沉到 data-access-admin.ts
48-53, 109-111, 140-142, 175-183, 369-377, 518-533, 636-644 Server Action规范 P1 输入验证使用手动 typeof 检查而非 Zodclasses 模块完全没有 schema.ts 文件 新建 schema.ts,定义 Zod schema
538 TS规范 P1 weekdayNum as 1 | 2 | 3 | 4 | 5 | 6 | 7as 断言 用类型守卫 isValidWeekday(weekdayNum): weekdayNum is 1|2|3|4|5|6|7 替换
582 TS规范 P1 weekdayNum as 1 | 2 | 3 | 4 | 5 | 6 | 7 | undefined — 同上 同上
287, 706 TS规范 P2 JSON.parse(subjectTeachers) as unknown 后续用 as { subject?: unknown } 用 Zod schema 解析

src/modules/classes/data-access.ts656 行)

行号范围 问题类别 严重程度 问题描述 改进建议
26-27, 182-206 架构违规 P0 getTeacherClasses 中调用 getClassHomeworkInsightshomework 逻辑)和 getClassSchedulescheduling 逻辑) 将 homework insights 聚合逻辑移至 homework 模块
47 TS规范 P1 isDuplicateInvitationCodeError 箭头函数缺少返回类型标注 添加 : boolean
54 TS规范 P1 generateInvitationCode 箭头函数缺少返回类型标注 添加 : string
87 TS规范 P1 normalizeSortText 箭头函数缺少返回类型标注 添加 : string
89 TS规范 P1 parseFirstInt 箭头函数缺少返回类型标注 添加 : number | null
94 TS规范 P1 compareGradeLabel 箭头函数缺少返回类型标注 添加 : number
101-104 TS规范 P1 compareClassLike 箭头函数缺少返回类型标注 添加 : number
240 TS规范 P1 r.subject as ClassSubjectas 断言 用类型守卫 isClassSubject(r.subject) 过滤
266 TS规范 P1 r.name as ClassSubject — 同上 同上
287 TS规范 P2 idByName.get(name)! — 非空断言 const id = idByName.get(name); if (!id) return null 显式处理
297-299 代码质量 P1 throw new Error("Failed to create class") 后有 return id 不可达代码 删除 return id
561 TS规范 P1 r.name as ClassSubjectas 断言 用类型守卫替换
567 TS规范 P2 idByName.get(name)! — 非空断言 显式判空处理
120-127 性能 P2 getAccessibleClassIdsForTeacher 中两个独立 DB 查询串行执行 Promise.all 并行化

src/modules/classes/data-access-admin.ts441 行)

行号范围 问题类别 严重程度 问题描述 改进建议
82-117, 237-239 代码质量 P1 try-catch 吞掉错误返回空数组或 fallback 查询 移除 try-catch 或记录错误日志后 rethrow
135 TS规范 P1 r.subject as ClassSubjectas 断言 用类型守卫替换
259 TS规范 P1 r.subject as ClassSubject — 同上 同上
303 TS规范 P1 getManagedGrades 缺少返回类型标注 添加 : Promise<GradeListItem[]>
349 TS规范 P1 r.name as ClassSubjectas 断言 用类型守卫替换
369 TS规范 P2 idByName.get(name)! — 非空断言 显式判空
380-382 代码质量 P1 throw new Error("Failed to create class") 后有 return id 不可达代码 删除 return id

src/modules/classes/data-access-schedule.ts230 行)

行号范围 问题类别 严重程度 问题描述 改进建议
7-11, 33-48 架构违规 P1 直接导入并查询 classSchedule 表(该表归属 scheduling 模块) 将读取也委托给 scheduling 模块的 data-access
54 TS规范 P1 r.weekday as StudentScheduleItem["weekday"]as 断言 用类型守卫或 Zod 校验 weekday 范围
93 TS规范 P1 r.weekday as ClassScheduleItem["weekday"] — 同上 同上

src/modules/classes/data-access-stats.ts604 行)

行号范围 问题类别 严重程度 问题描述 改进建议
11-18 架构违规 P0 直接导入并查询 homeworkAssignmentQuestionshomeworkAssignmentTargetshomeworkAssignmentshomeworkSubmissionsexams 等 homework/exams 模块的 DB 表 通过 homework 模块的 data-access 暴露的函数获取数据
250 TS规范 P1 (s.status ?? "started") as stringas 断言 s.status 已是 string 类型,无需断言
261 TS规范 P1 (a.status as string) ?? "draft"as 断言 同上
512 TS规范 P1 (s.status ?? "started") as string — 同上 同上
523 TS规范 P1 (a.status as string) ?? "draft" — 同上 同上
130-151, 175-191 性能 P2 多个早期返回中重复构造相同的返回对象结构 提取 buildEmptyInsights(classRow, studentCounts) 工厂函数

src/modules/classes/data-access-students.ts280 行)

行号范围 问题类别 严重程度 问题描述 改进建议
10-14 架构违规 P0 直接导入并查询 homeworkAssignmentTargetshomeworkAssignmentshomeworkSubmissionsexams 等 homework/exams 模块的 DB 表 通过 homework 模块 data-access 获取数据
102 TS规范 P2 studentScores.get(s.studentId)! — 非空断言 显式判空处理
168-204 代码质量 P2 getStudentClasses 中 try-catch fallback 查询使用 sql\NULL`.as(...)` 模式,吞掉错误 移除 try-catch

src/modules/classes/types.ts201 行)

基本符合规范,无违规问题。


3.7 school学校模块

src/modules/school/actions.ts325 行)

行号范围 问题类别 严重程度 问题描述 改进建议
7-8, 26-30, 53-59, 73, 96-108, 133-147, 161, 182-186, 211-217, 233, 261-268, 294-303, 317 架构违规 P0 actions 层直接导入 db 和所有 schema所有 mutation 直接操作 DB完全没有下沉到 data-access 层 data-access.ts 中新增 createDepartmentupdateDepartmentdeleteDepartmentcreateSchool 等函数
188, 219, 235 性能 P2 await logAudit(...) 阻塞响应,审计日志写入是非关键路径 使用 Next.js after() 函数将 logAudit 改为非阻塞执行

src/modules/school/data-access.ts186 行)

行号范围 问题类别 严重程度 问题描述 改进建议
13, 27, 44, 59, 112, 133 代码质量 P2 所有函数都用 try-catch 包裹并返回空数组 [] 吞掉错误 移除 try-catch 或记录错误日志后 rethrow

src/modules/school/schema.ts51 行)& types.ts42 行)

符合规范。


3.8 scheduling排课模块

src/modules/scheduling/actions.ts300 行)

行号范围 问题类别 严重程度 问题描述 改进建议
10-11, 112-116 架构违规 P0 actions 层直接导入 dbusers schemaautoScheduleAction 中直接查询 users 表获取教师信息 在 data-access.ts 中新增 getTeachersByIds(teacherIds: string[]) 函数
115 TS规范 P1 teacherIds[0]! — 非空断言 用条件表达式 eq(users.id, teacherIds[0] ?? "")

src/modules/scheduling/auto-scheduler.ts310 行)

行号范围 问题类别 严重程度 问题描述 改进建议
144-145 TS规范 P1 schedule[i]!schedule[j]! — 非空断言 用局部变量 + 显式判空
全文件 行数 P2 工具函数规范要求 ≤ 40 行,此文件 310 行 拆分为 auto-scheduler/ 目录下的多个文件

src/modules/scheduling/data-access.ts368 行)

行号范围 问题类别 严重程度 问题描述 改进建议
239 TS规范 P0 getAdminClassesForScheduling() 缺少返回类型标注 添加返回类型
246 TS规范 P0 getTeachersForScheduling() 缺少返回类型标注 添加返回类型
255 TS规范 P0 getClassroomsForScheduling() 缺少返回类型标注 添加返回类型
262 TS规范 P0 getClassSubjectsForScheduling(classId: string) 缺少返回类型标注 添加返回类型
113-114 代码质量 P2 requesterName: users.nameoriginalTeacherName: users.name 选中同一列,requesterName 在 map 中被 userMap.get() 覆盖select 中的字段是死代码 删除 select 中的 requesterName: users.name
140 TS规范 P1 userIds[0]! — 非空断言 显式判空
221-222 TS规范 P1 rows[i]!rows[j]! — 非空断言 用局部变量 + 显式判空

src/modules/scheduling/schema.ts81 行)& types.ts124 行)

符合规范。


3.9 attendance考勤模块

src/modules/attendance/actions.ts271 行)

基本符合规范。所有 action 调用了 requirePermission、使用 Zod 验证、返回 ActionState、使用 revalidatePath

src/modules/attendance/data-access.ts271 行)

行号范围 问题类别 严重程度 问题描述 改进建议
195 TS规范 P1 const update: Record<string, unknown> = { updatedAt: new Date() } — 使用宽泛的 Record<string, unknown> 丢失类型安全 使用 Partial<typeof attendanceRecords.$inferSelect> 类型

src/modules/attendance/data-access-stats.ts145 行)& schema.ts43 行)& types.ts103 行)

符合规范。


3.10 course-plans教学计划模块

src/modules/course-plans/actions.ts265 行)

行号范围 问题类别 严重程度 问题描述 改进建议
236-246 Server Action规范 P1 deleteCoursePlanItemAction 未调用 revalidatePath 添加 revalidatePlanPaths() 调用
248-264 Server Action规范 P1 toggleCoursePlanItemCompletedAction 未调用 revalidatePath 同上

src/modules/course-plans/data-access.ts320 行)

行号范围 问题类别 严重程度 问题描述 改进建议
149 TS规范 P1 params.status as CoursePlanStatusas 断言 用类型守卫或 Zod 校验
158, 183 代码质量 P2 getCoursePlansgetCoursePlanById 用 try-catch 返回空数组/null 吞掉错误 移除 try-catch 或记录日志后 rethrow
300-305 性能 P2 reorderCoursePlanItems 中循环内串行 await db.update()N 次 DB 往返 db.transaction 批量更新,或用 Promise.all 并行化

src/modules/course-plans/schema.ts148 行)& types.ts60 行)

符合规范。


3.11 users用户模块

src/modules/users/actions.ts151 行)

行号范围 问题类别 严重程度 问题描述 改进建议
29-51 Server Action规范 P0 updateUserProfile 使用 requireAuth() 而非 requirePermission() 改为 requirePermission(Permissions.USER_MANAGE) 或新增 USER_PROFILE_UPDATE 权限点
29-51 架构违规 P1 updateUserProfile 在 actions 层直接执行 db.update(users) 将写操作下沉到 data-access.ts
29-51 Server Action规范 P1 updateUserProfile 返回 Promise<void> 而非 ActionState<T> 改为返回 Promise<ActionState<void>>
29 TS规范 P2 updateUserProfile(data: UpdateUserProfileInput) 缺少显式返回类型标注 标注为 Promise<ActionState<void>>
29-51 Server Action规范 P2 updateUserProfile 输入未使用 Zod 验证 新增 Zod schema
76-125 Server Action规范 P2 importUsersAction 输入验证使用手动逻辑,未使用 Zod parseUserImportData 改用 Zod 实现

src/modules/users/class-registration.ts27 行)

合规,无违规问题。正确通过 classes/data-access.enrollStudentByInvitationCode 跨模块通信。

src/modules/users/data-access.ts152 行)

行号范围 问题类别 严重程度 问题描述 改进建议
24 命名规范 P2 const rolePriority 常量未使用 UPPER_SNAKE_CASE 重命名为 ROLE_PRIORITY
26-31 架构违规 P2 normalizeRoleNameshared/lib/role-utils.tsnormalizeRole 重复 改为 import { normalizeRole } from "@/shared/lib/role-utils" 复用
26 TS规范 P2 normalizeRoleName 缺少显式返回类型标注 标注为 (value: string) => string
33 TS规范 P2 resolvePrimaryRole 缺少显式返回类型标注 标注为 (roleNames: string[]) => string

src/modules/users/import-export.ts176 行)

行号范围 问题类别 严重程度 问题描述 改进建议
98 TS规范 P2 const conditions = [] 隐式推断为 any[],违反"禁止 any"规则 标注类型 const conditions: ReturnType<typeof eq>[] = []
100-114 性能 P2 exportUsersToExcel 中 role 查询 → userIds 查询 → users 查询为串行 可接受(有依赖关系),但建议合并为子查询减少往返

src/modules/users/user-service.ts99 行)

行号范围 问题类别 严重程度 问题描述 改进建议
13 安全规范 P0 const DEFAULT_PASSWORD = "123456" 硬编码弱密码 改为随机生成密码或要求首次登录强制修改密码
15-19 架构违规 P2 normalizeBcryptHashshared/lib/bcrypt-utils.ts 重复 改为 import { normalizeBcryptHash } from "@/shared/lib/bcrypt-utils" 复用
15 TS规范 P2 normalizeBcryptHash 缺少显式返回类型标注 标注为 (value: string) => string
30-92 架构违规 P1 batchImportUsers 注释标注"批量导入用户(事务)",但实际未使用 db.transaction 包裹 await db.transaction(async (tx) => { ... }) 包裹
50-92 性能 P2 循环内串行 await db.insertN 条记录需 N 次 DB 往返 可批量插入用户和角色关联

3.12 messaging消息模块

src/modules/messaging/actions.ts247 行)

行号范围 问题类别 严重程度 问题描述 改进建议
163 Server Action规范 P1 getNotificationsAction 使用 requireAuth() 而非 requirePermission() 改为 requirePermission(Permissions.MESSAGE_READ)
177 Server Action规范 P1 markNotificationAsReadAction 使用 requireAuth() 而非 requirePermission() 同上
190 Server Action规范 P1 markAllNotificationsAsReadAction 使用 requireAuth() 而非 requirePermission() 同上
203 Server Action规范 P1 getNotificationPreferencesAction 使用 requireAuth() 而非 requirePermission() 同上
218 Server Action规范 P1 updateNotificationPreferencesAction 使用 requireAuth() 而非 requirePermission() 同上
213-247 Server Action规范 P2 updateNotificationPreferencesAction 未使用 Zod 验证 新增 Zod schema 校验 8 个布尔字段
87, 101, 129 Server Action规范 P2 markMessageAsReadAction/deleteMessageAction/getMessageDetailAction 参数 messageId 未使用 Zod 验证 新增 z.string().min(1) 校验 messageId

src/modules/messaging/data-access.ts252 行)

行号范围 问题类别 严重程度 问题描述 改进建议
12-14 架构违规 P1 导入 classEnrollments, classesgetRecipients227-251 行)直接 JOIN 跨模块表 通过 classes/data-access 暴露 getStudentsByClassIds(classIds) 接口
94 TS规范 P2 const conds = [] 隐式 any[] 标注 drizzle 条件类型
97 TS规范 P2 or(...)! 使用非空断言 改为显式处理 null
117 TS规范 P2 or(...)! 使用非空断言 同上
163 TS规范 P2 or(...)! 使用非空断言 同上
63 TS规范 P2 mapMessage 缺少显式返回类型标注 标注返回类型
77 TS规范 P2 mapNotification 缺少显式返回类型标注 标注返回类型
80 TS规范 P2 r.type as NotificationType 使用 as 断言 使用类型守卫
74, 85 TS规范 P2 toIso(r.createdAt) as string 使用 as 断言 处理 null 情况或修改 toIso 返回类型
192-203 架构违规 P0 createNotificationmessageNotifications 表,但 notifications 模块反向调用此函数,形成循环依赖 messageNotifications 表所有权移交 notifications 模块

src/modules/messaging/notification-preferences.ts166 行)

行号范围 问题类别 严重程度 问题描述 改进建议
14 TS规范 P2 toIso 缺少显式返回类型标注 标注为 (d: Date) => string
16 TS规范 P2 mapRow 缺少显式返回类型标注 标注返回类型

src/modules/messaging/schema.ts18 行)& types.ts108 行)

合规,无违规问题。


3.13 notifications通知模块

src/modules/notifications/actions.ts119 行)

行号范围 问题类别 严重程度 问题描述 改进建议
14-17 架构违规 P1 actions 层直接导入 dbclassEnrollmentsclasses 将 DB 查询下沉到 data-access.ts
83-96 架构违规 P1 sendClassNotificationAction 直接查询 classesclassEnrollments 通过 classes/data-access 暴露查询接口
30-52 Server Action规范 P2 sendNotificationAction 参数 payload 未使用 Zod 验证 新增 NotificationPayloadSchema
62-119 Server Action规范 P2 sendClassNotificationAction 参数 classId/payload 未使用 Zod 验证 新增 Zod schema 校验

src/modules/notifications/data-access.ts86 行)

行号范围 问题类别 严重程度 问题描述 改进建议
20 架构违规 P0 import { getNotificationPreferences } from "@/modules/messaging/notification-preferences" 反向依赖 messaging 模块 notificationPreferences 表所有权移交 notifications 模块
21 架构违规 P0 import type { NotificationPreferences } from "@/modules/messaging/types" 反向依赖 messaging 模块 类型定义应迁移到 notifications 模块
71-77 架构违规 P2 logNotificationSendconsole.info,无 DB 持久化 新增 notification_logs 表并写入发送结果

src/modules/notifications/dispatcher.ts152 行)

行号范围 问题类别 严重程度 问题描述 改进建议
44 TS规范 P2 getSenders 缺少显式返回类型标注 标注为 () => SenderRegistry
59 TS规范 P2 selectChannels 缺少显式返回类型标注 标注返回类型

src/modules/notifications/external-sdk.d.ts47 行)

行号范围 问题类别 严重程度 问题描述 改进建议
12, 20, 25, 33, 42, 43 TS规范 P2 多处使用 anyconst _default: anyconfig: anyoptions: any 安装实际 SDK 后用其自带类型覆盖;或使用 unknown

src/modules/notifications/index.ts38 行)& types.ts70 行)& channels/types.ts38 行)

合规,无违规问题。

src/modules/notifications/channels/email-channel.ts183 行)

行号范围 问题类别 严重程度 问题描述 改进建议
29 TS规范 P2 getEmailConfig 缺少显式返回类型标注 标注返回类型
45 TS规范 P2 getTypeColor 缺少显式返回类型标注 标注为 (type: NotificationPayload["type"]) => string
60 TS规范 P2 buildHtmlContent 缺少显式返回类型标注 标注为 (payload: NotificationPayload) => string
79 TS规范 P2 escapeHtml 缺少显式返回类型标注 标注为 (text: string) => string

src/modules/notifications/channels/in-app-channel.ts88 行)

行号范围 问题类别 严重程度 问题描述 改进建议
50 架构违规 P0 await import("@/modules/messaging/data-access") 动态 import messaging 模块,运行时形成循环 messageNotifications 表所有权移交 notifications
54 TS规范 P1 payload.type as "message" | "announcement" | "homework" | "grade" 使用 as 断言且源类型与目标类型不兼容as 断言非法 重新设计类型映射函数

src/modules/notifications/channels/sms-channel.ts236 行)

行号范围 问题类别 严重程度 问题描述 改进建议
30 TS规范 P2 getSmsConfig 缺少显式返回类型标注 标注返回类型
32 TS规范 P2 (process.env.SMS_PROVIDER ?? "mock") as "aliyun" | "tencent" | "mock" 使用 as 断言 使用类型守卫或 Zod 校验环境变量
44 TS规范 P2 buildTemplateParams 缺少显式返回类型标注 标注返回类型

src/modules/notifications/channels/wechat-channel.ts208 行)

行号范围 问题类别 严重程度 问题描述 改进建议
40 TS规范 P2 getWechatConfig 缺少显式返回类型标注 标注返回类型
99 TS规范 P2 buildTemplateData 缺少显式返回类型标注 标注返回类型

3.14 parent家长模块

src/modules/parent/data-access.ts234 行)

行号范围 问题类别 严重程度 问题描述 改进建议
59-105 架构违规 P1 getChildBasicInfo 直接查询 usersgradesclassEnrollmentsclasses 通过 users/data-access.getUserProfileclasses/data-access 等接口查询
58 TS规范 P2 getChildBasicInfo 缺少显式返回类型标注 标注返回类型
30 TS规范 P2 (day === 0 ? 7 : day) as 1 | 2 | 3 | 4 | 5 | 6 | 7 使用 as 断言 使用类型守卫 function isWeekday(n: number): n is 1|2|3|4|5|6|7
58-117 性能 P2 getChildBasicInfo 串行查询 student → grade → enrollment → class 使用 JOIN 合并为单次查询,或用 Promise.all 并行化

src/modules/parent/types.ts57 行)

合规,无违规问题。


3.15 audit审计模块

src/modules/audit/actions.ts212 行)

行号范围 问题类别 严重程度 问题描述 改进建议
6, 70-100, 120-146, 166-192 架构违规 P2 Excel 导出逻辑内联在 actions 层 新建 audit/export.ts,将 Excel 构建逻辑迁移
63-205 架构违规 P2 三个导出 Action 结构高度重复 抽取通用 buildExcelSheet(name, columns, rows) 辅助函数
207-212 架构违规 P2 formatDateForFile 工具函数定义在 actions.ts 中 迁移到 shared/lib/utils.tsaudit/utils.ts
24-61 Server Action规范 P2 getDataChangeLogsAction 参数 params 未使用 Zod 验证 新增 DataChangeLogQueryParamsSchema
63-205 Server Action规范 P2 三个导出 Action 参数未使用 Zod 验证 新增对应 Zod schema

src/modules/audit/data-access.ts260 行)

行号范围 问题类别 严重程度 问题描述 改进建议
18 TS规范 P2 toIso 缺少显式返回类型标注 标注为 (d: Date) => string
23 TS规范 P2 clampPageSize 缺少显式返回类型标注 标注为 (size?: number) => number
28 TS规范 P2 clampPage 缺少显式返回类型标注 标注为 (page?: number) => number
40, 95, 158 TS规范 P2 const conditions = [] 隐式 any[] 标注 drizzle 条件类型
75 TS规范 P2 r.status as "success" | "failure" 使用 as 断言 使用类型守卫
122 TS规范 P2 r.action as "signin" | "signout" | "signup" 使用 as 断言 使用类型守卫
123 TS规范 P2 r.status as "success" | "failure" 使用 as 断言 使用类型守卫
186 TS规范 P2 r.action as "create" | "update" | "delete" 使用 as 断言 使用类型守卫
50-86, 104-137, 168-202 安全/质量 P2 getAuditLogs/getLoginLogs/getDataChangeLogs 使用 try-catch 吞错误返回空数组 至少 console.error 记录错误
235-240 逻辑错误 P1 getAuditLogsForExport 注释标注 "no pagination cap",但实际调用 getAuditLogs({ page: 1, pageSize: 100 }),最多只返回 100 条,导出数据不完整 实现真正的无分页查询,或循环分页拉取全部数据
245-250 逻辑错误 P1 getLoginLogsForExport 同上问题,最多 100 条 同上
255-260 逻辑错误 P1 getDataChangeLogsForExport 同上问题,最多 100 条 同上

src/modules/audit/types.ts91 行)

合规,无违规问题。


3.16 elective选修课模块

src/modules/elective/data-access.ts

行号范围 问题类别 严重程度 问题描述 改进建议
117 TS规范 P1 params.status as ElectiveCourseStatus 使用 as 断言 直接使用 params.status,无需断言
78 TS规范 P2 buildCourseSelect = () => 箭头函数缺少显式返回类型标注 添加返回类型标注
136-138, 150-152 代码质量 P2 catch { return [] / null } 静默吞掉异常 至少 console.error 记录错误

src/modules/elective/data-access-selections.ts

行号范围 问题类别 严重程度 问题描述 改进建议
102 TS规范 P1 r.status as CourseSelectionStatus 使用 as 断言 应通过类型守卫或直接赋值
114 TS规范 P1 r.courseStatus as ElectiveCourseStatus | null 同上 同上
59, 117 TS规范 P2 buildCourseSelectselectionDetailSelect 箭头函数缺少显式返回类型 添加返回类型标注
7-14 架构违规 P1 直接导入并查询 classesclassEnrollments 通过 @/modules/classes/data-access 暴露的函数获取
全文件 性能 P2 均未用 React.cache() 包裹 对读函数用 cache() 包裹

src/modules/elective/data-access-operations.ts

行号范围 问题类别 严重程度 问题描述 改进建议
18-34 性能 P2 runLottery 中先查 course 再查 selections两次独立查询串行 await Promise.all 并行
46-71 性能 P1 for 循环内逐条 await db.update()N 名学生产生 N 次 DB 往返 拆分为两组 IDinArray 执行 2 次批量 UPDATE
46-76 安全/数据完整性 P1 runLottery 多步更新未包裹事务 使用 db.transaction() 包裹整个摇号流程
86-112 性能 P2 selectCourse 中查 course 和查 existing selection 两次独立查询串行 Promise.all 并行
158-182 性能 P2 dropCourse 中查 existing 和查 course 串行 并行化独立查询

src/modules/elective/schema.ts20-24 行)

行号范围 问题类别 严重程度 问题描述 改进建议
20-24 TS规范 P2 emptyToNulloptionalStringToNull 箭头函数缺少显式返回类型 添加返回类型

src/modules/elective/types.ts

未发现违规问题。

src/modules/elective/actions.ts

行号范围 问题类别 严重程度 问题描述 改进建议
278-294 Server Action规范 P2 getStudentSelectionsAction(studentId: string) 直接接收参数,未经 Zod 校验 studentId 用 Zod 校验

3.17 proctoring监考模块

src/modules/proctoring/actions.ts

行号范围 问题类别 严重程度 问题描述 改进建议
11-13, 79-84 架构违规 P0 actions.ts编排层直接导入 dbexamSubmissions 并执行 DB 查询 将 submission 归属校验逻辑移至 data-access.ts
3 TS规范 P1 import { ActionState } 应为 import type { ActionState } 改为 import type { ActionState }
39 TS规范 P1 as z.ZodType<ProctoringEventType> 使用 as 断言 直接使用 z.enum([...]) 推导
63 Server Action规范 P1 recordProctoringEventAction 使用 requireAuth() 而非 requirePermission() 使用 requirePermission(Permissions.EXAM_SUBMIT)
全文件 Server Action规范 P2 recordProctoringEventAction 未调用 revalidatePath 添加 revalidatePath 刷新监考面板相关路径

src/modules/proctoring/data-access.ts

行号范围 问题类别 严重程度 问题描述 改进建议
127 TS规范 P1 row.event.eventType as ProctoringEventType 使用 as 断言 drizzle enum 列类型已是字面量联合,应直接匹配
152 TS规范 P1 row.eventType as ProctoringEventType 同上 同上
208 TS规范 P1 stat.eventType as ProctoringEventType 同上 同上
290 TS规范 P1 row.eventType as ProctoringEventType 同上 同上
313 TS规范 P1 (row.submission.status ?? null) as StudentProctoringStatus["submissionStatus"] 使用 as 断言 用类型守卫函数校验 status 值
378 TS规范 P1 row.event.eventType as ProctoringEventType 同上 同上
5-9 架构违规 P1 直接导入 examsexamSubmissions 通过 @/modules/exams/data-access 暴露的函数获取
188-193 性能 P2 getExamProctoringSummary 中对 submissions 数组调用两次 .filter() 用单次 for 循环同时统计两个计数
178-223 性能 P2 getExamProctoringSummary 中 submissions 查询、eventStats 查询、studentEventCounts 查询三者相互独立,却串行 await Promise.all 并行执行

src/modules/proctoring/types.ts

未发现违规问题。


3.18 diagnostic诊断模块

src/modules/diagnostic/actions.ts

行号范围 问题类别 严重程度 问题描述 改进建议
26-33, 54-61, 82-85, 105-108 Server Action规范 P1 generateStudentReportActiongenerateClassReportActionpublishReportActiondeleteReportAction 均使用手动 typeof + length 校验,未使用 Zod schema 新建 schema.ts,定义 Zod schema
121-133, 136-148 Server Action规范 P2 getDiagnosticReportsAction(params)getDiagnosticReportByIdAction(id) 直接接收参数,未经 Zod 校验 对入参用 Zod 校验
123, 138 TS规范 P2 Promise<ActionState<Awaited<ReturnType<typeof getDiagnosticReports>>>> 类型表达式过于复杂 在 types.ts 中定义具名返回类型并导入

src/modules/diagnostic/data-access.ts

行号范围 问题类别 严重程度 问题描述 改进建议
9, 13 架构违规 P1 直接导入 examSubmissionssubmissionAnswersquestionsToKnowledgePoints 通过对应模块的 data-access 函数获取数据
116 性能 P2 answers.find((a) => a.questionId === link.questionId)for 循环内调用O(n×m) 复杂度 先用 new Map(answers.map(a => [a.questionId, a])) 构建 Map
125-146 性能 P2 for 循环内逐条 await db.insert().onDuplicateKeyUpdate()N 个知识点产生 N 次 DB 往返 Promise.all 并行化,或构建批量 upsert
80-81 性能 P2 allMastery.filter(m => m.masteryLevel >= 80)allMastery.filter(m => m.masteryLevel < 60) 两次遍历同一数组 合并为单次循环
全文件 性能 P2 所有读函数均未用 React.cache() 包裹 cache() 包裹读函数

src/modules/diagnostic/data-access-reports.ts

行号范围 问题类别 严重程度 问题描述 改进建议
29-31 TS规范 P1 (r.strengths as string[] | null)(r.weaknesses as string[] | null)(r.recommendations as string[] | null) 三处 as 断言 编写类型守卫 isStringArray(v: unknown): v is string[]
59, 103 性能/规范 P2 const { createId } = await import("@paralleldrive/cuid2") 在函数内部动态导入 改为顶层静态导入
201-202 代码质量 P2 void round2 — 为抑制未使用警告而保留无用函数 直接删除 round2 函数定义及 void round2
172-180 性能 P2 getDiagnosticReportById 中先查 report再单独查 generator 名称,两次串行查询 将 generator 查询合并到主查询的 JOIN 中
全文件 性能 P2 getDiagnosticReportsgetDiagnosticReportById 未用 React.cache() 包裹 cache() 包裹
107 代码质量 P2 studentId: generatedBy 班级报告将生成者 ID 存入 studentId 字段 考虑将 studentId 改为可空,或使用单独的 classId 字段

src/modules/diagnostic/types.ts

未发现违规问题。


3.19 dashboard仪表盘模块

src/modules/dashboard/data-access.ts & types.ts

无违规问题。正确使用 Promise.all 并行获取多模块数据,正确使用 cache(),正确通过各模块 data-access 通信。是除 textbooks 外的另一个标杆模块。


3.20 files文件模块

src/modules/files/data-access.ts

行号范围 问题类别 严重程度 问题描述 改进建议
190 TS规范 P1 const conditions = [] 缺少类型标注TypeScript 推断为 never[]any[] 改为 const conditions: SQL[] = []
204 TS规范 P1 or(...)! 使用非空断言 显式处理 undefined
160-170 性能 P2 deleteFileAttachments 回退逻辑中 for 循环内逐条 await db.delete() Promise.allSettled 并行删除
53-55, 70-72, 95-97, 114-116, 131-133, 143-145, 219-221, 248-250, 264-266 代码质量 P2 大量 catch { return null / [] / false } 静默吞掉异常,共 9 处 至少 console.error 记录错误信息
全文件 性能 P2 所有读函数均未用 React.cache() 包裹 cache() 包裹读函数

src/modules/files/types.ts

未发现违规问题。


3.21 announcements公告模块

src/modules/announcements/data-access.ts186 行)

行号范围 问题类别 严重程度 问题描述 改进建议
46-47 TS规范 P1 toIso(row.createdAt) as stringas 断言掩盖潜在 null toIso 对非空入参返回 string,拆分为两个函数
59, 62 TS规范 P2 params.status as AnnouncementStatus — 冗余 as 断言 直接使用收窄后的变量
88-90, 118-120 性能/可靠性 P2 catch {} 静默吞掉所有异常 至少记录错误日志
25-26 命名/DRY P2 mapRow 参数中内联定义类型,与 types.ts 重复 导入并复用 types.ts 中的类型

src/modules/announcements/actions.ts231 行)

行号范围 问题类别 严重程度 问题描述 改进建议
217-231 Server Action规范 P2 getAnnouncementsAction 使用 requireAuth() 而非 requirePermission(Permissions.ANNOUNCEMENT_READ) 改为 requirePermission(Permissions.ANNOUNCEMENT_READ)
73-79, 137-143, 159-165, 185-191, 208-214, 224-230 性能/可维护性 P2 6 个 Action 的 try/catch 错误处理块完全相同 提取共享错误处理函数 handleActionError(e)

src/modules/announcements/schema.ts45 行)& types.ts50 行)

符合规范。


3.22 settings设置模块

src/modules/settings/actions.ts205 行)

行号范围 问题类别 严重程度 问题描述 改进建议
8, 64-76, 95-100, 104-113, 123-139, 154-169 架构违规 P1 模块无 data-access.ts 文件actions.ts 直接 import { db } 并执行 DB 查询 新建 data-access.ts,将所有 DB 操作下沉
62-77 Server Action规范 P2 getAiProviderSummaries 返回 Promise<AiProviderSummary[]> 而非 ActionState<T> 移至 data-access.ts 或包装为 ActionState
38-46 架构违规 P2 AiProviderSummary 类型定义在 actions.ts 中 新建 types.ts,将类型移入
48-51 TS规范 P2 ensureUser 是 async 箭头函数,未显式标注返回类型 添加 : Promise<{ id: string }>
53-60 TS规范 P2 normalizeBaseUrl 未显式标注返回类型 添加 : string | null
95-113 性能 P2 upsertAiProviderAction 的更新分支中,count() 查询与 select 查询是两个独立查询,串行执行 Promise.all 并行化
120, 152 命名规范 P2 nextIsDefaultmakeDefault 布尔变量前缀不规范 改为 isNextDefaultshouldMakeDefault

src/modules/settings/actions-password.ts113 行)

行号范围 问题类别 严重程度 问题描述 改进建议
7, 58-62, 78-81, 83-87, 89-105 架构违规 P1 actions-password.ts 直接 import { db } 并执行 DB 操作,无 data-access.ts 将 DB 操作下沉至 data-access.ts
39-51 Server Action规范 P1 输入通过 String(formData.get(...)) 手动读取,未使用 Zod schema 验证 定义 Zod schema 并 safeParse
30 Server Action规范 P2 changePasswordAction 使用 requireAuth() 而非 requirePermission() 新增 PASSWORD_SELF_CHANGE 权限点并赋给所有角色
58-87 性能 P2 查询 user 和查询 passwordSecurity 是两个独立表的查询,当前串行执行 重构为 Promise.all 并行获取
14-18 TS规范 P2 normalizeBcryptHash 未显式标注返回类型 添加 : string

3.23 layout布局模块

src/modules/layout/config/navigation.ts317 行)

行号范围 问题类别 严重程度 问题描述 改进建议
30-31 TS规范 P2 NavItem.permission 和子项的 permission 均为 string 类型,但项目已有 Permission 类型 导入 Permission 类型并使用
34 架构违规 P2 export type Role = "admin" | "teacher" | "student" | "parent" 定义在 config 文件中 考虑将 Role 类型提升至 @/shared/types

四、跨模块共性问题

4.1 架构违规P0/P1最高优先级

4.1.1 跨模块直接查询 DB 表(最普遍问题)

调用方模块 被查模块表 严重程度
exams questions直写、classes、subjects、grades P0/P1
homework exams5 处、classes、classEnrollments、subjects、users P1
questions knowledgePoints、chapters、textbooks P1
grades classes、classEnrollments、subjects、users P1
classes homeworkAssignments、homeworkSubmissions、exams、classSchedule P0
school actions 层直接 DB 操作) P0
scheduling usersactions 层) P0
messaging classEnrollments、classes P1
notifications classes、classEnrollments、messaging循环 P0/P1
parent users、grades、classEnrollments、classes P1
proctoring exams、examSubmissions P0/P1
diagnostic examSubmissions、submissionAnswers、questionsToKnowledgePoints P1
elective classes、classEnrollments P1

统一修复方案:在各模块 data-access 暴露跨模块查询接口,消除直查。

4.1.2 messaging↔notifications 循环依赖

  • messaging/data-access.tsmessageNotifications
  • notifications/data-access.ts 反向 import messaging 的 notification-preferencestypes
  • notifications/channels/in-app-channel.ts 动态 import messaging 的 data-access

修复方案:将 messageNotificationsnotificationPreferences 表所有权移交 notifications 模块。

4.1.3 actions 层直接操作 DB

模块 文件 问题
school actions.ts 所有 mutation 直接操作 DB
scheduling actions.ts 直接查询 users 表
proctoring actions.ts 直接查询 examSubmissions 表
classes actions.ts 直接查询 grades、classes 表做权限校验
settings actions.ts、actions-password.ts 无 data-access.ts直接 DB 操作
users actions.ts updateUserProfile 直接 db.update

统一修复方案DB 操作必须下沉到 data-access.ts。

4.2 TypeScript 规范违规P1

4.2.1 as 断言滥用(非从 unknown 转换)

模块 文件 行号
exams data-access.ts 76, 160, 361, 108, 172
exams actions.ts 270, 349-351
homework data-access.ts 39, 124, 226, 314, 392, 467, 645
homework stats-service.ts 220
textbooks actions.ts 54-58, 92-98, 154, 219-221, 259-26114 处)
textbooks data-access.ts 51
classes data-access.ts 240, 266, 561
classes data-access-admin.ts 135, 259, 349
classes data-access-schedule.ts 54, 93
classes data-access-stats.ts 250, 261, 512, 523
classes actions.ts 538, 582
course-plans data-access.ts 149
messaging data-access.ts 80, 74, 85
notifications channels/in-app-channel.ts 54非法
notifications channels/sms-channel.ts 32
audit data-access.ts 75, 122, 123, 186
elective data-access.ts 117
elective data-access-selections.ts 102, 114
proctoring data-access.ts 127, 152, 208, 290, 313, 378
proctoring actions.ts 39
diagnostic data-access-reports.ts 29-31
parent data-access.ts 30
announcements data-access.ts 46-47, 59, 62
attendance data-access.ts 195Record<string, unknown>

统一修复方案:用类型守卫函数或 Zod 校验替换 as 断言。

4.2.2 非空断言 !

模块 文件 行号
exams ai-pipeline.ts 464, 657, 665, 666, 671
homework export.ts 154
textbooks data-access.ts 42, 71
classes data-access.ts 287, 567
classes data-access-admin.ts 369
classes data-access-students.ts 102
scheduling data-access.ts 140, 221, 222
scheduling actions.ts 115
scheduling auto-scheduler.ts 144, 145
messaging data-access.ts 97, 117, 163
files data-access.ts 204

统一修复方案:用显式判空处理替换非空断言。

4.2.3 函数返回值未显式标注

模块 文件 函数
classes data-access.ts isDuplicateInvitationCodeError, generateInvitationCode, normalizeSortText, parseFirstInt, compareGradeLabel, compareClassLike
classes data-access-admin.ts getManagedGrades
scheduling data-access.ts getAdminClassesForScheduling, getTeachersForScheduling, getClassroomsForScheduling, getClassSubjectsForScheduling
users data-access.ts normalizeRoleName, resolvePrimaryRole
users user-service.ts normalizeBcryptHash
messaging data-access.ts mapMessage, mapNotification
messaging notification-preferences.ts toIso, mapRow
notifications dispatcher.ts getSenders, selectChannels
notifications channels/email-channel.ts getEmailConfig, getTypeColor, buildHtmlContent, escapeHtml
notifications channels/sms-channel.ts getSmsConfig, buildTemplateParams
notifications channels/wechat-channel.ts getWechatConfig, buildTemplateData
audit data-access.ts toIso, clampPageSize, clampPage
parent data-access.ts getChildBasicInfo
announcements
settings actions.ts ensureUser, normalizeBaseUrl
settings actions-password.ts normalizeBcryptHash
elective data-access.ts buildCourseSelect
elective data-access-selections.ts buildCourseSelect, selectionDetailSelect
elective schema.ts emptyToNull, optionalStringToNull
questions actions.ts getQuestionsAction

统一修复方案:所有函数(特别是箭头函数)必须显式标注返回类型。

4.2.4 import type 未使用

模块 文件 行号
exams actions.ts 4
questions actions.ts 7
textbooks actions.ts 18
proctoring actions.ts 3

统一修复方案:仅用于类型的导入必须使用 import type

4.3 Server Action 规范违规

4.3.1 requireAuth() 替代 requirePermission()

模块 文件 Action
users actions.ts updateUserProfile
messaging actions.ts getNotificationsAction, markNotificationAsReadAction, markAllNotificationsAsReadAction, getNotificationPreferencesAction, updateNotificationPreferencesAction
proctoring actions.ts recordProctoringEventAction
announcements actions.ts getAnnouncementsAction
settings actions-password.ts changePasswordAction

统一修复方案:改为 requirePermission(Permissions.XXX)

4.3.2 缺少 Zod 验证

模块 文件 问题
textbooks actions.ts 完全无 schema.ts所有 Action 无 Zod 验证
classes actions.ts 完全无 schema.ts使用手动 typeof 检查
diagnostic actions.ts 4 个 Action 使用手动 typeof 校验
settings actions-password.ts 输入手动读取,无 Zod
messaging actions.ts 多个 Action 参数未 Zod 校验
notifications actions.ts 多个 Action 参数未 Zod 校验
audit actions.ts 多个 Action 参数未 Zod 校验
users actions.ts updateUserProfile 无 Zod
elective actions.ts getStudentSelectionsAction 无 Zod

统一修复方案:新建/补充 schema.ts所有 Action 输入用 Zod 验证。

4.3.3 缺少 revalidatePath

模块 文件 Action
course-plans actions.ts deleteCoursePlanItemAction, toggleCoursePlanItemCompletedAction
proctoring actions.ts recordProctoringEventAction

4.3.4 未返回 ActionState<T>

模块 文件 Action
questions actions.ts getQuestionsAction, getKnowledgePointOptionsAction
users actions.ts updateUserProfile返回 Promise
settings actions.ts getAiProviderSummaries返回原始数组

4.4 重复代码

重复内容 出现位置 修复方案
normalizeRoleName users/data-access.ts、shared/lib/role-utils.ts 复用 shared
normalizeBcryptHash users/user-service.ts、settings/actions-password.ts、shared/lib/bcrypt-utils.ts 复用 shared
toNumber/normalize/buildScopeClassFilter grades/data-access.ts、data-access-analytics.ts、data-access-ranking.ts 提取到 grades/utils.ts
serializeDate scheduling/data-access.ts、attendance/data-access.ts、attendance/data-access-stats.ts 提取到 shared
toIso announcements/data-access.ts、messaging/data-access.ts、messaging/notification-preferences.ts、audit/data-access.ts 提取到 shared
try/catch 错误处理块 announcements/actions.ts6 处) 提取 handleActionError(e)
Excel 导出逻辑 audit/actions.ts3 处) 抽取 buildExcelSheet

4.5 错误吞没(静默 catch

模块 文件 处数
school data-access.ts 6
classes data-access-admin.ts、data-access-students.ts 多处
course-plans data-access.ts 2
announcements data-access.ts 2
files data-access.ts 9
audit data-access.ts 3
elective data-access.ts 2

统一修复方案:至少 console.error 记录错误,或向上抛出由调用方处理。

4.6 不可达代码

模块 文件 行号
classes data-access.ts 297-299throw 后 return id
classes data-access-admin.ts 380-382throw 后 return id
questions actions.ts 158-163, 170-175catch 块两分支都 throw e

五、性能优化专项react-best-practices

依据 Vercel React Best Practices 规则集,识别以下性能优化机会:

5.1 CRITICAL消除瀑布流async-*

5.1.1 async-parallel:独立操作用 Promise.all()

模块 文件 行号 问题 修复
classes data-access.ts 120-127 getAccessibleClassIdsForTeacher 两个独立 DB 查询串行 Promise.all
settings actions.ts 95-113 upsertAiProviderAction count 与 select 串行 Promise.all
settings actions-password.ts 58-87 user 与 passwordSecurity 查询串行 Promise.all
elective data-access-operations.ts 18-34 runLottery course 与 selections 串行 Promise.all
elective data-access-operations.ts 86-112 selectCourse course 与 existing 串行 Promise.all
elective data-access-operations.ts 158-182 dropCourse existing 与 course 串行 Promise.all
proctoring data-access.ts 178-223 getExamProctoringSummary 三个独立查询串行 Promise.all
diagnostic data-access-reports.ts 172-180 getDiagnosticReportById report 与 generator 串行 合并 JOIN 或 Promise.all
parent data-access.ts 58-117 getChildBasicInfo 4 个串行查询 JOIN 或 Promise.all

5.1.2 async-defer-await:将 await 移到实际使用的分支

无明显违规,多数文件已正确处理。

5.2 HIGH服务端性能server-*

5.2.1 server-cache-react:用 React.cache() 做请求内去重

模块 文件 缺失 cache() 的函数
grades data-access.ts getGradeRecords, getGradeRecordById, getClassGradeStats
grades data-access-analytics.ts getClassComparison, getGradeTrends
grades data-access-ranking.ts getClassRanking, getStudentRanking
elective data-access-selections.ts getCourseSelections, getStudentSelections, getStudentGradeId, getAvailableCoursesForStudent
diagnostic data-access.ts getStudentMastery, getStudentMasterySummary, getClassMasterySummary, getKnowledgePointStats
diagnostic data-access-reports.ts getDiagnosticReports, getDiagnosticReportById
files data-access.ts getFileAttachment, getFileAttachmentsByTarget, getFileAttachmentsByUploader, getAllFileAttachments, getFileAttachmentsWithFilters, getFileStats, getFileAttachmentsByIds
proctoring data-access.ts 多个查询函数

标杆exams、homework、questions、textbooks、dashboard、announcements 已正确使用 cache() ✓。

5.2.2 server-after-nonblocking:用 after() 做非阻塞操作

模块 文件 行号 问题
school actions.ts 188, 219, 235 await logAudit(...) 阻塞响应

修复:使用 Next.js after() 将审计日志改为非阻塞。

5.2.3 server-serialization:最小化传给客户端组件的数据

需结合前端组件审查,本次后端核查未深入。

5.3 MEDIUMJavaScript 性能js-*

5.3.1 js-set-map-lookups:用 Set/Map 做 O(1) 查找

模块 文件 行号 问题
grades data-access-analytics.ts 133-136 scope.classIds.includes(c.id) — O(n) 查找
diagnostic data-access.ts 116 answers.find(...) 在 for 循环内 — O(n×m)

修复:将数组转为 Set/Map 后用 .has() / .get()

5.3.2 js-combine-iterations:合并多次 filter/map 为一次循环

模块 文件 行号 问题
grades data-access.ts 248-252 两次 if 判断遍历同一数组
grades data-access-analytics.ts 180-181, 238-239 两次 filter 遍历同一数组
grades data-access-ranking.ts 100, 102 findIndex 和 find 查找同一元素
diagnostic data-access.ts 80-81 两次 filter 遍历同一数组
proctoring data-access.ts 188-193 两次 filter 统计 submissions

5.3.3 js-early-exit:函数早返回

多数文件已正确处理。

5.3.4 动态 import 改静态 import

模块 文件 行号 问题
grades data-access.ts 148, 172 await import("@paralleldrive/cuid2") 函数内动态导入
diagnostic data-access-reports.ts 59, 103 同上

修复:改为文件顶部静态 import { createId } from "@paralleldrive/cuid2"

5.4 性能问题汇总(按影响排序)

优先级 问题 影响范围
CRITICAL grades N+1 查询getClassComparison 大班级成绩对比性能差
HIGH 循环内串行 await db.update/inserthomework/data-access-write.ts、elective/data-access-operations.ts、diagnostic/data-access.ts、course-plans/data-access.ts 批量操作慢
HIGH 大量读函数未用 React.cache()grades、elective、diagnostic、files、proctoring 请求内重复查询
MEDIUM 独立查询未并行化9 处) 响应时间累加
MEDIUM 动态 import3 处) 每次调用有开销
LOW 重复 filter 遍历5 处) 微小性能损失
LOW O(n) 查找代替 O(1)2 处) 微小性能损失

六、优先修复路线图

第一阶段P0 严重问题(立即修复)

  1. exams/data-access.tspersistAiGeneratedExamDraft 改为调用 questions data-access
  2. exams/data-access.tsgetExams/getExamById 改为通过 classes data-access 获取 gradeId
  3. questions/schema.tsz.any()z.unknown()
  4. questions/actions.tsgetQuestionsActiongetKnowledgePointOptionsAction 包装为 ActionState
  5. textbooks/actions.ts:新建 schema.ts添加 Zod 验证;清理 14 处 as 断言
  6. grades/data-access-analytics.tsgetClassComparison N+1 查询重构为 inArray 批量查询
  7. classes/data-access-stats.ts、data-access-students.ts:移除对 homework/exams 表的直接查询
  8. school/actions.ts:所有 DB 操作下沉到 data-access.ts
  9. proctoring/actions.tsDB 查询下沉到 data-access.ts
  10. messaging↔notifications:将 messageNotificationsnotificationPreferences 表所有权移交 notifications 模块
  11. notifications/channels/in-app-channel.ts:54:修复非法 as 断言
  12. users/user-service.ts:13:移除硬编码弱密码 "123456"
  13. users/actions.tsupdateUserProfile 整改(权限+下沉+返回类型)
  14. scheduling/data-access.ts4 个函数补充返回类型标注

第二阶段P1 重要问题(尽快修复)

  1. 跨模块直查 DB:在各模块 data-access 暴露跨模块查询接口,消除直查(涉及 exams、homework、questions、grades、classes、messaging、notifications、parent、proctoring、diagnostic、elective
  2. as 断言清理:全局替换为类型守卫(涉及 20+ 文件60+ 处)
  3. requireAuthrequirePermissionusers、messaging、proctoring、announcements、settings 共 8 处
  4. import type 修正exams、questions、textbooks、proctoring 共 4 处
  5. 动态 import 改静态grades、diagnostic 共 3 处
  6. grades/data-access.ts:249:除零 bug 守卫
  7. audit/data-access.ts导出函数数据截断问题3 处)
  8. elective/data-access-operations.tsrunLottery 加事务包裹 + 批量更新
  9. diagnostic/actions.ts:新建 schema.ts用 Zod 替代手动校验
  10. classes 模块:新建 schema.ts用 Zod 替换 actions.ts 中的手动校验
  11. course-plans/actions.ts:补齐 revalidatePath 调用2 处)
  12. homework/data-access-write.ts:305-311gradeHomeworkAnswers 加事务包裹
  13. users/user-service.tsbatchImportUsers 加事务包裹
  14. 不可达代码清理classes/data-access.ts:297-299、classes/data-access-admin.ts:380-382

第三阶段P2 优化(迭代修复)

  1. React.cache() 包装grades、elective、diagnostic、files、proctoring 读函数添加 cache()
  2. Promise.all 并行化9 处独立查询串行执行
  3. after() 非阻塞审计日志school/actions.ts3 处)
  4. 错误吞没清理school、classes、course-plans、announcements、files、audit、elective 共 30+ 处静默 catch
  5. 非空断言 ! 清理20+ 处替换为显式判空
  6. 函数返回类型补齐30+ 个箭头函数
  7. 重复代码提取normalizeRoleName、normalizeBcryptHash、toIso、serializeDate、toNumber/normalize、handleActionError、buildExcelSheet
  8. 合并 filter 遍历5 处
  9. Set/Map 查找优化2 处
  10. 架构文档同步exams/actions.ts 行数、settings 导出函数列表、P2-11 状态、announcements 依赖关系
  11. exams/ai-pipeline.ts 拆分912 行按职责拆分为 4 个文件
  12. layout/navigation.tspermission 字段改用 Permission 类型
  13. notifications/external-sdk.d.ts:安装实际 SDK 后用其自带类型覆盖 any

附录:核查方法说明

核查流程

  1. 架构图优先:先阅读 docs/architecture/004_architecture_impact_map.md,理解模块依赖关系和已知问题
  2. 并行核查:启动 5 个并行搜索代理,分别核查核心教学、教学管理、用户沟通、扩展功能、其他模块
  3. 逐文件审查:每个代理读取所有后端 .ts 文件,对照项目规范逐条核查
  4. 性能规则应用:应用 Vercel React Best Practices 的 65 条规则,识别性能优化机会
  5. 结果汇总:合并 5 个代理的核查结果,按严重程度和模块分类整理

核查依据

  • .trae/rules/project_rules.md项目规则架构分层、TS规范、命名、组件、Server Action、Tailwind、安全、提交
  • docs/standards/coding-standards.md:编码规范(详细规范)
  • docs/architecture/004_architecture_impact_map.md:架构影响地图(模块清单、依赖关系、已知问题)
  • docs/architecture/005_architecture_data.jsonAI 友好格式的结构化数据
  • Vercel React Best Practices65 条性能优化规则8 个类别)

未核查范围

  • src/modules/*/components/ 下的前端组件文件
  • src/modules/*/hooks/ 下的 Hook 文件
  • src/shared/ 下的基础设施文件
  • src/app/ 下的路由层文件
  • 测试文件(*.test.ts

如需核查上述范围,请另行指派任务。