班级(classes)模块审计报告
审计时间:2026-06-25
审计范围:src/modules/classes/ 全部 32 个文件 + src/app/(dashboard)/ 下 11 个相关路由分组
架构图依据:docs/architecture/004_architecture_impact_map.md §2.7、docs/architecture/005_architecture_data.json modules.classes 节点
审计基线:项目规则(三层架构、权限校验、i18n、TypeScript 严格模式、文件行数、可测试性)
一、现有实现概要
1.1 文件分布
classes 模块位于 src/modules/classes/,共 32 个文件:
| 层 |
文件数 |
关键文件 |
| Server Actions |
7 |
actions.ts(barrel)+ actions-admin.ts / actions-grade.ts / actions-teacher.ts / actions-invitations.ts / actions-schedule.ts / actions-shared.ts |
| Data-access |
7 |
data-access.ts(聚合)+ data-access-admin.ts / data-access-teacher.ts / data-access-students.ts / data-access-stats.ts / data-access-schedule.ts / data-access-invitations.ts |
| Schema/Types |
2 |
schema.ts(13 个 Zod schema)、types.ts(19 个类型) |
| Components |
21 |
admin-classes-view.tsx / grade-classes-view.tsx / class-list-table.tsx / class-form-dialog.tsx / class-delete-dialog.tsx / class-list-toolbar.tsx / class-form-utils.ts / class-error-boundary.tsx / class-invitation-manager.tsx / class-skeleton.tsx / my-classes-grid.tsx / schedule-view.tsx / schedule-filters.tsx / students-filters.tsx / students-table.tsx + class-detail/ 下 7 个 widget(header/overview-stats/quick-actions/schedule-widget/students-widget/assignments-widget/trends-widget)+ class-detail/edit-class-dialog.tsx |
| Hooks |
2 |
use-class-data.ts、use-class-filters.ts |
1.2 主要数据流
1.3 架构图覆盖完整性评估
| 维度 |
004 文档 |
005 JSON |
一致性 |
| 模块职责 |
✅ §2.7 |
✅ modules.classes.description |
一致 |
| 依赖关系(出向) |
✅ shared/auth/school/homework/scheduling |
✅ dependencyMatrix 5 条边 |
一致 |
| 被依赖关系(入向) |
⚠️ 列出 10 个,遗漏 elective/error-book/adaptive-practice |
✅ 10 条边覆盖完整 |
不一致 |
| 导出函数 |
✅ 17 actions + 33 data-access |
⚠️ exports.actions 漏 3 个邀请码 action;exports.dataAccess 漏 6 个工具函数 |
不一致 |
| 数据库表 |
✅ classes/classSubjectTeachers/classEnrollments/classInvitationCodes |
⚠️ classInvitationCodes 字段未详细登记;classSchedule 的 usedBy 字段未含 scheduling |
部分遗漏 |
| 权限点 |
✅ 6 个 CLASS_* 权限 |
✅ permissions 常量定义完整 |
一致 |
| 路由 |
✅ 11 条路由登记 |
✅ routes 节点登记 |
一致 |
| 文件清单 |
✅ 33 个文件 |
⚠️ modules.classes.files 仅列 21 个,漏 12 个组件文件 |
不一致 |
结论:架构图总体覆盖较完整,但存在 7 处需同步更新(详见第五章)。
二、现存问题与原因分析
2.1 三层架构合规性
问题 A1:data-access.ts 与拆分文件 3 对同名函数重复定义(🔴 P0)
- 位置:
- 现状:
data-access.ts:383-386 同时 export * from "./data-access-*" 与本地 export const,ES 模块语义下本地定义优先,子文件同名导出对聚合入口而言是死代码。
- 违反规则:架构分层规则「data-access 拆分应避免职责重叠」+ DRY 原则。
- 后果:两份实现目前逻辑一致,但任何一方修改都不会自动同步。若消费者直接
import { getStudentScopeData } from "@/modules/classes/data-access-students",会得到另一份实现,是高风险维护陷阱。
问题 A2:组件使用绝对路径导入本模块 actions(🟢 P2)
- 位置:class-invitation-manager.tsx:30-32
- 现状:
import { createClassInvitationCodeAction } from "@/modules/classes/actions",而 my-classes-grid.tsx、admin-classes-view.tsx 等同模块其他组件使用 "../actions" 相对路径。
- 违反规则:编码规范一致性。
- 后果:模块迁移/重命名成本上升。
2.2 权限校验
问题 B1:listClassInvitationCodesAction 无班级归属校验(🔴 P0 越权漏洞)
- 位置:actions-invitations.ts:312-351
- 现状:
- 违反规则:安全规范「data-access 查询是否结合当前用户权限过滤(防越权)」+ Server Action 规范。
- 后果:教师 A 可通过传入教师 B 的 classId 枚举其邀请码(含 code 字符串),可能引发越权获取加入凭证,破坏邀请码体系的安全性。
问题 B2:3 个 schedule action 无班级归属校验(🔴 P0 越权漏洞)
- 位置:actions-schedule.ts:21-59(create)、61-101(update)、103-122
- 现状:3 个 action 仅调用
requirePermission(CLASS_SCHEDULE) 后直接调用 scheduling 模块 data-access,未校验当前用户对 classId 的归属。
- 违反规则:安全规范越权防护。
- 后果:教师 A 可为教师 B 的班级添加/修改/删除课表项,破坏排课数据完整性。
问题 B3:教师 update/delete/enroll action 未在 actions 层做归属校验(🟡 P1)
- 位置:actions-teacher.ts:79-122(update)、125-146(delete)、actions-invitations.ts:21-49、353-377、383-440
- 现状:actions 层仅
requirePermission,依赖 data-access 内部 getTeacherIdForMutations() + eq(classes.teacherId, teacherId) 校验。
- 违反规则:Server Action 规范「权限校验应在 actions 层完成」。
- 后果:管理员(拥有 CLASS_UPDATE 权限)调用时,因 data-access 内部强制按 teacherId 过滤而失败,错误信息为 "Teacher not found" 不友好;如未来重构 data-access 暴露 admin 路径,归属校验会被跳过。
问题 B4:data-access 中 7 处硬编码角色名字符串(🟡 P1)
- 位置:
- 违反规则:命名规范「常量:UPPER_SNAKE_CASE」+ DRY。
- 后果:若角色名变更(中英切换、复数化),需修改 7 处;魔法字符串降低可读性。
问题 B5:student 三个页面未调用 requirePermission 显式声明权限点(🟡 P1)
- 位置:
- 现状:仅
getCurrentStudentUser() 软校验学生身份,未显式声明所需权限点;[classId] 页面在权限不足时返回 notFound(),错误语义混淆(404 vs 403)。
- 违反规则:Server Action 必须使用
requirePermission()。
- 后果:权限审计与文档化困难;404/403 错误语义混淆影响用户体验与监控告警。
2.3 国际化(i18n)
问题 C1:class-detail/ 子组件普遍硬编码英文(🟡 P1)
- 位置:
- class-assignments-widget.tsx:40,46,64,84,88,101
- class-overview-stats.tsx:28,33,39,45
- class-quick-actions.tsx:26,32,36
- class-schedule-widget.tsx:17,102,110
- class-students-widget.tsx:36,41
- class-trends-widget.tsx:41-55,145,164,174,182,188,282,288,301,392
- 现状:8 个详情子组件几乎全部使用硬编码英文字符串。
- 违反规则:i18n 强制要求 + 架构图 004:998 已声明"13 个组件全部接入 i18n"——与现状不一致。
- 后果:详情页完全无法中文化,与 K12 中文产品定位严重冲突;架构图存在错误声明。
问题 C2:schedule-view / schedule-filters / students-filters 硬编码英文(🟡 P1)
- 位置:
- schedule-view.tsx:111,117,165,166,180,192,310,343,348,357,369,386,435,448,469,489,505-508
- schedule-filters.tsx:111,117,164,171,180,192
- students-filters.tsx:81,110,141,169,173,174,197,204,211
- 违反规则:i18n 强制要求。
- 后果:教师端课表/学生管理页全部英文,破坏产品一致性。
问题 C3:所有 actions 返回的 message 为英文硬编码(🟡 P1)
问题 C4:30+ 个 error.tsx 使用硬编码中文文案(🟡 P1)
- 位置:
src/app/(dashboard)/ 下 30 处 error.tsx(含 admin/school/classes/error.tsx、management/grade/classes/error.tsx 等)
- 示例:admin/school/classes/error.tsx:12-16
title="页面加载失败" / description="抱歉,页面加载时发生了意外错误。请稍后重试。"
- 违反规则:i18n 强制要求。
- 后果:英文用户在错误页仍看到中文,破坏语言一致性;30+ 处重复字符串维护成本高。
问题 C5:DEFAULT_CLASS_SUBJECTS 与 excludeSubjects 业务常量硬编码中文(🟡 P1)
- 位置:
- 违反规则:DRY(两份科目清单)+ i18n(业务规则硬编码字符串)。
- 后果:与
subjects 表查询重复;不同学校配置无法适配;excludeSubjects 未在架构图记录。
问题 C6:getSubjectColor 用英文匹配中文科目(🔴 P0 功能 bug)
- 位置:schedule-view.tsx:186-195
- 现状:
- 问题:
DEFAULT_CLASS_SUBJECTS 是中文("数学"、"英语"等),但 getSubjectColor 用英文 'math'/'english' 匹配,所有中文科目都会落到 default 分支,颜色视觉分组完全失效。
- 违反规则:i18n + 功能正确性。
- 后果:课表颜色视觉分组完全失效,不仅是 i18n 问题。
2.4 错误处理
问题 D1:catch 块未记录错误,仅显示 toast(🟡 P1)
- 位置:10 处
- 现状:
} catch { toast.error(t("list.failedCreate")) }
- 违反规则:错误处理最佳实践。
- 后果:服务端 500、网络错误、权限错误全部显示同一文案,开发者无法从用户截图定位错误;线上排查困难。
问题 D2:data-access 内 catch 静默返回空数组(🟡 P1)
- 位置:
- 问题:
getTeacherClasses 失败时返回空数组,会让教师看到"无班级"假象,区分不出"数据库错误"与"无数据"。
- 违反规则:错误处理最佳实践。
- 后果:教师班级列表假性空数据,难以排查。
问题 D3:actions 层错误处理两套风格混用(🟡 P1)
- 位置:
- 违反规则:编码规范一致性。
- 后果:权限拒绝场景下风格 A 会
throw e 冒泡到 Next.js 错误边界(用户体验差),风格 B 会转为结构化失败;维护成本高。
问题 D4:teacher/classes/my/[id] 缺 loading.tsx 和 error.tsx(🟡 P1)
- 位置:
src/app/(dashboard)/teacher/classes/my/[id]/
- 现状:页面内部 4 个
Promise.all 并行数据获取,但完全没有 loading.tsx 和 error.tsx。
- 违反规则:项目规则「学生路由必须包含 loading.tsx 和 error.tsx」+ 企业级规范。
- 后果:无骨架屏感知性能差;任一 data-access 抛错冒泡至上层;
notFound() 触发时展示默认 404 与站点风格不一致。
问题 D5:10 个页面缺 error.tsx(🟡 P1)
- 位置:teacher/classes/my、teacher/classes/schedule、teacher/classes/students、student/learning/courses、student/learning/courses/[classId]、student/schedule 等
- 违反规则:企业级规范要求主要路由必须有 error.tsx。
- 后果:错误上下文丢失,错误冒泡至上层。
2.5 类型安全
问题 E1:formData.get 强转 string 应使用类型守卫(🟢 P2)
- 位置:actions-admin.ts:93、actions-grade.ts:98
- 现状:
formData.get("subjectTeachers") as string | null
- 违反规则:禁止
as 断言(除类型收窄外)。
- 后果:若前端意外提交
File 对象(如通过 FormData.append 上传文件),parseSubjectTeachers 会因 typeof raw !== "string" 返回 null 而静默丢弃数据。
问题 E2:data-access-invitations.ts 中两处 string → union 强转(🟢 P2)
- 位置:data-access-invitations.ts:274、363
- 现状:
record.status as ValidationResult["reason"] / status: row.status as InvitationCodeStatus
- 违反规则:禁止
as 断言。
- 后果:DB 中出现意外值(如 "pending")不会触发类型错误,运行时返回错误 reason。
问题 E3:class-trends-widget.tsx 中 as string[] 应使用类型守卫(🟢 P2)
- 位置:class-trends-widget.tsx:129
- 现状:
Array.from(new Set(assignments.map(a => a.subject).filter(Boolean))) as string[]
- 违反规则:禁止
as 断言。
- 后果:
filter(Boolean) 在 TypeScript 中不会收窄类型,跳过空值检查。
问题 E4:14 个组件事件处理函数缺 Promise 返回类型(🟢 P2)
- 位置:my-classes-grid.tsx(4 处)、schedule-filters.tsx、schedule-view.tsx(4 处)、students-filters.tsx、students-table.tsx、class-invitation-manager.tsx(3 处)、edit-class-dialog.tsx
- 违反规则:函数返回值必须显式标注,特别是
Promise<T>。
- 后果:若将来函数内部
return 一个值(如返回 boolean 表示是否成功),调用方无类型提示。
2.6 文件大小
问题 F1:schedule-view.tsx 527 行超出组件 500 行建议(🟡 P1)
- 位置:schedule-view.tsx
- 现状:同时承担"周历视图渲染 + 创建对话框 + 编辑对话框 + 删除确认对话框"4 个职责。
- 违反规则:React 组件 ≤ 500 行。
- 后果:可读性差、修改易引入回归。
问题 F2:my-classes-grid.tsx 内含 210 行巨型组件 ClassTicket(🟢 P2)
2.7 组件复用性
问题 G1:3 个 view 的 CRUD handler 几乎重复(🟢 P2)
- 位置:admin-classes-view.tsx:41-95、grade-classes-view.tsx:31-85、schedule-view.tsx:100-158
- 现状:相同的 try/catch + toast + router.refresh 模式重复 9 次(每个 view 3 个 handler)。
- 违反规则:DRY。
- 后果:错误处理改进(如 D1 加 console.error)需修改 9 处。
2.8 可测试性
问题 H1:纯函数内嵌组件未导出(🟢 P2)
- 位置:
- 违反规则:可测试性「纯逻辑是否与 UI 分离」。
- 后果:业务计算逻辑(环比变化率、课表块定位、颜色映射)无法独立单测;
getSubjectColor 还存在 C6 提到的功能 bug,但因内嵌而难以被发现。
2.9 i18n metadata 缺失
问题 I1:8 个 teacher/student 页面缺 generateMetadata(🟢 P2)
- 位置:teacher/classes/my、teacher/classes/my/[id]、teacher/classes/schedule、teacher/classes/students、student/learning/courses、student/learning/courses/[classId]、student/schedule、parent/children/[studentId]
- 违反规则:页面级 metadata.title 应走 i18n。
- 后果:浏览器标签栏、社交分享卡片等场景文案不本地化,SEO 友好度差。
三、行业差距对比
参考 Google Classroom、钉钉教育、智学网、ClassDojo、PowerSchool 等 K12 班级管理产品的主流设计模式,对比当前实现差距:
3.1 班级列表与详情
| 维度 |
优秀实践 |
当前实现 |
差距 |
| 班级卡片信息密度 |
Google Classroom 卡片含教师头像、学生数、最近活动时间、未读作业数 |
my-classes-grid.tsx 含邀请码、提交率趋势、周历嵌入,信息密度高但未提供"最近活动"时间线 |
缺少"班级最近动态"feed |
| 班级封面图 |
Google Classroom / ClassDojo 支持自定义班级主题图 |
仅色彩区分 |
视觉识别度弱 |
| 班级详情布局 |
智学网采用"Tab 切换(学生/作业/成绩/课表/设置)+ 顶部 sticky header" |
class-detail/ 采用 widget 网格布局 |
widget 平铺在班级数多时滚动疲劳;可考虑 Tab 化 |
| 班级归档 |
Google Classroom 支持"归档班级",归档后只读但保留数据 |
无归档功能 |
学年结束后历史班级污染列表 |
| 班级复制 |
Google Classroom 支持复制班级(含学生/科目配置) |
无 |
新学年建班成本高 |
3.2 学生管理
| 维度 |
优秀实践 |
当前实现 |
差距 |
| 学生加入方式 |
邀请码 + 邮件 + 批量导入 + 班级链接 |
已实现邀请码 + 邮件 + 批量导入 |
缺少"班级加入链接"(点击即加入) |
| 学生列表筛选 |
智学网支持按科目成绩、出勤率、活跃度多维筛选 |
students-filters.tsx 仅按班级 + 状态 |
缺少按学业表现筛选 |
| 学生卡片信息 |
Google Classroom 显示学生头像、最近提交、整体进度 |
students-table.tsx 显示头像+科目成绩 |
缺少"最近提交/整体进度"时间维度 |
| 学生迁移 |
钉钉教育支持"批量迁班"(学年升级时) |
无 |
学年升级时手动逐个调整 |
| 学生邀请码状态可视化 |
ClassDojo 显示邀请码扫描情况(已加入/待加入) |
class-invitation-manager.tsx 显示邀请码列表 |
缺少"已扫码未加入"中间状态 |
3.3 课表
| 维度 |
优秀实践 |
当前实现 |
差距 |
| 课表视图 |
智学网周课表 + 日课表 + 月课表三视图切换 |
schedule-view.tsx 仅周课表 |
缺少日/月视图 |
| 课表冲突检测 |
PowerSchool 在添加时自动检测教室/教师/时段冲突 |
依赖 scheduling 模块外部检测 |
当前 actions-schedule 未触发检测(B2) |
| 课表颜色编码 |
钉钉教育按科目自动配色 |
getSubjectColor 中文失效(C6) |
功能 bug,必须修复 |
| 课表导出/打印 |
智学网支持导出 PDF/Excel、打印 |
无 |
教师打印课表需求未满足 |
| 课表提醒 |
Google Classroom 课前 5 分钟推送提醒 |
无 |
缺少课表提醒集成 |
3.4 多角色协作
| 维度 |
优秀实践 |
当前实现 |
差距 |
| 家长视角班级信息 |
ClassDojo 家长看到班级公告、教师动态、孩子表现 |
parent 仅看到孩子课表 + 班级概览 |
缺少"班级动态 feed" |
| 学生视角班级首页 |
Google Classroom 学生首页是"待办作业流" |
student/learning/courses 是班级列表 |
缺少"班级作业待办流"聚合视图 |
| 跨班级协作 |
钉钉教育支持"年级主任一键查看所有班级对比" |
management/grade 已有 insights |
✅ 已实现,对比图较完善 |
| 班级消息 |
Google Classroom 班级内消息流 |
messaging 模块支持 class_members scope |
✅ 已通过 messaging 模块实现 |
3.5 数据洞察
| 维度 |
优秀实践 |
当前实现 |
差距 |
| 班级健康度评分 |
PowerSchool 综合出勤+成绩+参与度给出班级健康分 |
class-trends-widget.tsx 仅展示提交率/平均分 |
缺少综合健康度评分 |
| 早期预警 |
ClassDojo 识别"低参与度学生"自动预警 |
无 |
缺少学生风险预警 |
| 班级对比 |
智学网支持同年级班级多维度对比 |
management/grade/insights 已有 |
✅ |
| 趋势同比环比 |
PowerSchool 提供周/月/学期同比 |
class-trends-widget.tsx 仅"Latest"指标 |
缺少时间维度对比 |
3.6 可访问性与性能
| 维度 |
优秀实践 |
当前实现 |
差距 |
| 键盘导航 |
WCAG 2.1 AA 要求所有交互可键盘操作 |
班级列表/课表键盘可访问但无 focus-visible 样式优化 |
a11y 待加强 |
| 流式渲染 |
React 18+ Suspense 流式渲染 |
全部 RSC 同步获取,无 Suspense 边界 |
班级详情 4 个并行查询可流式 |
| 骨架屏精确度 |
骨架屏应反映实际布局 |
class-skeleton.tsx 5 个 skeleton 布局匹配 |
✅ 良好 |
四、改进优先级建议
P0 — 安全/功能阻断(立即修复)
| # |
问题 |
改进方向 |
| P0-1 |
A1:data-access.ts 与拆分文件 3 对同名函数重复定义 |
删除 data-access.ts 中的本地定义,统一从拆分文件导出(保持 barrel 入口兼容) |
| P0-2 |
B1:listClassInvitationCodesAction 无归属校验 |
在 actions 层调用 verifyTeacherOwnsClass(classId, ctx.userId)(admin scope 跳过) |
| P0-3 |
B2:3 个 schedule action 无归属校验 |
同 P0-2,调用 verifyTeacherOwnsClass |
| P0-4 |
C6:getSubjectColor 中文科目不匹配 |
改用科目 ID 或类型守卫匹配;纯函数抽出到 schedule-utils.ts 并补单测 |
| P0-5 |
B3:教师 update/delete/enroll action 未在 actions 层做归属校验 |
actions 层显式判断 hasAdminScope(ctx) 否则校验 classes.teacherId === ctx.userId |
P1 — 重要合规性(本期实施)
| # |
问题 |
改进方向 |
| P1-1 |
C1:class-detail/ 8 子组件硬编码英文 |
全部接入 useTranslations("classes.detail.*") |
| P1-2 |
C2:schedule-view / schedule-filters / students-filters 硬编码英文 |
接入 i18n |
| P1-3 |
C3:所有 actions message 英文硬编码 |
在 actions 层使用 getTranslations() 或返回错误码由组件层翻译 |
| P1-4 |
C4:30+ error.tsx 硬编码中文 |
抽取 shared/components/ErrorState + i18n key common.error.boundary.* |
| P1-5 |
C5:DEFAULT_CLASS_SUBJECTS 与 excludeSubjects 硬编码 |
改为从 subjects 表查询;统一单一来源 |
| P1-6 |
B4:data-access 中 7 处 roles.name 硬编码 |
抽出 ROLE_TEACHER 常量 |
| P1-7 |
B5:student 三个页面未调用 requirePermission |
补 requirePermission(Permissions.HOMEWORK_SUBMIT) 或新增 STUDENT_READ 权限 |
| P1-8 |
D1:10 处 catch 块未记录错误 |
改为 catch (error) { console.error("[classes] xxx:", error); toast.error(...) } |
| P1-9 |
D2:getTeacherClasses 静默返回空数组 |
区分"DB 错误"与"无数据",DB 错误抛出 |
| P1-10 |
D3:actions 层错误处理两套风格 |
统一为 handleActionError |
| P1-11 |
D4:teacher/classes/my/[id] 缺 loading.tsx 和 error.tsx |
新增 |
| P1-12 |
D5:10 个页面缺 error.tsx |
补齐 |
| P1-13 |
F1:schedule-view.tsx 527 行超限 |
抽出 3 个对话框子组件 |
P2 — 工程优化(中长期)
| # |
问题 |
改进方向 |
| P2-1 |
E1/E2/E3:5 处 as 断言 |
改用类型守卫 |
| P2-2 |
E4:14 个事件处理函数缺 Promise |
补返回类型 |
| P2-3 |
G1:3 个 view CRUD handler 重复 |
抽 useClassFormHandlers hook |
| P2-4 |
H1:纯函数内嵌组件 |
抽到 class-stats-utils.ts / schedule-utils.ts 并补单测 |
| P2-5 |
F2:my-classes-grid ClassTicket 210 行 |
拆分为 ClassTicketHeader / ClassTicketInvitation / ClassTicketTrend |
| P2-6 |
A2:class-invitation-manager 绝对路径 |
改为相对路径 |
| P2-7 |
I1:8 个页面缺 generateMetadata |
补齐 |
| P2-8 |
行业差距:班级归档/复制 |
中长期产品规划 |
| P2-9 |
行业差距:班级健康度评分/早期预警 |
中长期产品规划 |
| P2-10 |
行业差距:课表多视图/导出/提醒 |
中长期产品规划 |
重构设计原则(强制满足)
为达成"完全解耦 + 组合优先 + 国际化就绪 + 最大化复用 + 错误边界 + 可测试 + 可扩展 + 企业级补充"八项原则,本次实施遵循:
- 完全解耦:classes 模块内部组件不直接 import 其他业务模块(exams/grades/homework/scheduling)的 actions/data-access;跨模块数据通过本模块 data-access 暴露的接口调用(已基本达成,仅需修复 P0-2/P0-3 的越权问题)。
- 组合优先:错误处理抽
useClassFormHandlers hook;纯逻辑抽 class-stats-utils.ts、schedule-utils.ts;详情 widget 通过配置驱动(ClassDetailWidgetConfig)。
- 国际化就绪:所有修复项必须使用 i18n key;新增翻译键写入
messages/{locale}/classes.json 的 detail.* / schedule.* / students.* 命名空间。
- 最大化复用:admin/grade/teacher/student 共用
ClassListTable / ClassFormDialog / ClassDeleteDialog / useClassData / useClassFilters / useClassFormHandlers。
- 错误与边界:每个详情 widget 独立用
ClassErrorBoundary 包裹;RSC 数据获取用 React Suspense + 骨架屏;空数据/无权限/网络异常状态明确处理。
- 可测试性:纯函数导出至
*.ts 文件,便于 vitest 单测;接口类型显式标注。
- 可扩展性:角色差异通过
hasAdminScope / hasTeacherScope 抽象,新增角色只改 actions-shared.ts。
- 企业级补充:补 a11y(focus-visible、ARIA)、性能(Suspense 流式)、安全(actions 层归属校验)、监控(埋点接口预留
trackClassEvent 工具函数)。
五、架构图同步说明
本次审计发现架构图存在以下遗漏或不一致,需在实施修复时同步更新:
| # |
位置 |
问题 |
修复动作 |
| 1 |
005 modules.classes.files |
仅列 21 个文件,漏 schema.ts/types.ts/12 个组件文件 |
补全至 33 个文件 |
| 2 |
005 modules.classes.exports.actions |
漏 createClassInvitationCodeAction / revokeClassInvitationCodesAction / listClassInvitationCodesAction 3 个 v3 邀请码 action |
补全至 20 个 |
| 3 |
005 modules.classes.exports.dataAccess |
漏 compareClassLike / isDuplicateInvitationCodeError / generateUniqueInvitationCode / getAccessibleClassIdsForTeacher / getSessionTeacherId / getTeacherSubjectIdsForClass 6 个工具函数 |
补全 |
| 4 |
005 dbTables |
classInvitationCodes 表字段未详细登记 |
补全字段定义 |
| 5 |
005 dbTables |
classSchedule 的 usedBy 字段未含 scheduling |
补充 ["classes", "scheduling"] |
| 6 |
005 knownIssues.P0-1 |
仍记录原始问题状态,未标注「已修复」 |
更新 status 字段 |
| 7 |
004 §2.7「被依赖」 |
遗漏 elective / error-book / adaptive-practice 三个模块 |
补全至 13 个 |
| 8 |
005 dependencyMatrix |
exams → classes 与 homework → classes 边未明确登记 |
补全边定义 |
| 9 |
004 §2.7 已知问题 |
P0-2/P0-3/P0-4/P0-5 等本次新增修复 |
同步新增修复记录 |
| 10 |
004 §2.7 文件清单 |
修复后行数变化(如 schedule-view.tsx 拆分) |
更新行数 |