Files
NextEdu/docs/architecture/audit/archive/grades-audit-report.md

26 KiB
Raw Blame History

grades(成绩)模块审计报告

审计日期:2026-06-25 审计范围:src/modules/grades/** + src/app/(dashboard)/**/grades/** 共 50 个文件 架构图定位:004_architecture_impact_map.md § 2.6 / 005_architecture_data.json modules.grades 总体结论:该模块在架构图中被标记为"标杆模块(拆分范例)",三层架构、跨模块 data-access 通信、Server Action 权限校验、纯函数抽取、a11y 与 i18n 在主要文件中已落实。但仍存在 3 处 P0 i18n 严重缺陷2 个文件超行数上限多处英文错误消息未 i18n若干 as 断言与缺返回值类型等问题,需按本报告优先级修复。


一、现有实现概要

1.1 文件分布

grades 模块共 50 个文件,按职责划分为四层:

文件数 路径 职责
类型/校验 2 modules/grades/types.tsschema.ts 类型定义 + Zod 输入校验
数据访问 5 data-access.tsdata-access-analytics.tsdata-access-ranking.tsexport.tsstats-service.ts DB I/O + Excel 导出 + 统计纯函数
Server Actions 2 actions.tsactions-analytics.ts 编排层(权限校验 → Zod → data-access → 通知 → revalidate)
Lib 工具 4 lib/grade-utils.tsscope-filter.tsscope-check.tstype-guards.ts 纯工具函数 + 行级权限过滤 + 类型守卫
组件 19 modules/grades/components/** RSC + 客户端组件混合
页面 18 app/(dashboard)/**/grades/** 四种角色页面 + loading/error

1.2 主要数据流

teacher/grades/page.tsx
  └─▶ requirePermission(GRADE_RECORD_READ)
      └─▶ grades/data-access.getGradeRecords(scope, currentUserId, limit, offset)
          └─▶ lib/scope-filter.buildScopeClassFilter → 行级过滤
          └─▶ db.query.gradeRecords (DB 层分页)
      └─▶ <GradeRecordList> + <GradeFilters> + <ExportButton>

teacher/grades/entry/page.tsx
  └─▶ requirePermission(GRADE_RECORD_MANAGE)
      └─▶ <BatchGradeEntryByExam>
          └─▶ exams/data-access.getExamsForGradeEntry
          └─▶ actions.batchCreateGradeRecordsByExamAction
              └─▶ 单事务写入 grade_records + grade_record_answers
              └─▶ 投影到 exam_submissions(status=graded) + submission_answers
              └─▶ 并行:diagnostic.updateMasteryFromExamScore + error-book.collectFromExamSubmission
              └─▶ notifyGradeEntered(批量通知学生 + 家长)

parent/grades/page.tsx
  └─▶ requirePermission(GRADE_RECORD_READ)
      └─▶ Promise.allSettled(为每个子女并行查询)
          └─▶ grades/data-access.getStudentGradeSummary
          └─▶ grades/data-access-analytics.getClassAverageTrend
          └─▶ <StudentGradeSummary> + <GradeTrendCard> + <ParentExportButton>

1.3 架构图完整性核对

经核对 004_architecture_impact_map.md § 2.6 与 005_architecture_data.json modules.grades:

  • 已记录且准确:exports.dataAccess(15+ 函数)、exports.actions(17 个)、exports.types(7 类)、exports.lib(4 函数)、exports.statsService(8 纯函数)、exports.export(3 函数)、exports.components(WidgetBoundary/SchoolWideSummaryCard/ScoreCell)、dependencies(classes/school/users/exams/error-book/diagnostic/notifications/parent)、knownIssues(已修复 28 项)。
  • 架构图遗漏:
    • components/widget-boundary.tsx 在文件清单中标注为 136 行,但未在 exports.components 中列出(仅在 P1-5 修复记录中提及)。
    • lib/scope-check.tsassertClassInScope 函数未在 exports.lib 节点中列出(仅在 v4-P2-6 修复记录中提及)。
    • parent/grades/page.tsx 调用的 getClassAverageTrend data-access 函数未在架构图 exports.dataAccess 中记录。

1.4 标杆特性

该模块作为项目标杆,已落实的实践:

  • data-access 按职责拆分为 3 个文件(analytics/ranking/主)
  • Server Actions 全部 requirePermission() + Zod 校验
  • 统计逻辑抽取为 stats-service.ts 纯函数(8 个),可独立测试
  • 行级权限过滤 buildScopeClassFilter(scope, currentUserId?)
  • DB 层分页(PaginatedGradeRecords)而非内存分页
  • 事务原子性(db.transaction)
  • 跨模块全部通过 data-access 通信,无直查他模块表
  • 类型守卫(isGradeType/isSemester/isDistributionTooltipPayload)替代 as 断言
  • handleActionError 统一错误处理 + safeActionCall 包装器
  • a11y:4 图表 role="img" + aria-label、2 表格 <caption>、色盲友好双重编码
  • RSC 优先 + 客户端组件最小化

二、现存问题与原因分析

2.1 [P0] i18n 严重缺失 — 3 个 error.tsx 硬编码中文

文件 行号 硬编码文本
parent/grades/error.tsx 16-20 "子女成绩页面加载失败" / "抱歉,页面加载时发生了意外错误..." / "重试"
admin/school/grades/insights/error.tsx 17-21 "成绩洞察页面加载失败" / "抱歉..." / "重试"
admin/school/grades/error.tsx 12-16 "页面加载失败" / "抱歉..." / "重试"
  • 违反规则:项目规则"所有用户可见文本必须适配 i18n(next-intl),提取翻译键"。
  • 原因:这三个 error.tsx 与 teacher/grades/error.tsx(已 i18n)同期创建,但遗漏未接入 useTranslations
  • 直接后果:非中文用户在页面出错时看到中文错误提示,国际化体验中断;与 teacher/grades/error.tsx 的良好实践形成明显不一致。

2.2 [P0] error.tsx 函数缺返回值类型标注

上述 3 个 error.tsx + student/grades/error.tsx + 所有 loading.tsx(共 7 个文件)的函数均未显式标注 : JSX.Element 返回值类型。

  • 违反规则:项目规则"TypeScript 严格模式:函数返回值必须显式标注,特别是 Promise<T>"。
  • 原因:loading/error 文件通常由脚手架生成,未补类型标注。
  • 直接后果:tsc 严格模式下可能漏检类型错误;代码可读性下降。

2.3 [P1] actions.ts 超行数上限(856 行)

actions.ts 当前 856 行,超过 Server Actions 800 行建议上限 56 行。

  • 违反规则:项目规则"Server Actions / Data Access 模块:建议 ≤ 800 行"。
  • 原因:模块职责持续扩张(草稿 CRUD、按试卷录入、撤销、批量删除、通知),所有逻辑集中在单文件。
  • 直接后果:接近 1000 行硬上限,后续新增 Action 将突破硬限;可读性、code review 成本上升。

2.4 [P1] data-access.ts 接近行数上限(816 行)

data-access.ts 当前 816 行,超过 800 行建议上限 16 行。

  • 违反规则:同上。
  • 原因:草稿 CRUD(saveGradeDraft/getGradeDraft/deleteGradeDraft)、按试卷录入(batchCreateGradeRecordsByExam)混入主文件。
  • 直接后果:与 analytics/ranking 已拆分形成不一致;新增数据访问函数将很快突破硬限。

2.5 [P1] actions.ts 多处英文错误消息未 i18n

行号 硬编码英文
148 "Invalid form data"
180 "Grade record created"
253 "Failed to delete grade record"
394-399 "No records to undo" / "Cannot undo more than 500 records at once"
483-487 "No records to delete" / "Cannot delete more than 500 records at once"
584-592 "Can only view your own grades" / "Can only view your children's grades"
654-669 "Can only view your own grade record" / "Can only view your children's grade records"
  • 违反规则:项目规则"所有用户可见文本必须适配 i18n"。
  • 原因:这些错误消息通过 ActionState.error 返回前端展示,早期未统一接入翻译键。
  • 直接后果:非中文用户看到英文错误提示。

2.6 [P1] lib/scope-check.ts 返回消息未 i18n

scope-check.ts 第 24/29/31 行返回 "You can only access classes you teach" 等英文,这些消息会通过 Action 层直接返回用户。

  • 违反规则:同上。
  • 原因:assertClassInScope 是同步函数,无法调用 getTranslations(异步),因此返回原始错误消息交由 Action 层包装。
  • 直接后果:Action 层目前未对返回消息做翻译包装,直接透传给用户。

2.7 [P1] actions-analytics.ts scope 校验消息未 i18n

actions-analytics.ts 第 176/183 行 "Can only view your own ranking trend" / "Can only view your children's ranking trend"。

  • 同 2.5 原因与后果。

2.8 [P1] batch-grade-entry.tsx 超组件行数上限(604 行)

batch-grade-entry.tsx 604 行,超过组件 500 行建议上限 104 行(复杂表单可放宽至 800,但仍建议拆分)。

  • 违反规则:项目规则"React 组件:建议 ≤ 500 行(复杂表单/大型表格可放宽至 800)"。
  • 原因:Excel 式表格 + 试卷/班级选择器 + 统计栏 + 撤销机制 + AlertDialog 全部集中在单文件。
  • 直接后果:可读性下降;子组件无法独立复用与测试;状态管理复杂度高,易引入 bug。

2.9 [P1] batch-grade-entry.tsx 第 341 行 as 断言无类型守卫

JSON.parse(raw) as { ids: string[]; timestamp: number }
  • 违反规则:项目规则"禁止 as 断言(除非从 unknown 转换或测试中,需注释原因)"。
  • 原因:sessionStorage 撤销数据反序列化未做类型守卫。
  • 直接后果:数据被篡改时可能运行时报错;类型安全缺失。

2.10 [P1] parent/grades/page.tsx 第 63 行 as 断言

summary as NonNullable<typeof r.value.summary>
  • 违反规则:同 2.9。
  • 原因:虽有前置 filter(r => r.value.summary) 保证,但严格违反"禁止 as 断言"规则。
  • 直接后果:类型系统对运行时假设依赖,filter 逻辑变更时可能失效。

2.11 [P2] student-grade-summary.tsx / grade-record-list.tsx 硬编码 "S" 前缀

两文件均使用 <TableCell>S{r.semester}</TableCell> 硬编码 "S1"/"S2" 前缀。

  • 违反规则:i18n 规则。
  • 原因:学期显示格式未抽象为翻译键。
  • 直接后果:非英文/中文语境下学期标签不符合本地化习惯。

2.12 [P2] 多个组件函数缺返回值类型标注

文件 函数
grade-filters.tsx GradeFilters
grade-query-filters.tsx GradeQueryFilters
export-button.tsx handleExport
grade-record-form.tsx handleSubmit
所有 loading.tsx(7 个) Loading
  • 违反规则:函数返回值必须显式标注。
  • 原因:脚手架/早期代码遗漏。
  • 直接后果:类型推导依赖,严格模式潜在漏检。

2.13 [P2] data-access.ts updateGradeRecord 类型安全性较弱

第 407 行使用 Record<string, unknown> 累积更新字段。

  • 违反规则:TypeScript 严格模式精神(虽未直接违反禁止 any)。
  • 原因:Drizzle 动态更新字段累积时类型推导困难。
  • 直接后果:可能写入非法字段名;类型安全缺失。

2.14 [P2] getStudentGradeSummary 内部调用 getClassRanking 形成 data-access 层内部耦合

data-access.ts 第 564 行 getStudentGradeSummary 内部调用 getClassRanking,形成 data-access 层内部依赖。

  • 原因:学生成绩摘要需要排名信息,直接复用排名查询。
  • 直接后果:语义上 getStudentGradeSummary 不应依赖 getClassRanking;两者缓存参数不完全一致,可能导致重复查询;测试时需 mock 排名逻辑。

2.15 [P2] 组件复用抽象不足

现状 建议
GradeFilters(student,nuqs) 与 GradeQueryFilters(teacher,URLSearchParams) 两个独立过滤器 抽象为统一组件 + props 配置
ExportButton(teacher) 与 ParentExportButton(parent) 可统一为带 variant prop 的单一组件
AnalyticsFilters(teacher RSC) 与 GradeInsightsFilters(school ChipNav) 可考虑统一
  • 违反规则:项目规则"识别四个角色共用的 UI 块和业务逻辑块,抽象为泛型组件和 hooks"。
  • 原因:各角色过滤器实现差异较大(nuqs vs URLSearchParams vs ChipNav),未做抽象。
  • 直接后果:新增角色需重写过滤器;维护成本上升。

2.16 [P2] 缺少 Error Boundary 包裹的独立数据区块

teacher/grades/page.tsx 列表与统计卡片未用 WidgetBoundary 包裹(仅 analytics 页面已包裹)。

  • 违反规则:项目规则"每个独立的数据区块必须用 React Error Boundary 包裹"。
  • 原因:主页面早期未应用 WidgetBoundary。
  • 直接后果:单个数据区块失败会导致整个页面崩溃。

2.17 [P2] 撤销机制仅依赖 sessionStorage(5 分钟)

batch-grade-entry.tsx 撤销令牌存于 sessionStorage,刷新或跨设备后丢失;undoBatchCreateGradeRecordsAction 无时间窗口限制,理论上可撤销任意时间自己录入的记录。

  • 违反规则:项目规则"错误与边界处理:明确处理空数据、无权限、网络异常等边界状态"(隐含)。
  • 原因:撤销机制为 v4 新增,未考虑持久化与时效。
  • 直接后果:误删风险;跨设备无法撤销。

2.18 [P2] 通知串行写入

notifyGradeEntered 对每个学生/家长串行调用 createNotification(actions.ts 第 88-117 行)。

  • 违反规则:性能最佳实践。
  • 原因:通知 data-access 未提供批量接口。
  • 直接后果:批量录入 30+ 学生时通知耗时显著。

2.19 [P2] 图表 tooltip a11y 不足

图表组件有 role="img" + aria-label,但 tooltip(recharts tooltip)的 a11y 支持不足,屏幕阅读器无法读取悬停数据。

2.20 [P2] lib/type-guards.ts 第 8/12 行 as 断言

(GRADE_TYPES as readonly string[]).includes(v)
  • 违反规则:禁止 as 断言(虽属类型收窄,但严格违规)。
  • 改进:改用 Array.from(GRADE_TYPES).includes(v)(GRADE_TYPES as readonly unknown[]).includes(v as unknown) 后做类型守卫。

2.21 [P3] 架构图遗漏

  • components/widget-boundary.tsx 未在 exports.components 节点列出
  • lib/scope-check.tsassertClassInScope 未在 exports.lib 节点列出
  • getClassAverageTrend data-access 函数未记录

三、行业差距对比

对标 PowerSchool / Gradebook、Google Classroom、Canvas LMS、智学网、校宝在线等 K12 成绩管理产品,本模块差距如下:

3.1 缺失:成绩报告卡(Report Card)PDF 导出

  • 行业实践:PowerSchool / Canvas 支持生成单生/班级 PDF 成绩报告卡,含学期汇总、排名、教师评语、签名区。
  • 本模块现状:仅支持 Excel 导出(exportGradeRecordsToExcel),无 PDF。
  • 影响:家长会、学期末场景需手动排版打印,效率低。

3.2 缺失:成绩变化智能预警

  • 行业实践:智学网提供"成绩大幅波动预警"(分数下降超过 10 分自动通知班主任 + 家长)。
  • 本模块现状:无预警机制,仅静态统计。
  • 影响:教师无法及时发现学习下滑学生,错过干预窗口。

3.3 缺失:知识点维度的成绩诊断

  • 行业实践:Canvas LMS 的 MasteryGradebook 按知识点(competency)展示掌握度,而非仅按考试/科目。
  • 本模块现状:成绩按科目/考试维度,虽 grade_record_answers 已存储每题得分,但未提供知识点聚合视图(依赖 diagnostic 模块但未集成到 grades 页面)。
  • 影响:教师无法在成绩页直接看到班级在哪个知识点薄弱。

3.4 缺失:学生纵向成长档案(Individual Growth Report)

  • 行业实践:PowerSchool 提供单生多年纵向趋势图,含跨学期/跨年级对比。
  • 本模块现状:GradeTrendCard 仅展示单学期/单科目趋势,无跨年级纵向档案。
  • 影响:家长无法全面了解学生长期成长轨迹。

3.5 缺失:班级横向对比的统计显著性标注

  • 行业实践:专业 BI 工具(如 Tableau 教育版)在班级对比时标注 p 值、效应量(Cohen's d)。
  • 本模块现状:ClassComparisonChart 有"显著性分析区域"(v3-P3-5 新增),但仅基于极差经验规则,未使用统计检验。
  • 影响:教师可能过度解读小样本差异。

3.6 缺失:成绩录入的草稿协同

  • 行业实践:Google Classroom 支持多位教师协同录入,草稿云端同步,锁定机制防止冲突。
  • 本模块现状:草稿仅单用户单设备(grade_drafts 表按 userId 唯一),无协同。
  • 影响:多教师任教同一班级时无法分工录入。

3.7 缺失:成绩申诉与复核流程

  • 行业实践:Canvas 支持学生对成绩提出申诉,教师复核后修改并留痕。
  • 本模块现状:仅 updateGradeRecord,无申诉状态机与审计轨迹。
  • 影响:成绩修改无留痕,合规性不足。

3.8 缺失:移动端适配深度优化

  • 行业实践:校宝在线移动端针对家长提供"成绩单卡片"简化视图,大表格转为卡片堆叠。
  • 本模块现状:grade-record-list.tsxoverflow-x-auto,但未做卡片堆叠适配;图表在移动端可能过小。
  • 影响:家长移动端查看体验一般。

3.9 缺失:成绩分布的隐私保护

  • 行业实践:GDPR/FERPA 合规要求学生视角的分布图应隐藏其他学生身份,仅显示相对位置。
  • 本模块现状:学生视角的 GradeDistributionChart 显示全班分布,虽未暴露个人身份,但需明确"你在分布中的位置"标注。
  • 影响:隐私合规风险(部分国家/地区)。

3.10 缺失:批量导入 Excel 成绩

  • 行业实践:智学网支持下载模板 → 填写 → 上传 Excel 批量导入。
  • 本模块现状:batch-grade-entry.tsx 支持下载 CSV 模板 + 粘贴录入,但无完整 Excel 上传解析。
  • 影响:教师需手动粘贴,大批量场景效率低。

四、改进优先级建议

P0 — 立即修复(影响用户体验与合规)

# 问题 改进方向
P0-1 3 个 error.tsx 硬编码中文(2.1) 改为 useTranslations("grades") + 新增 error.* 翻译键(zh-CN/en 同步)
P0-2 7 个 loading/error.tsx 函数缺返回值类型(2.2) 补全 : JSX.Element 返回值类型标注

P1 — 本周修复(架构规范与 i18n)

# 问题 改进方向
P1-1 actions.ts 超 800 行(2.3) 拆分草稿相关 3 个 Action 到 actions-draft.ts;拆分通知逻辑到 lib/notify.ts
P1-2 data-access.ts 超 800 行(2.4) 拆分草稿 CRUD 到 data-access-drafts.ts;拆分按试卷录入到 data-access-exam-entry.ts
P1-3 actions.ts 多处英文错误消息未 i18n(2.5) 新增 action.error.* 翻译键,所有错误消息改用 t("action.error.*")
P1-4 lib/scope-check.ts 返回消息未 i18n(2.6) 改为返回错误码枚举,由 Action 层翻译;或返回 null + Action 层自行抛错
P1-5 actions-analytics.ts scope 消息未 i18n(2.7) 同 P1-3
P1-6 batch-grade-entry.tsx 超 500 行(2.8) 拆分为 BatchGradeEntryTable + BatchGradeEntryStats + BatchGradeEntryDialogs 子组件
P1-7 batch-grade-entry.tsx 第 341 行 as 断言(2.9) 新增 isUndoData 类型守卫函数
P1-8 parent/grades/page.tsx 第 63 行 as 断言(2.10) 改用类型守卫 isSummaryFulfilled 或非空检查
P1-9 teacher/grades/page.tsx 列表与统计未 WidgetBoundary 包裹(2.16) <WidgetBoundary> 包裹独立区块

P2 — 中期改进(质量与一致性)

# 问题 改进方向
P2-1 "S" 前缀硬编码(2.11) 新增 semester.s1/semester.s2 翻译键
P2-2 组件函数缺返回值类型(2.12) 补全 : JSX.Element / : Promise<void>
P2-3 updateGradeRecord 类型弱(2.13) 改用 Partial<typeof gradeRecords.$inferInsert>
P2-4 getStudentGradeSummary 内部耦合 getClassRanking(2.14) 将排名计算抽取到 action 层或 stats-service
P2-5 过滤器组件未抽象(2.15) 抽象 GradeFilterBar 统一组件 + props 配置
P2-6 撤销机制 sessionStorage 依赖(2.17) 服务端存储撤销令牌 + 24 小时时间窗口
P2-7 通知串行写入(2.18) 新增 notifications/data-access.bulkCreateNotification 批量接口
P2-8 图表 tooltip a11y(2.19) 添加 aria-describedby + 旁路数据表(sr-only)
P2-9 lib/type-guards.ts as 断言(2.20) 改用 Array.from(GRADE_TYPES).includes(v)

P3 — 长期改进(行业对齐与企业级)

# 问题 改进方向
P3-1 缺 PDF 成绩报告卡(3.1) 新增 lib/report-card.ts,基于 @react-pdf/renderer 生成 PDF
P3-2 缺成绩变化预警(3.2) 新增 stats-service.detectScoreAnomaly 纯函数 + 通知触发
P3-3 缺知识点维度诊断集成(3.3) 在 analytics 页面集成 diagnostic 模块的知识点掌握度视图
P3-4 缺学生纵向档案(3.4) 新增 getStudentGrowthArchive data-access + GrowthArchiveChart 组件
P3-5 缺统计显著性标注(3.5) 引入 simple-statistics 库计算 p 值 + Cohen's d
P3-6 缺协同录入(3.6) grade_drafts 表新增 lockedBy/lockedAt/lockToken 字段 + classSubjectLockIdx 索引支持锁机制data-access-drafts.ts 5 个锁函数 + actions-lock.ts 4 个 Server Action + use-draft-lock Hook + DraftLockBanner 组件 + i18n
P3-7 缺申诉流程(3.7) 新增 grade_appeals 表(状态机枚举+4 个索引)+ data-access-appeals.ts7 个函数)+ actions-appeal.ts5 个 Server Action+ schema.ts Zod 校验 + i18n
P3-8 缺移动端卡片堆叠(3.8) 新增 GradeRecordCardList 移动端组件
P3-9 缺隐私保护位置标注(3.9) 学生视角分布图添加"你的位置"标注
P3-10 缺 Excel 上传批量导入(3.10) 集成 xlsx 库,新增 importGradesFromExcel Action
P3-11 单元测试覆盖(2.14 关联) 为 stats-service.ts 纯函数 + lib/scope-check.ts 补充 vitest 测试

架构图同步

# 改进内容 架构图更新
A-1 P1-1 拆分 actions.ts 004 文件清单 + 005 exports.actions 节点
A-2 P1-2 拆分 data-access.ts 004 文件清单 + 005 exports.dataAccess 节点
A-3 P1-6 拆分 batch-grade-entry 004 文件清单 + 005 exports.components 节点
A-4 补全遗漏 004/005 补充 widget-boundary、scope-check.assertClassInScope、getClassAverageTrend

五、架构图同步说明

5.1 本次审计发现的架构图遗漏(需补充)

  1. components/widget-boundary.tsx — 在 004 § 2.6 文件清单中标注为 136 行,但未在 exports.components 节点中列出。需在 005 modules.grades.exports.components 数组中新增条目。
  2. lib/scope-check.tsassertClassInScope — 仅在 v4-P2-6 修复记录中提及,未在 exports.lib 节点列出。需补充。
  3. getClassAverageTrend data-access 函数parent/grades/page.tsx 调用但架构图 exports.dataAccess 未记录。需确认其在 data-access-analytics.ts 中的位置并补充。

5.2 重构后需同步的节点

  • 若执行 P1-1(拆分 actions.ts):004 文件清单更新为 actions.ts(barrel)+ actions-draft.ts + actions-exam-entry.ts;005 exports.actions 按文件分组。
  • 若执行 P1-2(拆分 data-access.ts):004 文件清单更新为 data-access.ts + data-access-drafts.ts + data-access-exam-entry.ts;005 exports.dataAccess 按文件分组。
  • 若执行 P1-6(拆分 batch-grade-entry):004 文件清单新增 3 个子组件;005 exports.components 补充。
  • P0/P1 i18n 修复无需更新架构图(翻译键不影响模块导出结构)。

六、实施计划

本节为审计文档的实施清单,按优先级执行,每步完成后运行 npm run lint && npx tsc --noEmit 验证零错误。

阶段 1:P0 立即修复(本次会话完成)

  • P0-1: 3 个 error.tsx i18n(parent/grades、admin/school/grades、admin/school/grades/insights)
  • P0-2: 7 个 loading/error.tsx 函数补全返回值类型

阶段 2:P1 本周修复(本次会话完成)

  • P1-1: 拆分 actions.tsactions-draft.ts + 通知抽取到 lib/notify.ts
  • P1-2: 拆分 data-access.tsdata-access-drafts.ts + data-access-exam-entry.ts
  • P1-3: actions.ts 错误消息 i18n(新增 action.error.* 翻译键)
  • P1-4: lib/scope-check.ts 改为返回错误码枚举
  • P1-5: actions-analytics.ts scope 消息 i18n
  • P1-6: 拆分 batch-grade-entry.tsx 为子组件
  • P1-7: batch-grade-entry.tsx 第 341 行 as 断言 → 类型守卫
  • P1-8: parent/grades/page.tsx 第 63 行 as 断言 → 类型守卫
  • P1-9: teacher/grades/page.tsx WidgetBoundary 包裹

阶段 3:P2 中期改进(本次会话完成)

  • P2-1: "S" 前缀 i18n
  • P2-2: 组件函数返回值类型补全
  • P2-3: updateGradeRecord 类型强化
  • P2-4: 解耦 getStudentGradeSummarygetClassRanking
  • P2-5: 过滤器组件抽象(评估后决定是否实施)
  • P2-6: 撤销机制服务端持久化(评估后决定)
  • P2-7: 通知批量接口(依赖 notifications 模块改造,标注为后续)
  • P2-8: 图表 tooltip a11y
  • P2-9: lib/type-guards.ts as 断言修复

阶段 4:P3 长期改进(记录待排期,不在本次会话实施)

  • P3-1 ~ P3-10:行业差距对齐(需产品评估与设计)
  • P3-11:单元测试覆盖

阶段 5:架构图同步(本次会话完成)

  • A-1 ~ A-4:补充 004/005 遗漏节点 + 重构后节点更新