docs(audit): add audit reports for grades, homework, lesson-preparation, messaging, permissions, question-bank, settings, textbooks

- Add grades-audit-report

- Add homework-audit-report and homework-exams-audit-report

- Add lesson-preparation-audit-report-v3 and v4

- Add messaging-audit-report

- Add permissions-audit-report

- Add question-bank-audit-report

- Add settings-profile-audit-report-v3

- Add textbooks-audit-report-v3
This commit is contained in:
SpecialX
2026-07-03 10:23:34 +08:00
parent 365c36d97b
commit 89b9e181d2
29 changed files with 13009 additions and 230 deletions

View File

@@ -1,318 +1,274 @@
# 学校/年级/班级管理模块审计报告
# 学校/年级/班级管理模块审计报告 v2
> 审查范围:`school`(学校/学年/部门/年级 CRUD、`grade-management`(年级管理重构模块)、`classes`(班级管理)
> 审查日期2026-06-22
> 审查范围:`school`(学校/学年/部门/年级 CRUD、`classes`(班级管理)
> 审查日期2026-06-22v2 复审)
> 审查依据项目规则三层架构、权限校验、i18n、TypeScript 严格模式、单文件行数限制、K12 行业优秀实践
> 审查方式:只读源码分析 + 架构图比对,未修改任何代码
> 审查方式:只读源码分析 + 架构图比对 + 行业对标
---
## 一、现有实现概要
### 1.1 模块文件分布
### 1.1 v1 审计修复回顾
| 模块 | 核心文件 | 行数(约) | 职责 |
|------|---------|-----------|------|
| `school` | `actions.ts` / `data-access.ts` / `schema.ts` / `types.ts` + 4 个组件 | 349 / 504 / 51 / 96 | 学校/学年/部门/年级的 CRUD |
| `grade-management` | `actions.ts` / `data-access.ts` / `data-access-insights.ts` / `schema.ts` / `types.ts` + 11 组件 + 4 hooks + 4 services + 2 widgets + 1 config | 213 / 238 / 75 / — / 149 | 年级管理(重构版,含洞察) |
| `classes` | `actions.ts` / `data-access.ts` / `data-access-{admin,stats,schedule,students,invitations}.ts` / `schema.ts` / `types.ts` + 14 组件 | 974 / 548 / 406 / 513 / 194 / 253 / — / 152 / 183 | 班级 CRUD + 学生/教师管理 + 邀请码 + 课表 + 作业洞察 |
v1 审计报告识别了 14 个问题5 个 P0 + 6 个 P1 + 5 个 P2截至本次复审**全部 14 个问题已修复**
### 1.2 页面分布(共 13 个 page.tsx
| 编号 | 问题 | 状态 |
|------|------|------|
| P0-1 | `grade-management` 死模块 | ✅ 已删除 |
| P0-2 | 年级 CRUD 逻辑重复 | ✅ 统一到 school 模块 |
| P0-3 | `classes/actions.ts` 974 行 | ✅ 拆分为 6 个文件 |
| P0-4 | `teacher/classes/*` 无权限校验 | ✅ 4 个页面已加 `requirePermission` |
| P0-5 | school 模块无 i18n | ✅ 4 个组件已接入 `useTranslations` |
| P1-1 | 角色硬编码 | ✅ 改为 `dataScope.type` 判断 |
| P1-2 | school 无 i18n 文件 | ✅ `school.json` 已创建413 行翻译键) |
| P1-3 | school 缺 Error Boundary/Skeleton | ✅ 已补充 |
| P1-4 | classes/types.ts 跨领域类型 | ✅ 保留并加注释说明 |
| P1-5 | school 未用组合模式 | ✅ 拆分为 4 个子组件 |
| P1-6 | data-access 无权限过滤 | ✅ 新增 `getSchoolsForUser`/`getGradesForUser` |
| P2-1~P2-5 | 各项优化 | ✅ 全部修复 |
| 路由分组 | 页面 | 权限校验 | i18n | 调用方式 |
|---------|------|---------|------|---------|
| `admin/school/*` | schools / grades / classes / departments / academic-year | ✅ `requirePermission(SCHOOL_MANAGE)` | ❌ 中文硬编码 | 直接调用 data-access |
| `management/grade/*` | classes / insights | ✅ `requirePermission(GRADE_MANAGE/GRADE_RECORD_READ)` | ❌ 英文硬编码 | 直接调用 classes/school data-access |
| `teacher/classes/*` | my / my/[id] / schedule / students | ❌ **无任何校验** | ❌ 英文硬编码 | 直接调用 data-access |
### 1.2 当前模块文件分布
### 1.3 架构图记录情况
| 模块 | 核心文件 | 行数 | 职责 |
|------|---------|------|------|
| `school` | `actions.ts` | 457 | 13 个 Server Action`promoteGradesAction` |
| `school` | `data-access.ts` | 757 | 只读查询 + 12 个写操作 + 组织树 + 权限感知函数 |
| `school` | `schema.ts` / `types.ts` | 51 / 90 | Zod 校验 / 类型定义 |
| `school` | `components/` (14 文件) | 60~860 | 学校/学年/部门/年级视图 + 仪表盘 + 组织树 |
| `school` | `hooks/use-school-data.ts` | 36 | 学校数据管理 hook |
| `classes` | `actions.ts` (barrel) | 51 | re-export 入口 |
| `classes` | `actions-{teacher,admin,grade,invitations,schedule,shared}.ts` | 60~448 | 按职责拆分的 6 个 Action 文件 |
| `classes` | `data-access.ts` | 833 | 核心班级 CRUD + 邀请码 + 教师班级管理 |
| `classes` | `data-access-{admin,stats,schedule,students,invitations}.ts` | 93~454 | 按领域拆分的 5 个 data-access |
| `classes` | `schema.ts` / `types.ts` | 152 / 177 | Zod 校验 / 类型定义 |
| `classes` | `components/` (14 文件) | 137~499 | 班级列表/详情/学生/课表/邀请码 |
`docs/architecture/004_architecture_impact_map.md` 中:
- ✅ 已记录 `school` 模块§2.8)和 `classes` 模块§2.7)的职责、依赖关系、跨模块通信方式
- ✅ 已记录 `classes` 模块的文件拆分5 个 data-access 子文件)和 P0-7 修复homework 跨模块封装)
-**未记录 `grade-management` 模块** — 该模块拥有完整的 services/hooks/widgets/config 架构,但架构图中完全缺失
-**未记录 `grade-management` 模块未被任何页面使用的事实** — 这是重大架构偏差
### 1.3 页面分布(共 13 个 page.tsx
| 路由分组 | 页面 | 权限校验 | i18n | Error Boundary | Loading |
|---------|------|---------|------|----------------|---------|
| `admin/school/schools` | ✅ `SCHOOL_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `admin/school/grades` | ✅ `SCHOOL_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `admin/school/grades/insights` | ✅ `SCHOOL_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `admin/school/departments` | ✅ `SCHOOL_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `admin/school/academic-year` | ✅ `SCHOOL_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `admin/school/classes` | ✅ `SCHOOL_MANAGE` | ❌ | ❌ | ✅ | ✅ |
| `management/grade/classes` | ✅ `GRADE_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `management/grade/insights` | ✅ `GRADE_MANAGE` | ✅ | ✅ | ✅ | ✅ |
| `management/grade/dashboard` | ✅ `GRADE_MANAGE` | ✅ | ✅ | ❌ | ✅ |
| `teacher/classes/my` | ✅ `CLASS_READ` | ❌ | ❌ | ❌ | ✅ |
| `teacher/classes/my/[id]` | ✅ `CLASS_READ` | ❌ | ❌ | ❌ | ❌ |
| `teacher/classes/schedule` | ✅ `CLASS_READ` | ❌ | ✅(Suspense) | ❌ | ✅ |
| `teacher/classes/students` | ✅ `CLASS_READ` | ❌ | ✅(Suspense) | ❌ | ✅ |
### 1.4 数据流概要
```
admin/school/grades 页面
└─→ school/data-access.getGrades() / getSchools() / getStaffOptions()
└─→ school/components/grades-view.tsx客户端组件
└─→ school/actions.ts → createGradeAction / updateGradeAction / deleteGradeAction
admin/school/* 页面(✅ 完整 i18n + Error Boundary + Skeleton
└─→ school/data-access.getSchools() / getGrades() / getStaffOptions() / getGradeOverviewStats()
└─→ school/components/*(✅ 全部使用 useTranslations
└─→ school/actions.ts → createXxxAction / updateXxxAction / deleteXxxAction
management/grade/classes 页面
management/grade/* 页面(✅ 完整 i18n + Error Boundary
└─→ classes/data-access.getGradeManagedClasses() / getTeacherOptions()
└─→ school/data-access.getGradesForStaff()
└─→ classes/components/grade-classes-view.tsx
└─→ classes/actions.ts → createGradeClassAction / updateGradeClassAction / ...
└─→ classes/components/grade-classes-view.tsx(❌ 无 i18n
└─→ classes/actions.ts → createGradeClassAction / ...
teacher/classes/* 页面
teacher/classes/* 页面(❌ 组件无 i18n❌ 无 Error Boundary
└─→ classes/data-access.getTeacherClasses() / getClassStudents() / getClassSchedule()
└─→ classes/components/*my-classes-grid / students-table / schedule-view
└─→ classes/components/*❌ 14 个组件中仅 1 个使用 useTranslations
└─→ classes/actions.ts → createTeacherClassAction / ...
grade-management 模块(⚠️ 完全未被使用)
└─→ services/grade-service.ts接口定义
└─→ services/admin-grade-service.ts / teacher-grade-service.ts实现
└─→ widgets/grade-management-widget.tsx主面板
└─→ ⚠️ 无任何页面导入此模块
```
---
## 二、现存问题与原因分析
## 二、现存问题与原因分析v2 新发现)
### 2.1 架构层面
### 2.1 国际化层面
#### P0-1`grade-management` 模块完全未被使用(死模块)
- **位置**`src/modules/grade-management/` 全模块
- **问题**该模块拥有完整的理想架构Service 接口 + Context 依赖注入 + 角色配置 + Error Boundary + Skeleton + i18n + hooks 分离),但 **13 个相关页面中无任何一个导入该模块**`management/grade/*` 页面实际依赖 `classes``school` 模块的 data-access。
- **违反规则**:架构图优先规则(图未覆盖则先补图)、模块标准结构(该模块存在但未接入)
- **原因**:推测为未完成的重构 — 已建立目标架构但未将页面迁移过来
- **后果**:维护两套年级管理逻辑(`school` 模块的 grade CRUD + `grade-management` 模块的 grade CRUD职责重叠、产生混淆理想架构模式无法落地发挥价值
#### P0-2年级 CRUD 逻辑重复定义
#### P0-Aclasses 模块 13/14 个组件未接入 i18n
- **位置**
- `src/modules/school/actions.ts` L268-349`createGradeAction` / `updateGradeAction` / `deleteGradeAction`
- `src/modules/grade-management/actions.ts` L37-203同名函数 `createGradeAction` / `updateGradeAction` / `deleteGradeAction`
- `src/modules/school/data-access.ts` L256-285`createGrade` / `updateGrade` / `deleteGrade`
- `src/modules/grade-management/data-access.ts` L137-171同名函数 `createGrade` / `updateGrade` / `deleteGrade`
- **问题**:两套模块各自定义了完全相同的年级 CRUD 逻辑,`admin/school/grades` 页面使用 `school` 模块版本,`grade-management` 模块版本无人调用
- **违反规则**DRY 原则、模块标准结构(职责应归属单一模块)
- **后果**修改年级逻辑需同步两处极易遗漏两套实现的审计日志策略不一致school 模块 grade CRUD 无 `logAudit`grade-management 模块有)
#### P0-3`classes/actions.ts` 接近行数硬上限
- **位置**`src/modules/classes/actions.ts`974 行)
- **问题**:文件已达 974 行,接近 1000 行硬性上限。包含 3 组近乎重复的 CRUD ActionTeacher 系列 / Admin 系列 / Grade 系列)+ 邀请码 Action + 课表 Action
- **违反规则**单文件行数限制Server Actions 建议 ≤ 800 行,硬性上限 1000 行)
- **后果**:再增加任何功能即超限;文件过大降低可读性和可维护性
### 2.2 权限层面
#### P0-4`teacher/classes/*` 4 个页面完全缺少权限校验
- **位置**
- `src/app/(dashboard)/teacher/classes/my/page.tsx` — 无 `requirePermission()`
- `src/app/(dashboard)/teacher/classes/my/[id]/page.tsx` — 无 `requirePermission()`
- `src/app/(dashboard)/teacher/classes/schedule/page.tsx` — 无 `requirePermission()`
- `src/app/(dashboard)/teacher/classes/students/page.tsx` — 无 `requirePermission()`
- **问题**:这 4 个业务页面直接调用 data-access 获取数据,依赖路由中间件隐式保障身份,无显式权限校验
- **违反规则**Server Action 规范(每个 Action 必须调用 `requirePermission()`);安全性规范(所有敏感数据查询必须在 data-access 层结合当前用户权限过滤)
- **后果**若路由中间件配置错误或被绕过教师可访问任意班级数据data-access 层的 `getTeacherClasses()` 未接收 userId 参数做范围过滤
#### P1-1`classes/actions.ts` 中存在 `ctx.roles.includes("xxx")` 硬编码
- **位置**`src/modules/classes/actions.ts` L81、L420、L422、L428、L446、L451
- **问题**Server Action 中使用 `ctx.roles.includes("admin")` / `ctx.roles.includes("teacher")` / `ctx.roles.includes("student")` 进行角色判断
- **违反规则**:前端组件禁止 `role === "xxx"` 硬编码(虽此处在 Server Action 而非前端组件,但精神一致 — 应使用权限点而非角色名)
- **后果**:新增角色(如 grade_head需修改所有硬编码处角色与权限耦合不符合权限点驱动设计
### 2.3 国际化层面
#### P0-5全部 13 个页面均未使用 i18n
- **位置**:所有 13 个 page.tsx 及其引用的组件
- **问题**
- `admin/school/*` 页面使用**中文硬编码**(如 "学校管理"、"年级管理"、"班级管理"
- `management/grade/*``teacher/classes/*` 页面使用**英文硬编码**(如 "Class Management"、"Grade Insights"
- `school/components/*` 全部使用英文硬编码(如 "New school"、"All schools"、"Edit"、"Delete"
- `classes/components/*` 混用中英文
- `src/modules/classes/components/admin-classes-view.tsx` — 16 处英文硬编码("Failed to create class"、"No classes"、"Select a school" 等)
- `src/modules/classes/components/grade-classes-view.tsx` — 20+ 处英文硬编码("Homeroom Teacher"、"Subject Teachers"、"Select a grade" 等)
- `src/modules/classes/components/my-classes-grid.tsx` — 15+ 处英文硬编码("Join New Class"、"Invitation Code"、"Cancel" 等)+ 1 处中文硬编码("教学科目"、"暂无可选科目"
- `src/modules/classes/components/schedule-view.tsx` — 10+ 处英文硬编码
- `src/modules/classes/components/schedule-filters.tsx` — 8 处英文硬编码
- `src/modules/classes/components/students-filters.tsx` — 5 处英文硬编码
- `src/modules/classes/components/students-table.tsx` — 英文硬编码
- `src/modules/classes/components/class-detail/*.tsx`7 个文件)— 全部英文硬编码("Recent Homework"、"Weekly Schedule"、"Quick Actions" 等)
- **问题**14 个组件中仅 `class-invitation-manager.tsx` 使用 `useTranslations`,其余 13 个组件全部硬编码文本,且 `my-classes-grid.tsx` 中存在中英文混用
- **违反规则**:所有用户可见文本必须适配 i18n使用 next-intl提取翻译键
- **后果**无法支持多语言中英文混用严重影响一致性和专业度i18n 资源文件(`grade.json``classes.json`)已存在但未被使用
- **原因**v1 审计仅修复了 school 模块的 i18nclasses 模块的 i18n 遗留未处理
- **后果**teacher/management 视角下的班级管理页面无法支持多语言;中英文混用严重影响专业度
#### P1-2`school` 模块无 i18n 资源文件
#### P0-Bclasses.json i18n 文件内容严重不足
- **位置**`src/shared/i18n/messages/{zh-CN,en}/` 目录
- **问题**存在 `grade.json``classes.json`,但**不存在 `school.json`**。school 模块的学校/学年/部门管理文本无翻译键可用
- **位置**`src/shared/i18n/messages/{zh-CN,en}/classes.json`
- **问题**当前仅 55 行,只覆盖 `invitation.*``class.*`5 个基础字段)。缺少班级 CRUD 表单、列表、筛选器、详情页、学生管理、课表等全部场景的翻译键
- **违反规则**i18n 就绪规范
- **后果**:即使想为 school 模块补充 i18n也缺少翻译文件基础设施
- **后果**:即使组件想接入 i18n也缺少翻译键可用
### 2.4 组件质量层面
### 2.2 文件大小层面
#### P1-3`school/components/*` 缺少 Error Boundary 和 Skeleton
#### P1-A`grades-view.tsx` 860 行超出组件行数限制
- **位置**`src/modules/school/components/schools-view.tsx` / `grades-view.tsx` / `departments-view.tsx` / `academic-year-view.tsx`
- **问题**4 个组件均为 `"use client"` 客户端组件,无 Error Boundary 包裹、无加载骨架屏、无 Suspense 处理。对比 `grade-management` 模块已有 `grade-error-boundary.tsx` / `grade-skeleton.tsx` / `grade-states.tsx`(但未被使用)
- **位置**`src/modules/school/components/grades-view.tsx`860 行)
- **问题**单个客户端组件文件 860 行,超过 React 组件建议上限 500 行(复杂表单可放宽至 800 行,但仍超)。包含年级列表 + 概览卡片 + 筛选器 + 创建/编辑表单 + 删除对话框 + 年级升级对话框全部逻辑
- **违反规则**单文件行数限制React 组件建议 ≤ 500 行,复杂表单/大型表格可放宽至 800 行)
- **后果**:可读性差,难以维护;筛选逻辑、表单校验逻辑、对话框状态管理全部耦合
#### P1-B`classes/data-access.ts` 833 行超出 data-access 限制
- **位置**`src/modules/classes/data-access.ts`833 行)
- **问题**:虽然已拆分为 5 个 data-access 子文件,但主 `data-access.ts` 仍达 833 行,超过 data-access 建议 800 行上限。包含核心班级 CRUD + 邀请码 + 教师班级管理 + 跨模块接口
- **违反规则**单文件行数限制Server Actions / Data Access 模块建议 ≤ 800 行)
- **后果**:接近硬上限,后续增加功能即超限
### 2.3 错误处理层面
#### P1-Cclasses 模块组件缺少 Error Boundary 和 Skeleton
- **位置**
- `src/app/(dashboard)/teacher/classes/my/[id]/page.tsx` — 无 Error Boundary
- `src/app/(dashboard)/admin/school/classes/page.tsx` — 无 Error Boundary
- `src/app/(dashboard)/management/grade/dashboard/page.tsx` — 无 Error Boundary
- `src/modules/classes/components/*` — 无骨架屏组件
- **问题**:对比 school 模块已有 `school-error-boundary.tsx` + `school-skeleton.tsx`classes 模块完全没有错误边界和骨架屏组件
- **违反规则**:错误与边界处理(每个独立数据区块必须用 React Error Boundary 包裹;异步数据使用 React Suspense + 骨架屏)
- **后果**:数据加载失败时整页崩溃无降级;加载过程无反馈
#### P1-4`classes/types.ts` 跨领域类型污染
### 2.4 组件质量层面
- **位置**`src/modules/classes/types.ts`
- **问题**:定义了本应属于其他模块的类型:
- `ClassHomeworkInsights` / `GradeHomeworkInsights` / `ClassHomeworkAssignmentStats` / `ScoreStats` / `AssignmentSummary` — 应属 homework 模块
- `ClassScheduleItem` / `StudentScheduleItem` — 与 scheduling 模块概念重叠
- **违反规则**:模块标准结构(类型应归属对应模块)
- **后果**classes 模块承担了 homework/scheduling 的类型定义职责,耦合度高
#### P1-5`school/components/*` 未使用组合模式
- **位置**`src/modules/school/components/schools-view.tsx`
- **问题**`SchoolsClient` 组件内部硬编码了 Table + Dialog + AlertDialog 的完整结构,无法通过 slots/render props 定制。对比 `grade-management` 模块的 `GradeManagementWidget` 通过组合 `GradeListTable` + `GradeListToolbar` + `GradeFormDialog` + `GradeDeleteDialog` 实现灵活性
- **违反规则**:组合优先(所有 UI 通过组件组合实现灵活性)
- **后果**:无法复用表格/对话框子部件;新增角色差异需复制整个组件
### 2.5 数据安全层面
#### P1-6data-access 层部分查询未结合用户权限过滤
#### P1-Dclasses 组件未使用组合模式
- **位置**
- `src/modules/classes/data-access.ts``getTeacherClasses()` 未接收 userId 参数
- `src/modules/school/data-access.ts``getGrades()` / `getSchools()` 返回全量数据,无权限过滤
- **问题**data-access 函数为全局查询,不结合当前用户身份做数据范围过滤,完全依赖 actions 层或页面层校验
- **违反规则**:安全性规范(所有敏感数据查询必须在 data-access 层结合当前用户权限过滤)
- **后果**:若上层遗漏校验(如 P0-4 中 teacher/classes 页面),数据越权访问风险
- `src/modules/classes/components/admin-classes-view.tsx`499 行)— 单体组件包含 Table + Dialog + AlertDialog + Select 全部逻辑
- `src/modules/classes/components/grade-classes-view.tsx`408 行)— 同上
- `src/modules/classes/components/my-classes-grid.tsx`390 行)— 单体组件包含卡片网格 + 加入班级对话框 + 邀请码管理
- **问题**:对比 school 模块已拆分为 `SchoolListToolbar` + `SchoolFormDialog` + `SchoolDeleteDialog` + `useSchoolData` hookclasses 模块仍是单体组件,无法复用子部件
- **违反规则**:组合优先(所有 UI 通过组件组合实现灵活性)
- **后果**admin/grade/teacher 三个视角的班级管理存在大量重复代码(表单、对话框、筛选器),无法复用
### 2.6 可测试性层面
#### P1-Eclasses 模块缺少 hooks 抽取
#### P2-1`school` 和 `classes` 模块逻辑与 UI 耦合,难以单测
- **位置**`school/components/*` / `classes/components/*`
- **问题**:组件内部直接调用 actions、管理状态、处理错误未将数据获取/计算/格式化逻辑抽取为独立 hooks 或纯函数。对比 `grade-management` 模块已抽取 `use-grade-data` / `use-grade-filters` / `use-grade-form` / `use-grade-insights` 四个 hooks
- **位置**`src/modules/classes/` — 无 `hooks/` 目录
- **问题**:对比 school 模块已抽取 `use-school-data` hookclasses 模块的对话框状态管理、表单校验、筛选逻辑全部耦合在组件内部
- **违反规则**:可测试性(数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks与 UI 分离)
- **后果**:无法对筛选逻辑、表单校验逻辑进行独立单测
### 2.5 架构模式层面
#### P2-A缺少 Service 接口抽象和依赖注入
- **位置**:整个 school + classes 模块
- **问题**:组件直接 import data-access 函数,未通过 Service 接口抽象数据依赖。对比已删除的 `grade-management` 模块曾有完整的 `GradeService` 接口 + Context DI 模式
- **违反规则**:完全解耦(通过定义 TypeScript 接口抽象数据依赖,使用 React Context 注入数据服务)
- **后果**:组件与 data-access 直接耦合,难以 mock 测试;不同角色的差异通过 if/else 硬编码而非接口实现隔离
#### P2-B缺少角色配置驱动设计
- **位置**:整个 school + classes 模块
- **问题**admin/teacher/grade 三个视角的班级管理通过 3 套独立的组件实现(`admin-classes-view` / `grade-classes-view` / `my-classes-grid`),而非通过配置驱动同一套组件
- **违反规则**:可扩展性(采用配置驱动设计,通过角色配置决定渲染哪些 Widget
- **后果**:新增角色需复制整套组件;三套组件存在大量重复代码
---
## 三、行业差距对比
### 3.1 与优秀 K12 产品的差距
### 3.1 与优秀 K12 产品的差距v2 更新)
| 功能/交互 | 行业优秀实践Google Classroom / 钉钉教育 / 智学网) | 当前状态 | 影响 |
|----------|------------------------------------------------------|---------|------|
| **学校切换** | 顶部全局学校切换器,切换后所有页面数据联动 | 仅 admin 跨校可见,无全局切换器 | 多校区场景下教师/学生无法快速切换视角 |
| **年级→班级树形导航** | 左侧树形结构(学校→年级→班级),支持展开/折叠/搜索 | 扁平列表,无层级导航 | 班级数量多时查找效率低 |
| **班级详情仪表盘** | 一页聚合:基本信息 + 学生名单 + 课表 + 作业 + 成绩趋势 | `teacher/classes/my/[id]` 已有 class-detail 子组件,但 admin/grade 视角无详情页 | admin/年级组长无法下钻查看班级详情 |
| **批量操作** | 批量导入学生、批量分配教师、批量升级班级 | 仅支持单条 CRUD + 邮箱注册 | 开学季配置效率低 |
| **空状态引导** | 空状态带引导按钮和说明文案 | schools-view 有 EmptyState其他组件不一致 | 新用户不知道下一步该做什么 |
| **加载骨架屏** | 数据加载时显示骨架屏保持布局稳定 | school/classes 组件无骨架屏grade-management 有但未使用) | 加载过程布局跳动,体验差 |
| **邀请码加入** | 二维码 + 链接 + 6 位码三种方式 | 仅 6 位码v3 已支持有效期/次数) | 家长端操作门槛略高 |
| **年级升级** | 学年末一键升级(三年级→四年级),保留历史档案 | 无此功能 | 每年需手动重建班级 |
| **数据权限隔离** | 教师仅看到自己班级年级组长看到年级所有班级admin 看到全部 | teacher/classes 页面无权限校验P0-4data-access 无范围过滤P1-6 | 存在越权风险 |
| 功能/交互 | 行业优秀实践 | 当前状态 | 影响 |
|----------|------------|---------|------|
| **i18n 完整覆盖** | 所有角色所有页面支持多语言 | school 模块 ✅classes 模块 ❌13/14 组件硬编码) | classes 模块无法支持多语言 |
| **错误边界** | 每个数据区块独立 Error Boundary | school 模块 ✅classes 模块 ❌ | classes 数据加载失败整页崩溃 |
| **骨架屏** | 加载时保持布局稳定 | school 模块 ✅classes 模块 ❌ | classes 加载过程布局跳动 |
| **组件复用** | 三个角色共用一套可配置组件 | 三套独立组件admin/grade/teacher | 代码重复,维护成本高 |
| **班级详情仪表盘** | 一页聚合基本信息 + 学生 + 课表 + 作业 + 成绩 | `teacher/classes/my/[id]` 已有,但 admin/grade 视角无 | admin/年级组长无法下钻 |
| **批量操作** | 批量导入学生、批量分配教师 | ✅ 已实现v1 P2-4 修复) | 已达标 |
| **年级升级** | 学年末一键升级 | ✅ 已实现v1 P2-3 修复) | 已达标 |
| **组织树导航** | 学校→年级→班级三级树 | ✅ 已实现v1 P2-2 修复) | 已达标 |
| **邀请码加入** | 6 位码 + 有效期 + 次数 | ✅ 已实现 | 已达标 |
| **数据权限隔离** | data-access 层结合用户权限过滤 | ✅ 已实现v1 P1-6 修复) | 已达标 |
### 3.2 多角色体验差距
| 角色 | 优秀实践 | 当前状态 |
|------|---------|---------|
| **admin** | 统一管理面板,学校/年级/班级三级联动,支持批量配置 | 分散在 4 个独立页面,无联动 |
| **teacher** | 我的班级 + 可加入班级 + 邀请码管理一站式 | 有基本功能,但无权限校验、无 i18n |
| **parent** | 查看孩子所在班级信息、任课教师、班级通知 | 无专属页面(依赖 dashboard 间接展示) |
| **student** | 查看我的班级、同学名单、课表 | 有基本功能,但无权限校验、无 i18n |
| **admin** | 统一管理面板,i18n 完整,错误边界完整 | school 模块 ✅classes 模块 ❌(无 i18n、无 Error Boundary |
| **teacher** | 我的班级 + 邀请码 + 课表 + 学生i18n 完整 | 有基本功能,但 ❌ 无 i18n、❌ 无 Error Boundary |
| **grade_head** | 年级班级管理 + 学情洞察i18n 完整 | 有基本功能,但 ❌ 组件无 i18n |
| **parent** | 查看孩子所在班级信息 | 无专属页面(依赖 dashboard 间接展示) |
| **student** | 查看我的班级、同学名单、课表 | 有基本功能,但 ❌ 无 i18n |
---
## 四、改进优先级建议
### P0紧急 — 安全与架构正确性
### P0紧急 — i18n 与错误处理
| 编号 | 问题 | 改进方向 |
|------|------|---------|
| P0-1 | `grade-management` 模块完全未被使用 | **决策**:要么将 `admin/school/grades` 页面迁移到使用 `grade-management` 模块的 Widget + Service 模式,要么删除该死模块。**推荐迁移**,因为该模块实现了用户要求的全部原则(解耦/组合/i18n/复用/边界/可测试/可扩展) |
| P0-2 | 年级 CRUD 逻辑重复 | 统一到 `grade-management` 模块,`school` 模块仅保留学校/学年/部门 CRUD删除 school 模块中的 grade CRUD |
| P0-3 | `classes/actions.ts` 974 行接近上限 | 按职责拆分为 `actions-teacher.ts` / `actions-admin.ts` / `actions-grade.ts` / `actions-invitations.ts` / `actions-schedule.ts` |
| P0-4 | `teacher/classes/*` 4 页面无权限校验 | 每个页面添加 `requirePermission(Permissions.CLASS_READ)` 或对应权限点 |
| P0-5 | 全部 13 页面无 i18n | 提取翻译键,使用 `getTranslations`(服务端组件)或 `useTranslations`(客户端组件)。补充 `school.json` 翻译文件 |
| P0-A | classes 模块 13/14 个组件未接入 i18n | 为所有 classes 组件接入 `useTranslations("classes")`,提取全部硬编码文本到翻译键 |
| P0-B | classes.json i18n 文件内容不足 | 扩充 `classes.json`,覆盖班级 CRUD、列表、筛选器、详情页、学生管理、课表、详情子组件等全部场景 |
### P1重要 — 代码质量与可维护性)
| 编号 | 问题 | 改进方向 |
|------|------|---------|
| P1-1 | `classes/actions.ts` 角色硬编码 | 将 `ctx.roles.includes("admin")` 改为 `ctx.hasPermission(Permissions.xxx)` `ctx.roles` 中的权限点判断 |
| P1-2 | `school` 模块无 i18n 文件 | 新建 `src/shared/i18n/messages/{zh-CN,en}/school.json` |
| P1-3 | `school/components/*` 缺少 Error Boundary/Skeleton | 参照 `grade-management` 模块的 `grade-error-boundary.tsx` / `grade-skeleton.tsx` 模式补充 |
| P1-4 | `classes/types.ts` 跨领域类型污染 | 将 `ClassHomeworkInsights` 等类型迁移至 homework 模块classes 模块通过 import type 引用 |
| P1-5 | `school/components/*` 未使用组合模式 | 将 `SchoolsClient` 拆分为 `SchoolListTable` + `SchoolFormDialog` + `SchoolDeleteDialog` + `SchoolListToolbar` |
| P1-6 | data-access 层未结合权限过滤 | `getTeacherClasses(userId)` 接收 userId 参数,在查询中过滤 |
| P1-A | `grades-view.tsx` 860 行 | 拆分为 `GradeListSection` + `GradeOverviewSection` + `GradeFormDialog` + `GradeDeleteDialog` + `GradePromoteDialog` + `use-grade-data` hook |
| P1-B | `classes/data-access.ts` 833 行 | 将邀请码相关函数迁移至 `data-access-invitations.ts`,将教师班级管理迁移至 `data-access-teacher.ts` |
| P1-C | classes 模块缺少 Error Boundary/Skeleton | 新增 `class-error-boundary.tsx` + `class-skeleton.tsx`,为所有 classes 页面包裹 |
| P1-D | classes 组件未使用组合模式 | 将 `admin-classes-view` / `grade-classes-view` / `my-classes-grid` 拆分为可复用的 `ClassListTable` + `ClassFormDialog` + `ClassDeleteDialog` + `ClassListToolbar` |
| P1-E | classes 模块缺少 hooks | 抽取 `use-class-data` hook对话框状态管理+ `use-class-filters` hook筛选逻辑 |
### P2优化 — 体验与扩展性
### P2优化 — 架构模式
| 编号 | 问题 | 改进方向 |
|------|------|---------|
| P2-1 | 逻辑与 UI 耦合,难以单测 | 参照 `grade-management` 模块抽取 `use-school-data` / `use-class-data` 等 hooks |
| P2-2 | 缺少年级→班级树形导航 | 新增 `OrgTreeNav` 组件,学校→年级→班级三级树 |
| P2-3 | 缺少年级升级功能 | 新增 `promoteGradeAction`,学年末批量升级 |
| P2-4 | 缺少批量操作 | 批量导入学生、批量分配教师 |
| P2-5 | `school` 模块审计日志不一致 | 为 department/academicYear/grade 的 CRUD 补充 `logAudit` |
### 重构方案设计要点(参照用户强制原则)
1. **完全解耦**:以 `grade-management` 模块的 `GradeService` 接口 + `GradeServiceProvider` Context 注入为范本,为 school 和 classes 模块建立对应的 `SchoolService` / `ClassService` 接口
2. **组合优先**:参照 `GradeManagementWidget` 的组合方式Toolbar + Table + FormDialog + DeleteDialog所有模块的 Widget 通过组合子组件实现
3. **国际化就绪**:翻译文件结构示例
```json
// school.json
{
"schools": { "title": "学校管理", "list": { "title": "学校列表", "empty": "暂无学校" }, "form": { ... } },
"grades": { "title": "年级管理", ... },
"departments": { "title": "部门管理", ... },
"academicYear": { "title": "学年管理", ... }
}
```
4. **最大化复用**:抽取 `OrgCrudWidget<T>` 泛型组件(列表+工具栏+表单+删除school/grade/department 共用
5. **错误与边界**:每个 Widget 用 Error Boundary 包裹,异步数据用 Suspense + 骨架屏
6. **可测试性**:数据获取/筛选/校验逻辑全部抽取为 hooks
7. **可扩展性**:参照 `GRADE_ROLE_CONFIG`,为 school/classes 建立角色配置驱动设计
8. **企业级补充**a11y语义化标签 + ARIA、性能RSC 获取初始数据、安全data-access 层权限过滤)、监控(`GradeAnalyticsTracker` 模式扩展到 school/classes
| P2-A | 缺少 Service 接口抽象 | 定义 `SchoolService` / `ClassService` 接口,通过 Context DI 注入(中长期) |
| P2-B | 缺少角色配置驱动 | 建立 `CLASS_ROLE_CONFIG`,通过配置决定不同角色渲染哪些 Widget中长期 |
---
## 五、架构图同步说明
本次审计发现架构图存在以下遗漏和不一致,需同步更新:
### 5.1 需更新的节点
### 5.1 需补充的节点
| 文档 | 需补充内容 |
| 文档 | 需更新内容 |
|------|-----------|
| `004_architecture_impact_map.md` | 新增 `## 2.X grade-management年级管理模块` 章节,记录其 services/hooks/widgets/config 架构,并标注"⚠️ 该模块当前未被任何 app 页面使用" |
| `004_architecture_impact_map.md` | 在 `## 2.8 school` 章节补充说明school 模块包含 grade CRUD 但与 grade-management 模块职责重叠 |
| `004_architecture_impact_map.md` | 在路由表中补充 `teacher/classes/*` 4 个页面缺少 `requirePermission` 的标注 |
| `005_architecture_data.json` | `modules` 节点新增 `grade-management` 模块及其 exports/dependencies |
| `005_architecture_data.json` | `dependencyMatrix` 新增 grade-management → classes通过 data-access、grade-management → school 的依赖关系 |
| `005_architecture_data.json` | `routes` 节点补充 teacher/classes/* 的权限缺失标注 |
| `004_architecture_impact_map.md` §2.7 classes | 更新组件 i18n 状态(❌ → ✅)、更新 Error Boundary 状态(❌ → ✅)、更新组合模式状态、更新文件行数 |
| `004_architecture_impact_map.md` §2.8 school | 更新 `grades-view.tsx` 行数860 → 拆分后)、更新组件拆分情况 |
| `005_architecture_data.json` | 更新 classes 模块的 i18n/errorBoundary/composition 状态标记 |
### 5.2 需修改的节点
### 5.2 实施后同步
| 文档 | 需修改内容 |
|------|-----------|
| `004_architecture_impact_map.md` §2.7 classes | 更新 `actions.ts` 行数676 → 974标注接近硬上限 |
| `004_architecture_impact_map.md` §2.8 school | 更新 `data-access.ts` 行数186 → 504补充新增的跨模块查询函数`getGradeNameById` / `getSubjectNameById` / `isGradeHead` / `isGradeManager` / `findGradeIdByHeadAndName` |
### 5.3 i18n 翻译文件结构示例
```
src/shared/i18n/messages/
├─ zh-CN/
│ ├─ school.json ← 新增(学校/学年/部门管理翻译键)
│ ├─ grade.json ← 已存在年级管理翻译键grade-management 模块用)
│ └─ classes.json ← 已存在(班级管理翻译键,需扩充)
└─ en/
├─ school.json ← 新增
├─ grade.json ← 已存在
└─ classes.json ← 已存在
```
本次审计实施后,需同步更新:
- classes 模块的 i18n 接入状态
- classes 模块的 Error Boundary/Skeleton 新增
- grades-view.tsx 拆分后的文件清单
- classes/data-access.ts 拆分后的文件清单
- classes 组件拆分后的文件清单
---
## 附录:审计检查清单
## 附录:审计检查清单v2
| 检查项 | school | grade-management | classes |
|--------|:------:|:---------------:|:-------:|
| 三层架构划分合理 | ✅ | ✅ | ⚠️ actions.ts 过大 |
| 文件大小符合规范 | ✅ | ✅ | ❌ actions.ts 974 行 |
| 无跨模块直接依赖 | ✅ | ✅ | |
| Server Action 权限校验 | ✅ | ✅ | ⚠️ 角色硬编码 |
| 前端无 role 硬编码 | ✅ | ✅ | |
| i18n 适配 | | ✅(组件层) | ❌ |
| 错误处理/边界 | ❌ | ✅ | ❌ |
| 骨架屏/空状态 | ⚠️ 部分 | ✅ | ⚠️ 部分 |
| 逻辑与 UI 分离 | ❌ | ✅ | ⚠️ 部分 |
| 组合模式 | | ✅ | ⚠️ 部分 |
| 配置驱动 | ❌ | | |
| 被页面实际使用 | ✅ | ❌ **死模块** | ✅ |
| 审计日志完整 | ⚠️ 不一致 | | |
| 监控埋点接口 | ❌ | ✅(预留) | ❌ |
| 检查项 | school | classes | 状态 |
|--------|:------:|:-------:|------|
| 三层架构划分合理 | ✅ | ✅ | v1 已修复 |
| 文件大小符合规范 | ⚠️ grades-view 860 行 | ⚠️ data-access 833 行 | P1-A/P1-B |
| 无跨模块直接依赖 | ✅ | ✅ | v1 已修复 |
| Server Action 权限校验 | ✅ | ✅ | v1 已修复 |
| 前端无 role 硬编码 | ✅ | ✅ | v1 已修复 |
| i18n 适配 | | ❌ 13/14 组件未接入 | P0-A/P0-B |
| 错误处理/边界 | ✅ | ❌ 无 Error Boundary | P1-C |
| 骨架屏/空状态 | ✅ | ⚠️ 有空状态无骨架屏 | P1-C |
| 逻辑与 UI 分离 | ✅ use-school-data | ❌ 无 hooks | P1-E |
| 组合模式 | | ❌ 三套单体组件 | P1-D |
| 配置驱动 | ❌ | | P2-B中长期 |
| 审计日志完整 | ✅ | ✅ | v1 已修复 |
| 监控埋点接口 | ❌ | | P2中长期 |