# teacher-portal 模块 Next Steps

> 维护者：ai13（teacher-portal）
> 最后更新：2026-07-13
> 关联：
>
> - [workline.md](../../docs/architecture/issues/worklines/teacher-portal_workline.md)
> - [contract.md](../../docs/architecture/issues/contracts/teacher-portal_contract.md)
> - [issue.md](../../docs/architecture/issues/objections/teacher-portal_issue.md)

---

## 1. 当前状态总览

| 阶段 | 状态 | 说明 |
| ---- | ---- | ---- |
| P2 MF Shell + 基础页面 | ✅ 完成 | AppShell + urql GraphQL Provider + 6 基础页面 |
| P3 考试/作业/成绩 | ✅ 完成 | 详情 + 批改 + 乐观更新 + 多 Tab 同步 |
| P4 知识图谱 + 学情分析 | ✅ 完成 | SVG 可视化 + 班级/单生学情 |
| P5 通知 + AI 助手 | ✅ 完成 | WebSocket + SSE 流式 AI 出题/教案/学情报告 |
| P6 可观测性硬化 | ✅ 完成 | Sentry + WebVitals + OTel + A11y + 性能预算 |
| P7 参考项目差距闭环 | ✅ 完成 | 新增 35 页面，覆盖参考项目全部 16 业务模块 |
| Docker Desktop 验证 | ✅ 通过 | standalone 模式构建 + 27 静态 + 11 动态路由全部 200 |
| MSW mock → 真实 API 切换 | ⏳ 待上游 | 需 teacher-bff GraphQL schema 上线 |
| 单元测试 | ⏳ 待补 | vitest 配置 + 关键 hook/组件测试 |
| 设计令牌硬化 | ⏳ 待补 | globals.css hsl() 字面量修复 |
| i18n 集成 | ⏳ 待补 | 中文硬编码 → next-intl |

---

## 2. 下游依赖工作（需协调 AI / 其他 AI 推进）

### 2.1 teacher-bff（ai03）— 最高优先级

**依赖内容**：GraphQL schema 落地
**影响范围**：teacher-portal 全部 61 个 GraphQL operation 切换真实数据
**协调方式**：teacher-bff GraphQL schema 第一版（ARB-001 §1）需在 main 上发布

**具体清单**：

| 模块 | GraphQL operations 数 | 上游要求 |
| ---- | -------------------- | -------- |
| 基础（P2） | 5 Query + 1 Mutation | MeQuery / ViewportsQuery / ClassesQuery / ExamsQuery / HomeworkQuery / GradesQuery / LoginMutation |
| 考试/作业/成绩（P3） | 5 Query + 3 Mutation | ExamDetailQuery / HomeworkDetailQuery / CreateExamMutation / AssignHomeworkMutation / RecordGradeMutation |
| 知识图谱/学情（P4） | 3 Query | KnowledgeGraphQuery / ClassAnalyticsQuery / StudentAnalyticsQuery |
| 通知/AI（P5） | 2 Query + 3 Mutation | MyNotificationsQuery / MarkAsReadMutation / GenerateQuestionMutation / GenerateLessonPlanMutation / GenerateReportMutation |
| 成绩增强（P7-A） | 4 Query + 1 Mutation | GradeEntryQuery / SaveGradeEntriesMutation / GradeStatsQuery / GradeAnalyticsQuery / ReportCardQuery |
| 作业批改（P7-A） | 3 Query + 1 Mutation | HomeworkSubmissionsQuery / HomeworkAssignmentSubmissionsQuery / GradeSubmissionMutation |
| 考试组卷（P7-B） | 2 Query + 1 Mutation | ExamBuildQuery / SaveExamBuildMutation / ExamAnalyticsQuery |
| 题库/教材（P7-B） | 5 Query + 4 Mutation | QuestionsLibraryQuery / QuestionCreate/Update/DeleteMutation / QuestionBatchImportMutation / QuestionBatchExportQuery / TextbooksQuery / TextbookDetailQuery / TextbookCreateMutation |
| 考勤/班级/请假/调课（P7-C） | 8 Query + 4 Mutation | AttendanceListQuery / AttendanceSheetQuery / SaveAttendanceSheetMutation / AttendanceStatsQuery / AttendanceReportQuery / ClassDetailQuery / ClassScheduleQuery / LeaveRequestsQuery / ApproveLeaveRequestMutation / SubmitLeaveRequestMutation / SubmitScheduleChangeMutation / ScheduleChangesQuery |
| 备课/诊断/错题/练习（P7-D） | 12 Query + 5 Mutation | LessonPlansQuery / LessonPlanDetailQuery / CreateLessonPlanMutation / UpdateLessonPlanMutation / AIGenerateLessonPlanMutation / LessonPlanLibraryQuery / ForkLessonPlanMutation / LessonPlanCalendarQuery / LessonPlanHeatmapQuery / CoursePlansQuery / CoursePlanDetailQuery / CreateCoursePlanMutation / UpdateCoursePlanMutation / DiagnosticReportsQuery / ClassDiagnosticQuery / StudentDiagnosticQuery / ErrorBookQuery / PracticeAnalyticsQuery |
| 选课/富文本/监考/扫描批改/热力图（P7-E） | 8 Query + 5 Mutation | ElectiveCoursesQuery / ElectiveCourseDetailQuery / CreateElectiveCourseMutation / UpdateElectiveCourseMutation / PublishElectiveCourseMutation / CancelElectiveCourseMutation / ExamRichEditorQuery / SaveExamRichContentMutation / ProctoringStatusQuery / ProctoringEventMutation / SubmissionScanGradingQuery / SaveScanGradingMutation / LessonPlanHeatmapQuery |

**切换步骤**：

1. 等待 teacher-bff schema 上线 main
2. 在 teacher-portal 设置 `NEXT_PUBLIC_API_MOCKING=false`
3. 删除或停用 `src/mocks/handlers-p*.ts`
4. 端到端测试每个页面，校对字段映射

### 2.2 iam（ai06）— 高优先级

**依赖内容**：JWT refresh token cookie 模式（F12 裁决）
**影响范围**：teacher-portal 长会话保活
**协调方式**：iam 的 refresh cookie 端点上线后，teacher-portal 的 useAuth hook 需配合调整

### 2.3 push-gateway（ai09）— 中优先级

**依赖内容**：WebSocket 通知通道
**影响范围**：teacher-portal `/notifications` 页面的实时推送
**协调方式**：P5 阶段 push-gateway WebSocket 协议确定后，调整 `src/hooks/use-notifications-websocket.ts`

### 2.4 content / data-ana / msg / ai 服务 — 中优先级

**依赖内容**：各自域的 GraphQL query resolver
**影响范围**：P4 学情分析 / P7 知识图谱 / 错题本 / 练习 等数据消费
**协调方式**：等 teacher-bff 完成聚合后，通过 BFF 调用下游服务

---

## 3. 本模块待补工作

### 3.1 单元测试（P1）

**目标**：覆盖关键 hooks / 组件 / GraphQL 操作

**清单**：

- [ ] 配置 vitest（`vitest.config.ts` + `vitest.setup.ts`）
- [ ] 测试 `usePermission` hook（权限矩阵）
- [ ] 测试 `useAuth` hook（登录/登出/会话保活）
- [ ] 测试 `useCrossTabSync` hook（多 Tab 会话同步）
- [ ] 测试 `useNotificationsWebSocket` hook（指数退避）
- [ ] 测试 MSW handlers（每个 operationName 的 mock 响应）
- [ ] 测试关键页面组件：AppShell / grades/entry / homework/submissions/[submissionId]
- [ ] 配置 CI 运行 `pnpm --filter @edu/teacher-portal test`

### 3.2 设计令牌硬化（P1）

**问题**：`globals.css` 和 `tailwind.config.js` 中存在 `hsl(0 0% 100%)` 等字面量

**清单**：

- [ ] `src/app/styles/globals.css`：将所有 `hsl(...)` 字面量迁移到 `primitive.css`
- [ ] `tailwind.config.js`：将所有 `hsl(...)` 字面量迁移到 `@theme inline` 块
- [ ] ESLint 规则 `no-restricted-syntax` 强制禁止 `#hex`
- [ ] ESLint 规则 `design-tokens/no-hardcoded-fonts` 强制禁止字体字面量

### 3.3 i18n 集成（P2）

**问题**：所有页面中文文本硬编码

**清单**：

- [ ] 安装 `next-intl`
- [ ] 创建 `messages/zh-CN.json`（按模块分组）
- [ ] 修改 `next.config.js` 添加 i18n 插件
- [ ] 修改 `app/layout.tsx` 添加 `NextIntlClientProvider`
- [ ] 替换所有页面中文硬编码为 `t("...")` 调用
- [ ] 配置英文翻译（可选）

### 3.4 packages/ui-components 扩展（P2）

**清单**：

- [ ] 抽取 `DataTable` 组件（grades/stats、questions、textbooks 等表格页复用）
- [ ] 抽取 `FilterBar` 组件（统一筛选栏样式）
- [ ] 抽取 `StatusBadge` 组件（统一状态徽章）
- [ ] 抽取 `Form` 组件（基于 react-hook-form）
- [ ] 抽取 `RichTextEditor` 组件（Tiptap 封装，lesson-plans/edit + exams/edit-rich 复用）
- [ ] 抽取 `Chart` 组件（SVG 图表统一封装）
- [ ] 抽取 `Modal` 组件（统一弹窗样式）
- [ ] 抽取 `Calendar` 组件（lesson-plans/calendar 复用）

### 3.5 性能优化（P2）

**清单**：

- [ ] 配置 `size-limit.json`（已建）并接入 CI 阻断
- [ ] 首页 LCP < 2.5s（Sentry / WebVitals 监控）
- [ ] 路由懒加载（动态 import 重型页面，如 grades/analytics、knowledge-graph）
- [ ] 图片优化（`next/image` 替换 `<img>`）
- [ ] 字体优化（`next/font` 替换 CSS @font-face）

### 3.6 A11y 硬化（P2）

**清单**：

- [ ] 配置 `eslint-plugin-jsx-a11y`（已建）
- [ ] 修复所有 jsx-a11y 警告
- [ ] 键盘导航测试（Tab/Shift+Tab/Enter/Esc）
- [ ] 屏幕阅读器测试（NVDA / VoiceOver）
- [ ] WCAG 2.2 AA 颜色对比度验证

---

## 4. Docker 部署注意事项

### 4.1 当前配置

- **Dockerfile**：`apps/teacher-portal/Dockerfile`
- **构建模式**：Next.js standalone（`output: "standalone"` in `next.config.js`）
- **基础镜像**：`node:20-alpine`（与 lockfile 对齐；本地测试可用 `node:22-alpine` retag）
- **端口**：4000
- **健康检查**：`/api/health` 端点，30s 间隔

### 4.2 必需环境变量

| 变量 | 用途 | 默认值 |
| ---- | ---- | ------ |
| `NEXT_PUBLIC_API_MOCKING` | 启用 MSW mock（true 时浏览器端拦截 GraphQL） | `true`（mock 阶段）/ `false`（接入上游后） |
| `NEXT_PUBLIC_MF_ENABLED` | 启用 Module Federation Remote 加载 | `false`（P2 阶段）/ `true`（P3+ Remote 上线后） |
| `API_GATEWAY_URL` | rewrites 代理目标 | `http://localhost:8080`（dev）/ `http://api-gateway:8080`（docker compose） |
| `NODE_ENV` | Node 环境 | `production` |
| `PORT` | 监听端口 | `4000` |
| `NEXT_PUBLIC_SENTRY_DSN` | Sentry DSN（可选） | — |
| `NEXT_PUBLIC_OTEL_ENDPOINT` | OpenTelemetry OTLP 端点（可选） | — |

### 4.3 已知限制

1. **MSW 仅浏览器端生效**：服务端渲染（SSR）时，urql 发起的 GraphQL 请求会通过 `next.config.js` rewrites 代理到 `API_GATEWAY_URL`。若 api-gateway 未启动，SSR 会 500。生产部署时必须先启动 api-gateway。
2. **MF Remote 未启用**：`NEXT_PUBLIC_MF_ENABLED=false`，student/parent/admin Remote 不会加载。需等 Remote 应用上线后开启。
3. **standalone 模式限制**：`output: "standalone"` 已自动打包依赖，但 `public/` 和 `.next/static/` 需单独 COPY（已在 Dockerfile 中处理）。

---

## 5. 路由清单

### 5.1 静态路由（27 个，全部 HTTP 200 验证通过）

| 路径 | 模块 | 阶段 |
| ---- | ---- | ---- |
| `/` | 重定向 | P2 |
| `/login` | 登录 | P2 |
| `/dashboard` | 仪表盘 | P2 |
| `/classes` | 班级列表 | P2 |
| `/exams` | 考试列表 | P2 |
| `/exams/new` | 新建考试 | P3 |
| `/homework` | 作业列表 | P2 |
| `/homework/new` | 布置作业 | P3 |
| `/grades` | 成绩列表（含录入/统计/分析/报告卡入口） | P2+P7 |
| `/grades/entry` | 批量录入成绩 | P7 |
| `/grades/stats` | 班级成绩统计 | P7 |
| `/grades/analytics` | 成绩分析仪表盘 | P7 |
| `/grades/report-card` | 学生成绩报告卡 | P7 |
| `/analytics` | 学情分析 | P4 |
| `/knowledge-graph` | 知识图谱 | P4 |
| `/notifications` | 通知中心 | P5 |
| `/ai-assist` | AI 辅助出题 | P5 |
| `/ai-lesson-plan` | AI 教案 | P5 |
| `/ai-report` | AI 学情报告 | P5 |
| `/attendance` | 考勤记录 | P7 |
| `/attendance/sheet` | 批量录入考勤 | P7 |
| `/attendance/stats` | 考勤统计 | P7 |
| `/attendance/report` | 考勤报告 | P7 |
| `/questions` | 题库 | P7 |
| `/textbooks` | 教材列表 | P7 |
| `/lesson-plans` | 课案列表 | P7 |
| `/lesson-plans/new` | 新建课案 | P7 |
| `/lesson-plans/library` | 校内课案库 | P7 |
| `/lesson-plans/calendar` | 课案日历 | P7 |
| `/lesson-plans/heatmap` | 课标覆盖热力图 | P7 |
| `/course-plans` | 课程计划列表 | P7 |
| `/diagnostic` | 诊断报告列表 | P7 |
| `/error-book` | 错题本 | P7 |
| `/practice` | 练习分析 | P7 |
| `/elective` | 选修课列表 | P7 |
| `/elective/create` | 创建选修课 | P7 |
| `/leave` | 请假审批 | P7 |
| `/schedule-changes` | 调课申请 | P7 |
| `/settings` | 个人设置 | P2 |
| `/students` | 学生列表 | P2 |

### 5.2 动态路由（11 个，全部 HTTP 200 验证通过）

| 路径 | 模块 | 阶段 |
| ---- | ---- | ---- |
| `/exams/[id]` | 考试详情 | P3 |
| `/exams/[id]/build` | 组卷 | P7 |
| `/exams/[id]/analytics` | 考后分析 | P7 |
| `/exams/[id]/edit-rich` | 富文本编辑 | P7 |
| `/exams/[id]/proctoring` | 监考 | P7 |
| `/homework/[id]` | 作业详情 + 批改 | P3 |
| `/homework/assignments/[id]/submissions` | 批量批改 | P7 |
| `/homework/submissions/[submissionId]` | 单份批改 | P7 |
| `/homework/submissions/[submissionId]/scan-grading` | 扫描批改 | P7 |
| `/classes/[id]` | 班级详情聚合页 | P7 |
| `/classes/schedule` | 班级课表 | P7 |
| `/analytics/[studentId]` | 单生学情 | P4 |
| `/diagnostic/class/[classId]` | 班级诊断 | P7 |
| `/textbooks/[id]` | 教材阅读器 | P7 |
| `/lesson-plans/[planId]/edit` | 课案编辑器 | P7 |
| `/course-plans/[id]` | 课程计划详情 | P7 |
| `/elective/[id]/edit` | 编辑选修课 | P7 |

### 5.3 API 路由

| 路径 | 用途 |
| ---- | ---- |
| `/api/health` | liveness 健康检查 |
| `/api/ready` | readiness 健康检查 |
| `/api/v1/teacher/graphql` | GraphQL 端点（rewrites 到 api-gateway） |
| `/api/auth/*` | 登录端点（rewrites 到 iam） |

---

## 6. 已知问题

| 问题 | 影响 | 临时方案 |
| ---- | ---- | -------- |
| GraphQL SSR 请求在 api-gateway 未启动时 500 | 首次加载 SSR 阶段会报错 | 部署时确保 api-gateway 先启动 |
| pnpm symlink 在 Docker runtime 下 react 解析失败 | 容器无法启动 | 已用 `output: "standalone"` 解决 |
| `tsconfig.base.json` 未在 Dockerfile 中 COPY | 构建阶段报 TS5083 | 已在 Dockerfile line 13 修复 |
| MSW mock 在 production 模式下仅浏览器端生效 | SSR 阶段无法 mock | 接入真实 API 后自动解决 |
| `node:20-alpine` 镜像在 Docker Hub 被墙 | 国内构建失败 | 配置 registry-mirror 或 retag 本地 node:22-alpine |

---

**本文件维护规则**：每次完成一项 Next Step 后，将对应条目标记为 ✅ 并在 workline.md §4 或 §5 中记录审计结果。
