Files
NextEdu/docs/architecture/audit/archive/textbooks-audit-report-v3.md

410 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 教材Textbooks模块审计报告 v3
> 审计日期2026-06-24
> 审计范围:`src/modules/textbooks/**`、`src/app/(dashboard)/teacher/textbooks/**`、`src/app/(dashboard)/student/learning/textbooks/**`
> 对比基准:[textbooks-audit-report-v2.md](./textbooks-audit-report-v2.md)v2
> 参照规则:`docs/architecture/004_architecture_impact_map.md`、`docs/architecture/005_architecture_data.json`、`.trae/rules/project_rules.md`
---
## 一、现有实现概要
### 1.1 模块定位
教材模块是 K12 系统的"标杆模块"(架构图 004 第 2.5 节明确标注),承担**教材与知识体系管理**职责:
- 教材/章节树形结构 CRUD
- 知识点 CRUD + Markdown 内容编辑
- 知识图谱可视化React Flow + dagre 布局)
- 知识点前置依赖管理(含循环检测)
- 学生/班级掌握度聚合查询
### 1.2 文件分布与规模
| 层 | 文件数 | 总行数 | 最大文件 | 备注 |
|----|--------|--------|----------|------|
| 模块核心modules/textbooks | 26 | ~3,800 | `data-access.ts` 662 行 | 含 5 个 hooks、16 个组件 |
| App 层 - 教师 | 6 | ~350 | `[id]/page.tsx` 66 行 | 含 loading/error |
| App 层 - 学生 | 6 | ~240 | `page.tsx` 86 行 | 含 loading/error |
| 测试 | 2 | ~200 | `utils.test.ts` | 纯函数单测 |
### 1.3 数据流概览
```
┌─────────────────────────────────────────────────────────────────┐
│ App 层RSC
│ teacher/textbooks/page.tsx ──┐ │
│ student/learning/textbooks/page.tsx ──┤ │
└────────────────────────────────┼─────────────────────────────────┘
│ 直接调用 data-access
┌─────────────────────────────────────────────────────────────────┐
│ modules/textbooks │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ actions.ts │──▶│ data-access.ts│──▶│ data-access-graph.ts│ │
│ │ (14 Actions) │ │ (662 行) │ │ (207 行, 图谱只读) │ │
│ └──────────────┘ └──────────────┘ └────────────────────┘ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────────────┐ ┌──────────────┐ │
│ │ │ utils.ts │ │ graph-layout │ │
│ │ │ (225 行纯函数)│ │ (121 行纯函数)│ │
│ │ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ components/16 个组件)+ hooks/5 个 Hook │ │
│ │ textbook-reader / knowledge-graph / chapter-sidebar-list │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
▼ 跨模块依赖(通过 data-access合规
┌─────────────────────────────────────────────────────────────────┐
│ users.data-accessgetCurrentStudentUser
│ classes.data-access-studentsgetClassStudents
│ school.data-accessgetGradeNameById
└─────────────────────────────────────────────────────────────────┘
```
### 1.4 架构图记录完整性评估
| 架构图节点 | 记录状态 | 差异 |
|------------|----------|------|
| 004 § 2.5 textbooks | ✅ 完整 | 导出函数、依赖、已知问题、文件清单均已记录 |
| 005 textbooks 节点 | ✅ 完整 | actions/dataAccess/hooks/types/components/files 均已记录 |
| 已知问题记录 | ⚠️ 部分过期 | 005 `knownIssues` 仍写"i18n 覆盖率约 98%"实际审计发现残留硬编码英文异常文案、a11y 缺失等问题未记录 |
**结论**:架构图对教材模块的覆盖度约 90%,主要差距在 `knownIssues` 字段未同步最新审计发现。
---
## 二、现存问题与原因分析
### 2.1 安全与权限维度P0
#### 问题 T-AUDIT-01 学生端页面缺少 `requirePermission` 显式校验
- **位置**[student/learning/textbooks/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/learning/textbooks/page.tsx)、[student/learning/textbooks/[id]/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/learning/textbooks/[id]/page.tsx)
- **现象**:两个学生端页面均未调用 `requirePermission(Permissions.TEXTBOOK_READ)`,仅靠 `getCurrentStudentUser()` 隐式校验角色。对比教师端 [teacher/textbooks/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/textbooks/page.tsx) 第 18 行显式调用 `requirePermission`
- **违反规则**`project_rules.md` → "Server Action 规范" → "每个 Action 必须调用 `requirePermission()` 进行权限校验";以及"安全规范" → "所有敏感数据查询必须在 data-access 层结合当前用户权限过滤Server Action 二次校验"
- **原因**:学生端页面是 RSC 直接调用 data-access非 Server Action开发者认为 `getCurrentStudentUser` 已隐含角色校验,但权限点 `TEXTBOOK_READ` 未被显式校验,无法通过权限矩阵灵活调整
- **后果**:若未来权限矩阵调整(如临时禁止某学生查看教材),学生端无法响应;权限审计日志缺失"教材阅读"事件
#### 问题 T-AUDIT-02 `getKnowledgeGraphDataAction` 缺少数据范围过滤
- **位置**[actions.ts](file:///e:/Desktop/CICD/src/modules/textbooks/actions.ts) 第 373-413 行
- **现象**`getKnowledgeGraphDataAction` 仅校验 `TEXTBOOK_READ` 权限,未按学生年级做 scope 过滤(对比 `getTextbooksWithScope` 有 scope.grade 过滤)。学生可传任意 `textbookId` 查看跨年级教材的图谱数据
- **违反规则**`project_rules.md` → "安全规范" → "所有敏感数据查询必须在 data-access 层结合当前用户权限过滤"
- **原因**:图谱查询是 Task 7 新增功能,开发时复用了教师端逻辑,未区分学生数据范围
- **后果**:学生可越权查看非本年级教材的知识图谱与掌握度数据
#### 问题 T-AUDIT-03 `class-mastery` 视图缺少教师-班级归属校验
- **位置**[actions.ts](file:///e:/Desktop/CICD/src/modules/textbooks/actions.ts) 第 393-403 行
- **现象**`getKnowledgeGraphDataAction``class-mastery` 分支调用 `getClassStudents({ status: "active" })` 获取全量班级学生 ID未校验当前教师是否拥有这些班级
- **违反规则**`project_rules.md` → "安全规范" → "Server Action 二次校验"
- **原因**:直接调用 classes 模块的 `getClassStudents` 未传入教师 scope
- **后果**:任何持有 `TEXTBOOK_READ` 权限的教师可查看全校所有班级的掌握度数据
### 2.2 数据完整性维度P0
#### 问题 T-AUDIT-04 `deleteChapter` 未清理孤儿前置依赖记录
- **位置**[data-access.ts](file:///e:/Desktop/CICD/src/modules/textbooks/data-access.ts) 第 259-298 行
- **现象**:递归删除章节及其知识点时,未删除 `knowledgePointPrerequisites` 表中引用被删知识点的边(包括作为 `prerequisiteKpId` 的记录)
- **违反规则**:数据完整性最佳实践
- **原因**:删除逻辑只关注了 `knowledgePoints` 表本身,遗漏了外键关联表
- **后果**:图谱渲染时出现指向已删除知识点的孤儿边,循环检测算法 `hasCycleAfterAddingEdge` 可能因引用不存在节点而异常
### 2.3 类型安全维度P1
#### 问题 T-AUDIT-05 `as` 断言违反规范
- **位置**
- [data-access.ts](file:///e:/Desktop/CICD/src/modules/textbooks/data-access.ts) 第 661 行 `as [string, string]`
- [knowledge-point-dialogs.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/knowledge-point-dialogs.tsx) 第 84 行 `as (formData: FormData) => void`
- [graph-kp-node.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/graph-kp-node.tsx) 第 35、37 行 `as unknown as GraphLayoutNodeData`(双重断言,缺注释)
- **违反规则**`project_rules.md` → "TypeScript 规则" → "禁止 `as` 断言(除非从 `unknown` 转换或测试中,需注释原因)"
- **原因**React Flow 的 `NodeProps` 类型与自定义数据结构不匹配,开发者用 `as unknown as` 绕过类型检查
- **后果**:类型安全被削弱,运行时可能因数据形状不符而崩溃
#### 问题 T-AUDIT-06 类型与 DB Schema 不一致
- **位置**[types.ts](file:///e:/Desktop/CICD/src/modules/textbooks/types.ts)
- **现象**
- 第 42 行 `KnowledgePoint.chapterId?: string`(可选),但 DB schema 中该字段非空
- 第 13 行 `Textbook.grade: string | null`(可空),但 `CreateTextbookSchema.grade` 要求 `min(1)` 非空
- **违反规则**`project_rules.md` → "TypeScript 规则" → "禁止 `any`"
- **原因**:类型手动定义而非从 Drizzle schema 推断types.ts 第 1-3 行注释承认)
- **后果**:下游需大量 `?? undefined` 兜底data-access.ts 第 320、347 行),类型契约不可信
### 2.4 错误处理维度P0/P1
#### 问题 T-AUDIT-07 前置依赖操作无 try/catchloading 状态卡死
- **位置**[knowledge-graph.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/knowledge-graph.tsx) 第 202-219 行(`handleAddPrerequisite`)、第 222-235 行(`handleRemovePrerequisite`
- **现象**:两个函数均无 try/catch若 action 抛异常,`setIsSavingPrereq(false)` 不会执行
- **违反规则**`project_rules.md` → "错误处理" 隐含要求
- **原因**:开发者假设 Server Action 不会抛异常(实际网络异常、服务端 500 均会抛)
- **后果**:用户点击"添加前置依赖"失败后,按钮永久 loading需刷新页面
#### 问题 T-AUDIT-08 `textbook-reader.tsx` `onCreateKnowledgePoint` 无 try/catch
- **位置**[textbook-reader.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-reader.tsx) 第 177-181 行
- **现象**`onCreateKnowledgePoint` 回调中调用 `handleCreateKnowledgePoint`,无 try/catch异常时 `setIsCreating(false)` 不执行
- **后果**创建知识点失败时UI 永久显示创建中状态
#### 问题 T-AUDIT-09 `section-error-boundary.tsx` 缺 `componentDidCatch`
- **位置**[section-error-boundary.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/section-error-boundary.tsx)
- **现象**:仅实现 `getDerivedStateFromError`,未实现 `componentDidCatch`,错误被吞没未上报
- **违反规则**React Error Boundary 最佳实践
- **后果**:生产环境无法追踪章节内容渲染错误
#### 问题 T-AUDIT-10 4 个 error.tsx 完全重复且未记录日志
- **位置**4 个 error.tsx 文件(教师/学生 × 列表/详情)
- **现象**:内容完全相同(仅函数名不同),`error` 参数接收但未 `console.error` 记录、未展示 `error.digest`、未区分错误类型
- **违反规则**DRY 原则、Next.js error.tsx 最佳实践
- **后果**错误无法追踪4 份重复代码维护成本高
### 2.5 国际化维度P1
#### 问题 T-AUDIT-11 data-access 层硬编码英文异常文案
- **位置**[data-access.ts](file:///e:/Desktop/CICD/src/modules/textbooks/data-access.ts) 第 188、244、383 行
- **现象**`throw new Error("Textbook not found")` / `"Chapter not found"` 等英文硬编码
- **违反规则**`project_rules.md` → "所有用户可见文本必须适配 i18n"
- **原因**data-access 层无法直接调用 `getTranslations`(需 async context
- **后果**:错误冒泡到 `handleActionError` 后,非英文用户看到英文错误信息
#### 问题 T-AUDIT-12 `use-graph-data.ts` 错误状态值类型不一致
- **位置**[use-graph-data.ts](file:///e:/Desktop/CICD/src/modules/textbooks/hooks/use-graph-data.ts) 第 60、66 行
- **现象**`error` 状态有时是服务端已翻译文案(`result.message`),有时是原始 i18n key 字符串(`"graph.error.loadFailed"`),有时是 JS Error.message
- **后果**:下游组件无法判断该直接显示还是再 `t()` 翻译
### 2.6 可访问性维度P1
#### 问题 T-AUDIT-13 章节项可点击 div 无键盘支持
- **位置**[chapter-sidebar-list.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/chapter-sidebar-list.tsx) 第 100-110 行
- **现象**:章节项点击区是 `<div onClick>`,缺少 `role="button"``tabIndex={0}``onKeyDown`
- **违反规则**WCAG 2.1 AA → 键盘可达性
- **后果**:键盘用户无法选中章节
#### 问题 T-AUDIT-14 图标按钮缺 `aria-label`
- **位置**[graph-node-detail-panel.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/graph-node-detail-panel.tsx) 第 45、139-146 行
- **现象**关闭按钮X 图标、删除前置按钮Trash2 图标)无 `aria-label`
- **后果**:屏幕阅读器用户无法识别按钮用途
#### 问题 T-AUDIT-15 loading.tsx 缺少 ARIA 标记
- **位置**4 个 loading.tsx 文件
- **现象**:根容器缺少 `role="status"``aria-busy="true"`
- **后果**:屏幕阅读器无法感知加载状态
#### 问题 T-AUDIT-16 error.tsx 缺少 `role="alert"`
- **位置**4 个 error.tsx 文件
- **现象**:错误容器缺少 `role="alert"`,屏幕阅读器不会自动播报错误
### 2.7 跨模块耦合维度P1
#### 问题 T-AUDIT-17 跨模块 URL 硬编码
- **位置**
- [graph-node-detail-panel.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/graph-node-detail-panel.tsx) 第 101 行 `<Link href={`/teacher/questions?kp=${kp.id}`}>`
- [textbook-reader.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-reader.tsx) 第 378 行 `<Link href={`/teacher/lesson-plans/new?...`}>`
- [textbook-card.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-card.tsx) 第 47 行 `hrefBase` 默认值 `/teacher/textbooks`
- [textbook-settings-dialog.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-settings-dialog.tsx) 第 80 行 `router.push("/teacher/textbooks")`
- **现象**:组件内硬编码角色前缀 URL`/teacher/...`),无法复用于学生/家长端
- **违反规则**`project_rules.md` → "前端组件禁止使用 `role === "xxx"` 硬编码"URL 硬编码角色前缀同理)
- **原因**:组件未通过 props 注入路由前缀
- **后果**:组件无法跨角色复用;新增角色需修改组件源码
### 2.8 代码质量维度P2
#### 问题 T-AUDIT-18 `use-kp-crud.ts` 行数超限
- **位置**[hooks/use-kp-crud.ts](file:///e:/Desktop/CICD/src/modules/textbooks/hooks/use-kp-crud.ts) 122 行
- **现象**:超过 Hook 上限 80 行
- **违反规则**`project_rules.md` → "自定义 Hook建议 ≤ 80 行"
- **原因**CRUD 操作集中在一个 Hook
- **后果**:维护困难
#### 问题 T-AUDIT-19 表单字段代码重复
- **位置**[textbook-form-dialog.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-form-dialog.tsx) 与 [textbook-settings-dialog.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-settings-dialog.tsx)
- **现象**表单字段title/subject/grade/publisher几乎完全相同应抽取共享 `TextbookFormFields` 组件
- **违反规则**DRY 原则
- **后果**:字段变更需同步修改两处
#### 问题 T-AUDIT-20 死代码
- **位置**
- [data-access.ts](file:///e:/Desktop/CICD/src/modules/textbooks/data-access.ts) `verifyKnowledgePointBelongsToChapter`(全项目未使用)
- [schema.ts](file:///e:/Desktop/CICD/src/modules/textbooks/schema.ts) `ReorderChaptersSchema`(未使用)
- [textbook-reader.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-reader.tsx) `canEdit` deprecated prop
- **违反规则**:代码整洁
- **后果**:增加维护负担
#### 问题 T-AUDIT-21 `textbook-content-panel.tsx` props 膨胀
- **位置**[textbook-content-panel.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-content-panel.tsx) 17 个 props
- **现象**props 过多,违反组合优先原则
- **违反规则**`project_rules.md` → "组合优先"
- **原因**:编辑态、内容态、选区态未分离
- **后果**:组件难以复用和测试
#### 问题 T-AUDIT-22 函数返回类型未显式标注
- **位置**`use-knowledge-point-actions.ts``use-kp-dialog-state.ts``use-text-selection.ts``use-graph-data.ts``constants.ts``getSubjectColor` 等)
- **违反规则**`project_rules.md` → "函数返回值必须显式标注,特别是 `Promise<T>`"
- **后果**:类型推导不透明
### 2.9 性能与可测试性维度P2
#### 问题 T-AUDIT-23 `textbook-reader.tsx` 命令式 DOM 操作
- **位置**[textbook-reader.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-reader.tsx) 第 229-235 行
- **现象**`document.querySelector(\`[data-kp-id="${highlightedKpId}"]\`)` + `el.classList.add/remove`
- **风险**:模板字符串选择器存在选择器注入风险;命令式 DOM 操作与 React 数据流冲突
- **后果**:难以测试、潜在 XSS
#### 问题 T-AUDIT-24 `graph-layout.ts` O(n²) 性能
- **位置**[graph-layout.ts](file:///e:/Desktop/CICD/src/modules/textbooks/graph-layout.ts) 第 56、64、89、103 行
- **现象**:多次 `knowledgePoints.some(...)` 线性查找
- **后果**:大图谱(>100 节点)性能差
#### 问题 T-AUDIT-25 `cache()` 包裹影响可测试性
- **位置**[data-access.ts](file:///e:/Desktop/CICD/src/modules/textbooks/data-access.ts)、[data-access-graph.ts](file:///e:/Desktop/CICD/src/modules/textbooks/data-access-graph.ts)
- **现象**:所有查询用 `cache()` 包裹,测试时需处理 React cache 上下文
- **后果**:单元测试需额外 mock
---
## 三、行业差距对比
基于对 PowerSchool、Veracross、钉钉教育、智学网、班级小管家、ClassIn、智慧树等 K12 产品的调研,教材模块相比行业优秀实践存在以下差距:
### 3.1 功能差距
| 差距项 | 行业实践 | 当前实现 | 影响角色 |
|--------|----------|----------|----------|
| **多角色视图缺失** | admin 全校教材管理、parent 查看子女教材 | 仅 teacher/student 两端 | admin、parent |
| **教材版本管理** | 支持多版本教材对比、历史版本回滚 | 无版本概念 | teacher、admin |
| **协作编辑** | 多教师协作编辑同一教材(锁机制/CRDT | 单人编辑,无锁 | teacher |
| **离线阅读** | 移动端缓存章节内容离线访问 | 无离线缓存 | student |
| **PDF/打印导出** | 章节导出为 PDF、打印友好版式 | 无导出功能 | teacher、student |
| **阅读进度追踪** | 记录学生阅读进度、停留时长 | 无进度追踪 | student、teacher |
| **教材资源附件** | 章节关联视频、音频、PDF 附件 | 仅 Markdown 文本 | teacher、student |
| **知识点掌握度联动** | 图谱节点点击跳转至相关题目/作业练习 | 仅展示掌握度,无跳转练习入口 | student |
| **教材评论/批注** | 教师可在章节内添加批注,学生可见 | 无批注功能 | teacher、student |
| **智能推荐** | 基于掌握度推荐复习路径 | `analytics.tsx` 仅预留接口,未实现 | student |
### 3.2 UI/UX 差距
| 差距项 | 行业实践 | 当前实现 | 影响 |
|--------|----------|----------|------|
| **骨架屏布局不匹配** | 骨架屏与实际页面结构一致 | [id]/loading.tsx 渲染 grid+sidebar实际是阅读器布局 | 用户体验割裂 |
| **空状态引导** | 空状态提供"创建教材"CTA 按钮 | 仅文字提示 | 转化率低 |
| **筛选持久化** | 筛选条件持久化到 URLnuqs | 部分持久化,不一致 | 刷新丢失筛选 |
| **移动端阅读体验** | 上下滑动阅读、字号调节、夜间模式 | 有 Sheet 抽屉,无字号/主题调节 | 阅读体验差 |
| **图谱交互** | 节点拖拽、缩放、小地图、方向键导航 | 有拖拽/缩放,缺方向键导航 | 键盘用户不可达 |
### 3.3 架构差距
| 差距项 | 行业实践 | 当前实现 | 影响 |
|--------|----------|----------|------|
| **配置驱动** | 角色配置决定渲染哪些 Widget | 组件内硬编码角色 URL | 新增角色需改组件 |
| **依赖注入** | 通过 Context 注入数据服务 | 组件直接调用 data-access | 难以 mock 测试 |
| **错误恢复** | 错误边界提供重试按钮 + 自动上报 | 仅 router.refresh无上报 | 错误不可追踪 |
| **监控埋点** | 关键操作(创建/删除/阅读)埋点 | `analytics.tsx` 仅 stub | 无行为数据 |
---
## 四、改进优先级建议
### 4.1 P0紧急安全与数据完整性
| 编号 | 问题 | 改进方向 | 影响范围 |
|------|------|----------|----------|
| T-FIX-01 | T-AUDIT-01 学生端缺 requirePermission | 学生端两个页面添加 `requirePermission(Permissions.TEXTBOOK_READ)` | 2 文件 |
| T-FIX-02 | T-AUDIT-02 图谱缺 scope 过滤 | `getKnowledgeGraphDataAction` 学生端按年级 scope 过滤 textbookId | actions.ts |
| T-FIX-03 | T-AUDIT-03 class-mastery 缺教师-班级校验 | 传入教师 scope校验班级归属 | actions.ts |
| T-FIX-04 | T-AUDIT-04 deleteChapter 孤儿记录 | 级联删除 `knowledgePointPrerequisites` 表相关记录 | data-access.ts |
| T-FIX-05 | T-AUDIT-07/08 前置依赖/创建知识点无 try/catch | 补 try/catch/finallyfinally 中复位 loading | knowledge-graph.tsx、textbook-reader.tsx |
| T-FIX-06 | T-AUDIT-09 Error Boundary 缺 componentDidCatch | 添加 `componentDidCatch` 记录错误 | section-error-boundary.tsx |
### 4.2 P1重要规范合规
| 编号 | 问题 | 改进方向 | 影响范围 |
|------|------|----------|----------|
| T-FIX-07 | T-AUDIT-05 as 断言 | 用 `NodeProps<GraphLayoutNodeData>` 泛型替代双重断言data-access 用 `satisfies` | 3 文件 |
| T-FIX-08 | T-AUDIT-06 类型与 DB Schema 不一致 | chapterId 改为必填grade 与 schema 对齐 | types.ts |
| T-FIX-09 | T-AUDIT-10 error.tsx 重复 | 抽取 `shared/components/error-boundary.tsx` 共享组件 | 4 文件 → 1 共享 |
| T-FIX-10 | T-AUDIT-11 data-access 硬编码英文 | 改用错误码actions 层翻译 | data-access.ts |
| T-FIX-11 | T-AUDIT-12 错误状态值类型不一致 | 统一为 i18n key 或错误码 | use-graph-data.ts |
| T-FIX-12 | T-AUDIT-13 章节项无键盘支持 | 添加 `role="button"`/`tabIndex`/`onKeyDown` | chapter-sidebar-list.tsx |
| T-FIX-13 | T-AUDIT-14 图标按钮缺 aria-label | 添加 `aria-label` | graph-node-detail-panel.tsx |
| T-FIX-14 | T-AUDIT-15/16 loading/error 缺 ARIA | 添加 `role="status"`/`aria-busy`/`role="alert"` | 8 文件 |
| T-FIX-15 | T-AUDIT-17 跨模块 URL 硬编码 | 通过 props 注入 `hrefBase`,移除角色前缀 | 4 文件 |
| T-FIX-16 | T-AUDIT-18 use-kp-crud 行数超限 | 按 create/update/delete 拆为 3 个子 Hook | use-kp-crud.ts |
### 4.3 P2优化代码质量
| 编号 | 问题 | 改进方向 | 影响范围 |
|------|------|----------|----------|
| T-FIX-17 | T-AUDIT-19 表单字段重复 | 抽取 `TextbookFormFields` 共享组件 | 2 文件 |
| T-FIX-18 | T-AUDIT-20 死代码 | 删除 `verifyKnowledgePointBelongsToChapter``ReorderChaptersSchema``canEdit` prop | 3 文件 |
| T-FIX-19 | T-AUDIT-21 props 膨胀 | 拆分为编辑态/内容态/选区态 Context | textbook-content-panel.tsx |
| T-FIX-20 | T-AUDIT-22 返回类型未标注 | 显式标注所有 Hook/工具函数返回类型 | 5 文件 |
| T-FIX-21 | T-AUDIT-23 命令式 DOM 操作 | 改用 React 状态驱动高亮 | textbook-reader.tsx |
| T-FIX-22 | T-AUDIT-24 O(n²) 性能 | 预建 Set 替代 `some()` | graph-layout.ts |
| T-FIX-23 | T-AUDIT-25 cache() 可测试性 | 导出非 cache 版本供测试 | data-access.ts |
### 4.4 中长期计划P3功能增强
| 编号 | 功能 | 优先级 | 说明 |
|------|------|--------|------|
| T-FEAT-01 | admin/parent 端教材视图 | 中 | 复用现有组件,新增配置驱动 |
| T-FEAT-02 | 教材版本管理 | 低 | 新增 `textbook_versions` 表 |
| T-FEAT-03 | PDF/打印导出 | 中 | 服务端生成 PDF |
| T-FEAT-04 | 阅读进度追踪 | 中 | 新增 `reading_progress` 表 |
| T-FEAT-05 | 教材资源附件 | 中 | 章节关联 files 模块 |
| T-FEAT-06 | 智能推荐学习路径 | 低 | 接入 AI 模块 |
| T-FEAT-07 | 图谱方向键导航 | 低 | React Flow 键盘交互 |
| T-FEAT-08 | 监控埋点接入 | 中 | 实现 `analytics.tsx` 真实逻辑 |
---
## 五、架构图同步说明
### 5.1 需要更新的节点
| 文档 | 节点 | 修改内容 |
|------|------|----------|
| 004 § 2.5 | 已知问题 | 新增 v3 审计发现:学生端缺 requirePermission、图谱缺 scope 过滤、deleteChapter 孤儿记录、error.tsx 重复、a11y 缺失等 |
| 004 § 2.5 | 文件清单 | 更新行数(如 use-kp-crud 拆分后行数变化) |
| 005 textbooks.knownIssues | knownIssues | 同步上述新发现 |
| 005 textbooks.files | files | 同步行数变化 |
### 5.2 无需修改的部分
- 导出函数清单:本次审计未发现新增/删除/重命名导出函数
- 依赖关系:未新增跨模块依赖
- 权限点:未新增权限点
- 数据库表:未新增表(中长期计划中的新表待实施时再同步)
---
## 附录:审计方法说明
- **审计基准**2026-06-24 代码库快照
- **审计工具**:人工阅读全部 26 个模块文件 + 13 个 app 层文件
- **覆盖维度**:安全/权限、数据完整性、类型安全、错误处理、i18n、a11y、跨模块耦合、代码质量、性能、可测试性
- **未覆盖**E2E 测试、性能压测、安全渗透测试(建议后续补充)