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

@@ -0,0 +1,382 @@
# AI 模块审计报告
> 审计日期2026-06-25
> 审计范围:`src/modules/ai/` 全部代码 + `src/app/api/ai/` 路由 + app 层接入点
> 审计依据:`docs/architecture/004_architecture_impact_map.md`、`docs/architecture/005_architecture_data.json`、`docs/standards/coding-standards.md`、项目硬约束
> 审计方法:逐文件源码审阅 + 架构图一致性比对 + 角色-权限映射核对 + 行业标杆对标Khanmigo / Duolingo Max / Squirrel AI / Century Tech
---
## 一、现有实现概要
### 1.1 文件分布(共 32 个文件)
```
src/modules/ai/
├─ types.ts 330 行 AiService / AiClientService 接口 + 业务类型
├─ schema.ts 248 行 Zod 校验(输入 + AI 输出)
├─ actions.ts 415 行 10 个 Server Action含权限校验
├─ data-access.ts 138 行 内存事件存储 + 使用统计聚合
├─ services/
│ ├─ ai-service.ts 478 行 DefaultAiService 实现(封装 shared/lib/ai
│ ├─ prompt-templates.ts 300 行 9 套 System Prompt 常量
│ ├─ usage-tracker.ts 100 行 trackAiUsage + withAiTracking
│ └─ content-safety.ts 291 行 输入/输出过滤 + 每日限额(原子操作)
├─ context/
│ ├─ ai-client-provider.tsx 62 行 React Context 注入 AiClientService
│ └─ create-ai-client-service.ts 54 行 createFullAiClientService / createCoreAiClientService
├─ hooks/
│ ├─ use-ai-chat-stream.ts 155 行 SSE 流式聊天 + localStorage 持久化
│ ├─ use-ai-chat.ts 57 行 非流式聊天(⚠ 死代码,未被引用)
│ ├─ use-ai-suggestion.ts 72 行 相似题 / 批改建议
│ ├─ stream-utils.ts 135 行 SSE 解析纯函数
│ ├─ use-floating-ball.ts 160 行 悬浮球组合 hook
│ ├─ use-drag-position.ts 130 行 拖拽 hook
│ └─ use-position-persistence.ts 99 行 位置 localStorage
├─ components/
│ ├─ ai-assistant-widget.tsx 329 行 全局悬浮球 + 上下文感知 + Sheet
│ ├─ ai-chat-panel.tsx 417 行 聊天面板card / widget 双变体)
│ ├─ ai-error-boundary.tsx 31 行 SectionErrorBoundary 包装
│ ├─ ai-skeleton.tsx 47 行 AiSuggestionSkeleton / AiChatSkeleton
│ ├─ ai-suggestion-card.tsx 178 行 相似题卡片(⚠ 死代码,未被引用)
│ ├─ ai-provider-selector.tsx 89 行 表单字段react-hook-form
│ ├─ ai-markdown-renderer.tsx 162 行 Markdown + 图表代码块渲染
│ ├─ ai-chart-renderer.tsx 351 行 Recharts 4 图表bar/line/pie/radar
│ ├─ ai-grading-assist.tsx 173 行 教师批改辅助
│ ├─ ai-error-book-analysis.tsx 246 行 学生错题本 AI 分析
│ ├─ ai-lesson-content-generator.tsx 180 行 教师备课内容生成
│ ├─ ai-question-variant-generator.tsx 218 行 题目变体生成
│ ├─ ai-usage-dashboard.tsx 221 行 管理员使用统计
│ ├─ ai-child-summary.tsx 186 行 家长学情摘要(⚠ 未接入页面)
│ └─ ai-study-path.tsx 200 行 学生学习路径(⚠ 未接入页面)
└─ src/app/api/ai/
├─ chat/route.ts 196 行 非流式聊天端点
└─ chat/stream/route.ts 237 行 SSE 流式端点
```
### 1.2 数据流
```
app/(dashboard)/layout.tsx
│ 模块级 const aiClientService = createFullAiClientService()
<AiClientProvider service={aiClientService}> ← React Context
├─ <AiAssistantWidget /> ← 全局悬浮球
│ └─ useAiClientOptional() / useFloatingBall()
│ └─ <AiChatPanel variant="widget">
│ └─ useAiChatStream() → fetch('/api/ai/chat/stream')
│ │
│ ▼
│ route.ts: requirePermission(AI_CHAT)
│ + tryConsumeDailyQuota
│ + filterUserInput / filterAiOutput
│ + createAiChatCompletionStream (shared/lib/ai)
└─ 各业务页面teacher/homework/submissions、student/error-book、teacher/exams/build 等)
└─ <AiClientProvider service={createCoreAiClientService()}>
└─ <AiGradingAssist /> / <AiErrorBookAnalysis /> / ...
└─ useAiClient().suggestGrading(...) → suggestGradingAction
→ requirePermission(AI_CHAT, HOMEWORK_GRADE)
→ createAiService(userId).suggestGrading(input)
→ withAiTracking(...)
→ createAiChatCompletion (shared/lib/ai)
```
### 1.3 架构图记录情况
`005_architecture_data.json``modules.ai` 节点记录了完整的依赖矩阵、exports 清单、集成点、权限点、安全策略、流式特性、i18n 命名空间。
**但比对发现两处与实际实现不一致**(详见 §二 P0-2
- `ai.integrations.parent-dashboard` 声称 `AiChildSummary` 接入 `parent/dashboard` 页面 → 实际未接入
- `ai.integrations.student-learning` 声称 `AiStudyPath` 接入 `student/learning/study-path` 页面 → 实际该路由不存在
---
## 二、现存问题与原因分析
### P0 — 紧急且阻断使用
#### P0-1家长角色完全缺失 `AI_CHAT` 权限
- **位置**[permissions.ts](file:///e:/Desktop/CICD/src/shared/lib/permissions.ts#L161-L176) `ROLE_PERMISSIONS_SEED.parent` 数组
- **问题**parent 角色权限清单中**没有任何** `Permissions.AI_CHAT`,但:
- [actions.ts](file:///e:/Desktop/CICD/src/modules/ai/actions.ts#L267) `generateChildSummaryAction` 第一行调用 `requirePermission(Permissions.AI_CHAT)` → 家长调用必返回 403
- [actions.ts](file:///e:/Desktop/CICD/src/modules/ai/actions.ts#L296) `recommendStudyPathAction` 同上
- `/api/ai/chat/route.ts` L49 同上
- `AiChildSummary` / `AiStudyPath` 组件存在但家长/学生路径下完全无法使用
- **违反规则**
- 项目硬约束「所有 Server Action 必须调用 `requirePermission()` 进行权限校验」—— 校验逻辑本身正确,但权限未授予
- 项目硬约束「家长需要的功能应被授权」K12 系统家长是关键角色)
- **后果**:家长角色付费的 AI 学情摘要功能在生产环境 100% 失败;学生使用学习路径推荐时若依赖家长代调也会失败
#### P0-2架构图虚构集成AiChildSummary / AiStudyPath 完全未接入)
- **位置**
- [005_architecture_data.json](file:///e:/Desktop/CICD/docs/architecture/005_architecture_data.json#L19725-L19744) `ai.integrations.parent-dashboard` / `ai.integrations.student-learning`
- 004 文档同步描述
- **问题**
- 声称 `AiChildSummary` 集成于 `parent/dashboard` —— grep 全仓 `AiChildSummary` 仅在自身文件、actions、context 出现,**app/ 下零引用**
- 声称 `AiStudyPath` 集成于 `student/learning/study-path` —— 该路由**不存在**`app/(dashboard)/student/learning/` 下只有 `textbooks/``assignments/``courses/``page.tsx`
- 声称 `AiUsageDashboard` 集成于 `admin/ai-usage` —— 实际接入在 `admin/ai-settings/page.tsx`(路径不一致)
- **违反规则**
- 项目硬约束「如果发现项目中存在架构图未记录的模块、函数、表、路由等,必须优先完善架构图信息」
- 项目硬约束「改码必同步图」—— 反向也成立:图中记录的集成必须真实存在
- **后果**:依赖架构图做影响分析的开发者会误以为功能已上线,跳过实现;测试用例遗漏;产线功能缺失
#### P0-3`getAiUsageStatsAction` 错误消息 i18n 键错误
- **位置**[actions.ts](file:///e:/Desktop/CICD/src/modules/ai/actions.ts#L381)
- **问题**:管理员查询使用统计失败时返回 `t("error.chatFailed")`"AI 请求失败"/"AI request failed"),与场景不符
- **后果**:管理员看到"AI 请求失败"误以为是 AI 调用失败,实为统计查询失败
### P1 — 高优先级
#### P1-1数据访问层使用内存存储多实例部署不可用
- **位置**
- [data-access.ts](file:///e:/Desktop/CICD/src/modules/ai/data-access.ts#L34) `const eventStore: StoredAiEvent[] = []` 单实例内存
- [content-safety.ts](file:///e:/Desktop/CICD/src/modules/ai/services/content-safety.ts#L137) `const dailyUsageMap = new Map<...>()` 单实例内存
- **问题**:注释自承认"生产环境应替换为 Redis",但当前实现:
- 多实例部署下,`getAiUsageStats` 聚合的统计仅包含当前实例数据
- `tryConsumeDailyQuota` 在多实例下,每个实例独立计数,实际可用次数 = 限额 × 实例数
- 进程重启后所有统计归零
- **违反规则**:项目硬约束「企业级补充」「可扩展性:采用配置驱动设计」
- **后果**K8s 多 Pod 部署后限额失效、统计失真
#### P1-2`AiUsageDashboard` 违反 React Hooks 规范
- **位置**[ai-usage-dashboard.tsx](file:///e:/Desktop/CICD/src/modules/ai/components/ai-usage-dashboard.tsx#L53-L57)
- **问题**
```tsx
useEffect(() => {
void loadStats()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
```
- `loadStats` 依赖 `aiClient` 但被 disable 抑制
- `aiClient` 变化时不会重新加载
- **后果**eslint-disable 掩盖真实 bugaiClient 引用变更时不刷新
#### P1-3`AiClientProvider` 在 layout 模块级创建 service
- **位置**[layout.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/layout.tsx#L10)
- **问题**`const aiClientService = createFullAiClientService()` 在模块加载时执行module scopeservice 对象被所有用户共享
- **当前可工作原因**Server Action 内部 `requirePermission()` 会从 session 动态解析用户
- **风险**:未来若 service 需要请求级状态(如缓存当前用户权限),模块级单例会泄露
- **建议**:移入 Server Component 函数体内创建
#### P1-4`AiAssistantWidget` 内嵌英文 prompt 硬编码
- **位置**[ai-assistant-widget.tsx](file:///e:/Desktop/CICD/src/modules/ai/components/ai-assistant-widget.tsx#L228-L326) `inferContextFromPath`
- **问题**6 个角色的 `systemPrompt` 为英文硬编码字符串,未走 i18n
- **缓解**API 端点会强制覆盖(学生侧 SOCRATIC_TUTOR_SYSTEM_PROMPT客户端 prompt 仅作为上下文提示
- **后果**:维护 prompt 需改代码;多语言场景下非英语用户的提示词不一致
#### P1-5死代码 `useAiChat` Hook
- **位置**[use-ai-chat.ts](file:///e:/Desktop/CICD/src/modules/ai/hooks/use-ai-chat.ts) 57 行
- **问题**grep 全仓 `useAiChat` 仅在自身文件 + 005 架构数据中引用,**实际无任何组件使用**
- **原因**:早期非流式实现被 `useAiChatStream` 取代,但文件未删除
- **后果**:架构图 exports 中仍记录 `useAiChat`,误导调用方
#### P1-6死代码 `AiSuggestionCard` 组件
- **位置**[ai-suggestion-card.tsx](file:///e:/Desktop/CICD/src/modules/ai/components/ai-suggestion-card.tsx) 178 行
- **问题**grep 全仓 `AiSuggestionCard` 仅在自身文件 + 架构数据中引用,**实际无任何页面使用**
- **原因**`AiErrorBookAnalysis` 已包含相似题功能,`AiSuggestionCard` 是早期独立实现
- **后果**:维护成本;架构图 exports 仍记录该组件
#### P1-7API 路由与非流式路由大量重复代码
- **位置**
- [chat/route.ts](file:///e:/Desktop/CICD/src/app/api/ai/chat/route.ts) 196 行
- [chat/stream/route.ts](file:///e:/Desktop/CICD/src/app/api/ai/chat/stream/route.ts) 237 行
- **问题**:权限校验 / 限流 / Zod 校验 / 配额消费 / 输入过滤 / 系统提示构建 / 配额退款 7 段逻辑几乎逐行复制
- **后果**:修一处漏一处易出 bug测试需双倍
### P2 — 中等优先级
#### P2-1`ai-chart-renderer.tsx` 使用 `as` 断言
- **位置**[ai-chart-renderer.tsx](file:///e:/Desktop/CICD/src/modules/ai/components/ai-chart-renderer.tsx#L122-L132)
- **问题**
```ts
data: obj.data as Array<Record<string, string | number>>, // as 断言
series: obj.series as AiChartSeries[], // as 断言
yDomain: Array.isArray(obj.yDomain) ? obj.yDomain as [number, number] : undefined, // as 断言
```
- **违反规则**:项目硬约束「禁止 `as` 断言(除非从 `unknown` 转换)」—— 严格说此处从 `unknown` 转,但应使用类型守卫或 Zod parse
- **建议**:用 `z.array(AiChartSeriesSchema).parse(obj.series)` 校验
#### P2-2`AiChatPanel` 单文件 417 行接近上限
- **位置**[ai-chat-panel.tsx](file:///e:/Desktop/CICD/src/modules/ai/components/ai-chat-panel.tsx) 417 行
- **问题**card / widget 两个变体有 ~60% 重复 JSX消息列表、空状态、输入框、流式指示器各写两遍
- **建议**:抽取 `<ChatMessages>` / `<ChatInput>` / `<ChatEmptyState>` / `<ChatStreamingIndicator>` 子组件
#### P2-3`AiAssistantWidget.inferContextFromPath` 配置硬编码
- **位置**[ai-assistant-widget.tsx](file:///e:/Desktop/CICD/src/modules/ai/components/ai-assistant-widget.tsx#L223-L328)
- **问题**100+ 行 if-else 路由匹配,新增角色/路由需改代码
- **建议**:改为配置驱动
```ts
const CONTEXT_MAP: Array<{ match: RegExp; config: AiContextConfig }> = [...]
```
#### P2-4`content-safety.ts` 关键词仅英文
- **位置**[content-safety.ts](file:///e:/Desktop/CICD/src/modules/ai/services/content-safety.ts#L20-L43)
- **问题**`BLOCKED_INPUT_PATTERNS` / `STUDENT_BLOCKED_PATTERNS` 正则仅匹配英文关键词
- **后果**:中文"自杀/暴力/色情"等不当内容无法识别K12 中国场景下安全防线不足
#### P2-5`AiService.chat` 的 `usage` 字段始终返回 `null`
- **位置**[ai-service.ts](file:///e:/Desktop/CICD/src/modules/ai/services/ai-service.ts#L177)
- **问题**`return { result: { content, usage: null }, tokenUsage }` —— `AiChatResult.usage: unknown` 类型但实际始终 null
- **建议**:将 `tokenUsage` 包入 `usage` 字段,或修改类型为 `usage: null`
#### P2-6架构图遗漏 `/admin/ai-settings` 路由
- **位置**[005_architecture_data.json](file:///e:/Desktop/CICD/docs/architecture/005_architecture_data.json) `routes` 节点
- **问题**:仅在 `ai.integrations.admin-dashboard.page` 字段提及 `admin/ai-usage`,但 `routes` 表中无 `/admin/ai-settings` 条目(实际页面位于 `/admin/ai-settings`
- **后果**:路由审计遗漏
---
## 三、行业差距对比
### 3.1 与 KhanmigoKhan Academy差距
| 维度 | Khanmigo | 我们 | 差距影响 |
|------|----------|------|---------|
| 教师可见学生 AI 对话 | ✓ 教师后台可审阅 | ✗ 对话仅存 localStorage | 教师无法了解学生提问习惯,无法干预 Socratic 失败场景 |
| 多模态输入 | ✓ 支持图片 | ✗ 仅文本 | 数学几何题无法拍照上传 |
| Activity 难度自适应 | ✓ 根据学生水平动态调整 | ✗ 固定 difficulty 参数 | 同一题目对快慢学生无差异 |
| Teacher copilot 模式 | ✓ 教师侧 AI 提示教学策略 | ✗ 仅 widget 通用助手 | 教师备课缺专业引导 |
### 3.2 与 Duolingo Max 差距
| 维维 | Duolingo Max | 我们 | 差距影响 |
|------|--------------|------|---------|
| Explain My Answer | ✓ 错题后一键解释 | ✓ `explainError` 已实现但未接入页面 | 功能闲置 |
| Roleplay | ✓ 情景对话练习 | ✗ 无 | 英语口语训练缺失 |
| "立即练习"按钮 | ✓ 相似题后直接进入练习流 | ✗ 仅"选择" | 学生看到相似题但无法作答,流程断裂 |
### 3.3 与 Squirrel AI松鼠 AI差距
| 维度 | Squirrel AI | 我们 | 差距影响 |
|------|-------------|------|---------|
| 纳米级知识图谱 | ✓ 700+ 知识点拆分 | ⚠ `recommendStudyPath` 已支持 knowledgeGraph 注入,但未接入页面 | 功能已实现但未上线 |
| 自适应路径 | ✓ 实时根据答题调整 | ✗ 一次性生成路径,无反馈循环 | 路径在学习过程中不更新 |
| 学习目标对齐 | ✓ 与课标 / 升学目标对齐 | ✗ studyPathInput.learningGoal 仅文本 | 缺少课标映射 |
### 3.4 与 Century Tech 差距
| 维度 | Century Tech | 我们 | 差距影响 |
|------|--------------|------|---------|
| 全校 AI 成本看板 | ✓ token 消耗 / 预算预警 | ⚠ `AiUsageDashboard` 无 token 字段 | 管理员无法评估成本 |
| 多 Provider 对比 | ✓ A/B 测试 | ✗ 单次调用单 provider | 无法评估哪家性价比高 |
| 课程标准映射 | ✓ AI 推荐与课标对齐 | ✗ 无 | 学习路径与课标脱节 |
### 3.5 K12 通用缺失
- **a11y**`AiAssistantWidget` 悬浮球无键盘焦点;`AiChatPanel` 流式 token 更新未限流(屏幕阅读器频繁打断)
- **空状态**`AiUsageDashboard` 无数据时仅显示文案,无引导管理员"先发起一次 AI 对话"
- **错误恢复**`AiErrorBoundary` 透传 `SectionErrorBoundary`,无 AI 专属重试策略(如降级到非流式)
---
## 四、改进优先级建议
### P0必须立即修复 — 阻断核心功能)
| 编号 | 改进项 | 方向说明 |
|------|--------|---------|
| P0-1 | parent 角色补齐 `AI_CHAT` 权限 | 在 `ROLE_PERMISSIONS_SEED.parent` 数组追加 `Permissions.AI_CHAT` |
| P0-2 | 修复架构图虚构集成 | 二选一:(A) 在 parent/dashboard 接入 `AiChildSummary`,新建 `student/learning/study-path` 路由接入 `AiStudyPath`(B) 从架构图 integrations 中移除两条虚构集成。**本次采用方案 A**:实际接入组件,让功能上线 |
| P0-3 | `getAiUsageStatsAction` 错误 i18n 修复 | 新增 `ai.error.statsFailed` 翻译键,替换 `chatFailed` |
### P1高优先级 — 影响可维护性与正确性)
| 编号 | 改进项 | 方向说明 |
|------|--------|---------|
| P1-1 | 内存存储抽象化 | 提取 `AiUsageStore` 接口,当前内存实现作为 `InMemoryAiUsageStore`,未来可替换 `RedisAiUsageStore`;不阻塞当前发布 |
| P1-2 | `AiUsageDashboard` useEffect 修复 | 抽取 `loadStats` 为 `useCallback`,依赖数组加入 `aiClient` |
| P1-3 | layout service 创建移入 Server Component | 改为 `function DashboardLayout() { const service = createFullAiClientService(); ... }` |
| P1-4 | `inferContextFromPath` 配置化 + i18n 化 | 改为 `CONTEXT_MAP` 数组prompt 走 i18n key |
| P1-5 | 删除 `use-ai-chat.ts` 死代码 | 文件 + 架构图 exports 同步移除 |
| P1-6 | 删除 `ai-suggestion-card.tsx` 死代码 | 同上 |
| P1-7 | API 路由共享逻辑抽取 | 抽取 `prepareAiChatRequest(req)` 返回 `{ body, isStudent, quota, limitResult }` |
### P2中等优先级 — 代码质量与扩展性)
| 编号 | 改进项 | 方向说明 |
|------|--------|---------|
| P2-1 | `ai-chart-renderer` `as` 断言替换为 Zod parse | 用 `AiChartSpecSchema.parse()` 校验 |
| P2-2 | `AiChatPanel` 拆分子组件 | 抽取 `ChatMessages` / `ChatInput` / `ChatEmptyState` |
| P2-3 | `content-safety` 增加中文关键词 | 扩展正则至中文场景 |
| P2-4 | `AiService.chat.usage` 修正 | 返回实际 tokenUsage 或改类型为 `null` |
| P2-5 | 架构图补齐 `/admin/ai-settings` 路由 | 005 routes 节点新增 |
### 中长期方向(不在本次实施范围)
- 接入 Redis 替换内存存储(需运维配合)
- 多模态输入(需 OCR/视觉模型)
- 教师 AI 对话审阅后台(需新增 DB 表)
- 多 Provider A/B 测试(需扩展 Provider 模型)
- 课程标准映射(需课标数据源)
---
## 五、架构图同步说明
本次审计发现架构图需更新如下节点:
### 5.1 `005_architecture_data.json` 同步项
1. **`modules.ai.exports.hooks`** 移除 `useAiChat`(死代码已删除)
2. **`modules.ai.exports.components`** 移除 `AiSuggestionCard`(死代码已删除)
3. **`modules.ai.integrations.parent-dashboard`** 更新 `page` 字段为真实接入路径
4. **`modules.ai.integrations.student-learning`** 更新 `page` 字段为真实接入路径 `student/learning/study-path`
5. **`modules.ai.integrations.admin-dashboard`** 更正 `page` 为 `admin/ai-settings`(原误记为 `admin/ai-usage`
6. **`routes./admin/ai-settings`** 新增节点(若 routes 表中确实缺失)
7. **`rolePermissionsSeed.parent`** 追加 `ai:chat` 权限
8. **`modules.ai.i18n.v2Keys`** 追加 `error.statsFailed` 翻译键
### 5.2 `004_architecture_impact_map.md` 同步项
1. AI 模块章节的「集成点」表格更新实际接入路径
2. 移除已删除组件的引用
---
## 六、本次实施清单
### 已实施(本次审计直接修复)
| 编号 | 类型 | 改动 |
|------|------|------|
| P0-1 | 代码 | `permissions.ts` parent 角色追加 `AI_CHAT` |
| P0-2 | 代码 + 架构图 | 接入 `AiChildSummary` 到 parent/dashboard`ParentDashboard` 新增 `aiSummarySlot`page.tsx 为每个子女渲染 `AiChildSummary`);新建 `student/learning/study-path` 路由page.tsx + loading.tsx + error.tsx接入 `AiStudyPath`;同步 004/005 文档集成点与路由表 |
| P0-3 | 代码 + i18n | `actions.ts` 修复错误键;`ai.json` (zh/en) 新增 `error.statsFailed` |
| P1-2 | 代码 | `ai-usage-dashboard.tsx` 修复 useEffect |
| P1-3 | 代码 | `layout.tsx` service 移入函数体 |
| P1-5 | 代码 | 删除 `use-ai-chat.ts`;架构图 exports.hooks 移除 `useAiChat` |
| P1-6 | 代码 | 删除 `ai-suggestion-card.tsx`;架构图 exports.components 移除 `AiSuggestionCard` |
| P2-1 | 代码 | `ai-chart-renderer.tsx` 替换 `as` 为 Zod parse新增 `AiChartSpecSchema` |
| P2-4 | 代码 | `ai-service.ts` 修正 `usage` 字段返回实际 tokenUsage |
| 架构图 | 文档 | 004/005 同步上述改动;新增 `student.studyPath` i18n 块zh/en |
| 权限 | 文档 | `005` 的 `rolePermissionsSeed.parent` 追加 `AI_CHAT` |
| i18n | 文档 | `005` 的 `modules.ai.i18n.v2Keys` 追加 `error.statsFailed` |
| 路由 | 文档 | `005` 的 `routes` 表新增 `/student/learning/study-path`;更新 `/parent/dashboard` 描述含 AI 摘要集成;`/admin/ai-settings` 校正为 admin 集成路径(原误记为 `admin/ai-usage` |
### 未实施(中长期,需独立任务)
| 编号 | 原因 |
|------|------|
| P1-1 Redis 替换内存 | 需运维提供 Redis 实例 |
| P1-4 prompt 完全 i18n 化 | 客户端 prompt 已被服务端覆盖,影响小 |
| P1-7 API 路由共享逻辑抽取 | 涉及测试回归,单独 PR |
| P2-2 AiChatPanel 拆分 | 涉及大量回归,单独 PR |
| P2-3 中文关键词扩展 | 需安全策略评审 |