# 知识图谱重构设计文档

- **日期**：2026-06-22
- **模块**：textbooks
- **范围**：知识图谱功能全面重构
- **状态**：已批准，待实现

## 1. 背景与动机

### 1.1 当前问题

教材模块的知识图谱功能（[knowledge-graph.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/knowledge-graph.tsx)）处于"基本无用"状态：

- **静态 SVG 树状布局**：仅 `parentId` 父子关系，无前置依赖
- **仅显示当前章节**：无法跨章节/全书查看知识体系
- **交互单一**：点击节点仅高亮正文，无缩放/平移/拖拽/键盘导航
- **信息密度低**：节点只有名称，无关联题目数、无掌握度
- **无师生区分**：教师和学生看到相同的图，无学情数据

### 1.2 同类平台调研

| 平台 | 核心设计 | 可借鉴点 |
|------|---------|---------|
| 人教数字教材 | 按学科/章节聚合的层级图，节点关联资源 | 跨章节聚合 + 资源关联 |
| Khan Academy | 力导向图，前置依赖边，节点显示掌握度 | 前置依赖 + 掌握度 + 跳转练习 |
| 学而思/猿辅导 | 学习路径图，红/黄/绿表示掌握度 | 掌握度色彩 + 路径推荐 |
| ClassIn/Seewo | 师生双视角，教师看班级整体 | 师生双视角 |
| 洋葱学院 | 章节→知识点→题目三级下钻 | 下钻交互 + 缩放 |

**共性特征**：① 跨章节/全书视图 ② 前置依赖关系 ③ 掌握度可视化 ④ 关联题目/资源 ⑤ 缩放平移 ⑥ 师生双视角

### 1.3 已有可复用数据

- `questionsToKnowledgePoints` 关联表（题目↔知识点多对多）
- `knowledgePointMastery` 表（学生掌握度，已被 `diagnostic` 模块填充）
- `questions` 模块已支持按 `knowledgePointId` 筛选
- `@xyflow/react`（React Flow 12）已在 `lesson-preparation` 模块使用

## 2. 设计目标

1. **跨章节全书视图**：支持单章节和全书两种范围切换
2. **前置依赖关系**：新增数据模型，支持声明任意知识点间的前置依赖
3. **掌握度可视化**：学生看个人，教师看班级，红/黄/绿/灰着色
4. **关联题目预览**：节点显示关联题目数，详情面板可跳转题目库
5. **缩放平移交互**：React Flow 内置画布交互
6. **师生双视角**：同一组件，通过 prop 注入不同数据源
7. **侧边栏详情面板**：点击节点显示详情，不离开当前页面

## 3. 数据模型扩展

### 3.1 新增表：knowledge_point_prerequisites

```typescript
export const knowledgePointPrerequisites = mysqlTable("knowledge_point_prerequisites", {
  id: id("id").primaryKey(),
  knowledgePointId: varchar("knowledge_point_id", { length: 128 }).notNull()
    .references(() => knowledgePoints.id, { onDelete: "cascade" }),
  prerequisiteKpId: varchar("prerequisite_kp_id", { length: 128 }).notNull()
    .references(() => knowledgePoints.id, { onDelete: "cascade" }),
  createdAt: timestamp("created_at").defaultNow().notNull(),
}, (table) => ({
  kpPairPk: primaryKey({ columns: [table.knowledgePointId, table.prerequisiteKpId] }),
  kpIdx: index("kp_prereq_kp_idx").on(table.knowledgePointId),
  prereqIdx: index("kp_prereq_prereq_idx").on(table.prerequisiteKpId),
}))
```

**设计说明**：
- 多对多自关联表，表达"学习 KP_B 前应先掌握 KP_A"
- `knowledgePointId` = 目标知识点，`prerequisiteKpId` = 前置知识点
- 联合主键防止重复声明
- 级联删除：知识点删除时自动清理关联
- 循环依赖检测由 Server Action 层 DFS 校验，拒绝形成环的声明

### 3.2 不修改的表

- `knowledgePoints`：已有 `parentId`（树归属）和 `chapterId`（章节归属），不变
- `knowledgePointMastery`：已有 `masteryLevel`/`totalQuestions`/`correctQuestions`，不变
- `questionsToKnowledgePoints`：不变

## 4. 架构与模块结构

### 4.1 新增文件清单

```
src/modules/textbooks/
├─ data-access-graph.ts              # 新增：图谱专用数据访问
├─ components/
│  ├─ knowledge-graph.tsx            # 重写：React Flow 渲染器
│  ├─ graph-node-detail-panel.tsx    # 新增：节点详情侧边栏
│  ├─ graph-kp-node.tsx              # 新增：React Flow 自定义节点
│  ├─ graph-prerequisite-edge.tsx    # 新增：React Flow 自定义边
│  └─ graph-toolbar.tsx              # 新增：视图切换/筛选/搜索工具栏
└─ hooks/
   └─ use-graph-data.ts              # 新增：图谱数据加载与缓存 Hook
```

### 4.2 修改的文件

| 文件 | 修改内容 |
|------|---------|
| `src/shared/db/schema.ts` | 新增 `knowledgePointPrerequisites` 表定义 |
| `data-access.ts` | 新增 prerequisite CRUD 函数 |
| `actions.ts` | 新增 3 个 Server Action |
| `schema.ts` | 新增 prerequisite 声明的 Zod 校验 |
| `types.ts` | 新增 `GraphNodeData` / `GraphViewMode` / `KpWithRelations` 等类型 |
| `graph-layout.ts` | 重写：调用 dagre，保留纯函数签名 |
| `components/textbook-reader.tsx` | 图谱 Tab 接入新组件 |
| `i18n/messages/zh-CN/textbooks.json` | 新增 graph.* 翻译键 |
| `i18n/messages/en/textbooks.json` | 新增 graph.* 翻译键 |

### 4.3 数据访问层（data-access-graph.ts）

```typescript
// 全书知识点 + 前置依赖 + 关联题目数，一次查询聚合
export async function getKnowledgePointsWithRelations(
  textbookId: string
): Promise<KpWithRelations[]>

// 学生个人掌握度（按教材范围）
export async function getStudentKpMastery(
  studentId: string,
  textbookId: string
): Promise<Map<string, MasteryInfo>>

// 班级平均掌握度（教师视角）
export async function getClassKpMastery(
  teacherId: string,
  textbookId: string
): Promise<Map<string, MasteryInfo>>

// 单个知识点的前置列表
export async function getPrerequisitesForKp(
  kpId: string
): Promise<KnowledgePoint[]>
```

**性能考量**：
- 全书知识点通常 50-300 个，一次查询无压力
- 关联题目数用子查询 `COUNT` 聚合，避免 N+1
- 掌握度查询走索引（`mastery_kp_idx` + `mastery_student_idx`）

### 4.4 Server Actions（actions.ts）

```typescript
// 图谱数据懒加载入口
export async function getKnowledgeGraphDataAction(
  textbookId: string,
  viewMode: GraphViewMode
): Promise<ActionState<KnowledgeGraphData>>

// 声明前置依赖（含循环检测）
export async function createPrerequisiteAction(
  input: CreatePrerequisiteInput
): Promise<ActionState<void>>

// 删除前置依赖
export async function deletePrerequisiteAction(
  input: DeletePrerequisiteInput
): Promise<ActionState<void>>
```

**权限**：
- `getKnowledgeGraphDataAction`：`requirePermission(Permissions.TEXTBOOK_READ)`，掌握度数据按当前用户角色过滤
- `createPrerequisiteAction` / `deletePrerequisiteAction`：`requirePermission(Permissions.TEXTBOOK_UPDATE)`

**循环检测**：`createPrerequisiteAction` 中做 DFS，若声明 `A→B` 后从 B 可达 A 则拒绝。

## 5. 图谱视图与交互

### 5.1 视图模式

| 模式 | 数据源 | 节点着色 | 适用角色 |
|------|--------|---------|---------|
| `structure` | 全书知识点 + parentId + prerequisites | 按章节分色 | 教师/学生 |
| `student-mastery` | + 学生个人掌握度 | 红(<60%)/黄(60-85%)/绿(>85%)/灰(未测) | 学生 |
| `class-mastery` | + 班级平均掌握度 | 同上但聚合班级数据 | 教师 |

### 5.2 节点设计（graph-kp-node.tsx）

- 矩形卡片，宽度 180px，高度自适应
- 内容：知识点名称 + 关联题目数徽章 + 掌握度进度条（mastery 模式下）
- 双击节点 → 打开右侧详情面板
- 单击节点 → 高亮关联节点（前置+后置），其余节点降低透明度
- 节点支持拖拽（位置不持久化，切换章节后重新布局）

### 5.3 边设计

- `parentId` 关系：实线，无箭头（树归属）
- `prerequisite` 关系：虚线 + 箭头（依赖方向）
- 选中节点时：关联边高亮，其余边降低透明度

### 5.4 画布交互

- React Flow 内置：缩放（滚轮）、平移（拖拽空白）、小地图、键盘导航（Tab/方向键）
- 工具栏（`graph-toolbar.tsx`）：
  - 视图模式切换（structure / student-mastery / class-mastery）
    - 学生角色：仅显示 `structure` + `student-mastery`
    - 教师角色：显示 `structure` + `class-mastery`（教师看班级整体，不看个人）
  - 章节筛选（多选下拉，默认全选）
  - 关键词搜索（高亮匹配节点，非匹配节点降低透明度）
  - 重置视图按钮

### 5.5 详情面板（graph-node-detail-panel.tsx）

- 知识点描述
- 掌握度详情（个人/班级，含答题数/正确率）
- 关联题目列表（前 5 条 + "查看全部"跳转题目库，带 `?kp=<id>` 查询参数）
- 前置知识点列表（可点击跳转）
- 后置知识点列表（可点击跳转）
- 教师/有权限者：编辑前置依赖入口（添加/删除前置）

## 6. 数据流与性能

### 6.1 数据加载策略

- 图谱数据按教材维度一次性加载（全书知识点 + 依赖 + 题目数聚合）
- 掌握度数据按 viewMode 懒加载：切换到 mastery 模式时才请求
- 使用 Server Action `getKnowledgeGraphDataAction(textbookId, viewMode)` 统一入口
- 客户端缓存：`use-graph-data.ts` 用 `useState` + `useRef` 防重复请求（复用 P2-3 模式）

### 6.2 布局计算

- dagre 布局在客户端 `useMemo` 中执行
- 知识点量级（50-300）下 dagre 计算时间 <10ms
- 布局参数：`rankdir=TB`（从上到下）、`nodesep=40`、`ranksep=90`

### 6.3 错误处理

- 图谱数据加载失败 → 复用 `TextbookSectionErrorBoundary`
- 掌握度数据缺失 → 节点显示"未测评"灰色状态，不阻断图谱渲染
- 前置依赖循环检测 → Server Action 返回结构化错误，前端 toast 提示

## 7. 权限与 i18n

### 7.1 权限

- `TEXTBOOK_READ` — 查看图谱
- `TEXTBOOK_UPDATE` — 编辑前置依赖
- 掌握度查看：学生只能看自己，教师看班级（由 data-access 层按 `getCurrentStudentUser`/`getCurrentTeacherUser` 过滤）

### 7.2 i18n 新增键

```json
{
  "graph": {
    "viewMode": {
      "structure": "结构图",
      "studentMastery": "个人掌握度",
      "classMastery": "班级掌握度"
    },
    "node": {
      "questions": "题目",
      "mastery": "掌握度",
      "prerequisite": "前置",
      "successor": "后置"
    },
    "detail": {
      "title": "知识点详情",
      "noDescription": "暂无描述",
      "viewAllQuestions": "查看全部题目",
      "editPrerequisite": "编辑前置依赖",
      "addPrerequisite": "添加前置",
      "removePrerequisite": "移除",
      "noPrerequisites": "暂无前置知识点",
      "noSuccessors": "暂无后置知识点",
      "masteryNotAssessed": "未测评",
      "correctRate": "正确率"
    },
    "toolbar": {
      "search": "搜索知识点",
      "filterByChapter": "按章节筛选",
      "resetView": "重置视图"
    },
    "empty": {
      "noPrerequisites": "暂无前置依赖关系",
      "noData": "暂无图谱数据"
    },
    "error": {
      "cyclicDependency": "不能添加循环依赖",
      "loadFailed": "图谱加载失败"
    }
  }
}
```

## 8. 测试策略

### 8.1 单元测试

- `graph-layout.ts`：dagre 集成后布局正确性、空数据、循环容错
- `data-access-graph.ts`：聚合查询正确性、权限过滤
- 循环依赖检测：DFS 算法单测

### 8.2 组件测试

- `graph-kp-node.tsx`：节点渲染、掌握度进度条、徽章
- `graph-node-detail-panel.tsx`：详情展示、前置/后置列表、跳转链接
- `graph-toolbar.tsx`：视图切换、搜索、筛选

### 8.3 集成测试

- 图谱数据加载 → 渲染 → 节点点击 → 详情面板
- 视图模式切换 → 掌握度数据懒加载
- 前置依赖 CRUD → 图谱边更新

## 9. 依赖变更

### 9.1 新增依赖

- `@dagrejs/dagre` — 分层有向图布局算法（~50KB gzip）

### 9.2 复用依赖

- `@xyflow/react`（已在项目中使用）

## 10. 架构图同步

实现完成后需同步以下架构文档：

- `docs/architecture/004_architecture_impact_map.md` — §2.5 教材模块章节
  - 更新文件清单（新增 6 个文件）
  - 更新导出函数（新增 4 个 data-access + 3 个 actions）
  - 更新 knownIssues（移除"P2 图谱方向键导航未实现"）
- `docs/architecture/005_architecture_data.json` — modules.textbooks 节点
  - 更新 exports、dbTables（新增 knowledge_point_prerequisites）、dependencyMatrix

## 11. 非目标（YAGNI）

以下功能不在本次范围内，后续迭代考虑：

- 节点位置持久化（拖拽后保存布局）
- 学习路径自动推荐
- 关联视频/课件资源（当前仅关联题目）
- 教材阅读进度跟踪
- 学生笔记/标注
- 教材导入/导出
- 多版本教材对比
