# student-portal 工作排期

> 负责人：ai14
> 关联：[workline.md](../workline.md)、[coord.md §1 ARB-001](../coord.md)、[coord.md §2 ARB-002](../coord.md)、[contracts/student-portal_contract.md](../contracts/student-portal_contract.md)、[matrix.md](../matrix.md)
> 模式：全并行（各 AI 一口气完成 P2-P6 全部代码，开发期间用 mock，最后统一集成测试）
> 依据：president-final-rulings.md §3.6（ai14 P3 功能范围）+ §7.14（ai14 工作内容最终清单）+ ARB-002 §2.3（P3 首个 Remote）+ 02-architecture-design.md v2 阶段能力累积矩阵

---

## §1 总览

student-portal 是学生端微前端（MF Remote），通过 Module Federation 接入 teacher-portal Shell，覆盖考试作答、作业提交、学情查看等场景。全阶段目标：P2 MF Remote 骨架预埋 → P3 考试作答 + 作业提交 + 基础页面 → P4 知识图谱 + 学情诊断 → P5 实时通知 + AI 辅助 → P6 可观测性硬化 + A11y + 性能。

**全并行模式**：ai14 一口气完成 P2-P6 全部代码，开发期间用 MSW mock 上游（student-bff GraphQL / api-gateway HTTP / push-gateway WebSocket），上游就绪后在 [matrix.md](../matrix.md) §8 更新就绪信号，最后统一集成测试。

**批次归属**（见 [workline.md §1](../workline.md)）：

- 批次 2（P3）：ai14 与 ai07 + ai08 + ai04 + ai03扩展 并行启动（`b2d, after b1d, 8d`）
- 批次 3（P4）：与 ai09 + ai11 + ai05 + ai15 并行
- 批次 4（P5）：与 ai10 + ai02 + ai12 + ai03扩展 并行
- 批次 5（P6）：与 ai16 + 持续优化 并行

---

## §2 全阶段甘特图（P2-P6）

```mermaid
gantt
    title ai14 student-portal 全阶段排期（全并行）
    dateFormat YYYY-MM-DD
    axisFormat %m-%d

    section P2 预埋
    项目骨架+设计令牌三层+独立壳路由 :crit, a14p0, 2026-07-10, 2d
    MF Remote配置(NextFederationPlugin remotes) :crit, a14a, after a14p0, 2d
    MSW基础设施+GraphQL请求层骨架 :a14b, after a14a, 2d

    section P3 学生核心
    AppShell复用+学生端导航+路由守卫 :crit, a14c, after a14b, 2d
    Dashboard页(studentDashboard query) :a14d, after a14c, 2d
    我的班级页+我的考试列表+我的作业列表 :a14e, after a14d, 3d
    考试作答页(状态机+服务器时间同步) :crit, a14f, after a14e, 4d
    IDB断网恢复队列+自动保存+DraftRecovery :crit, a14g, after a14f, 3d
    防作弊采集+BroadcastChannel多标签检测 :a14h, after a14g, 2d
    作业提交页(submitHomework mutation+乐观更新) :a14i, after a14h, 2d
    我的成绩页+我的考勤页 :a14j, after a14i, 2d

    section P4 知识与学情
    学习路径页(learningPath query+知识点卡片) :a14k, after a14j, 3d
    学情诊断页(myWeakness+myTrend query+图表) :a14l, after a14k, 3d
    教材章节浏览页(textbooks+chapters) :a14m, after a14l, 2d

    section P5 推送与AI
    WebSocket通知中心(myNotifications+markAsRead) :a14n, after a14m, 2d
    跨Tab通知同步(BroadcastChannel) :a14o, after a14n, 1d
    AI辅助答疑(SSE流式,可选) :a14p, after a14o, 3d

    section P6 硬化
    Sentry+RUM+OTel browser :a14q, after a14p, 2d
    A11y审计(WCAG 2.2 AA) :a14r, after a14q, 2d
    性能优化+bundle门禁(Remote <80KB) :a14s, after a14r, 2d
    P3未尽事项补全+降级策略验证 :a14t, after a14s, 2d
```

---

## §3 详细任务

### P2：MF Remote 骨架预埋

- **负责人**：ai14
- **裁决依据**：ARB-002 §2.3（P3 首个 Remote，但 P2 可预埋骨架）+ 总裁裁决 §3.6（ai14 P3 起步）+ §2.17（MF GraphQL client 单例方案 A）
- **交付物**：
  - 项目骨架（`apps/student-portal/` 目录结构：`src/app/`、`src/components/`、`src/lib/`、`src/hooks/`、`src/mocks/`）
  - 设计令牌三层（primitive.css / semantic.css / tailwind-theme.ts，与 teacher-portal Shell 一致）
  - 独立壳路由（next.config.js + app/layout.tsx + app/page.tsx，MF 关闭时可独立渲染）
  - NextFederationPlugin 配置（`remotes: { teacher: 'teacher@http://localhost:4000/_next/static/chunks/remoteEntry.js' }`，`exposes: { './StudentApp': './src/app/student-app.tsx' }`）
  - MF shared singleton 配置（react/react-dom/urql/graphql/@tanstack/react-query/zustand/nuqs/@edu/* 全部 singleton）
  - MSW 基础设施（`src/mocks/handlers.ts` + `src/mocks/fixtures/*.json` + `NEXT_PUBLIC_API_MOCKING=enabled`）
  - GraphQL 请求层骨架（`src/lib/graphql.ts` 复用 Shell `useGraphQLClient()`，不重复创建 client）
- **依赖**：
  - packages 骨架（ui-tokens/ui-components/hooks，ai13 批次 0.15 已完成）
  - teacher-portal MF Shell 配置（ai13 P2，exposes 就绪）
- **Mock 策略**：MSW 拦截 `POST /api/v1/student/graphql` + `POST /api/auth/login`
- **验收标准**：
  - `pnpm dev` 启动 :4001 可访问
  - MF 配置不破坏独立壳渲染（`NEXT_PUBLIC_MF_ENABLED=false` 时独立渲染首页）
  - MSW 拦截 GraphQL 请求返回 mock 数据
  - lint + typecheck 零错误

### P3：考试作答 + 作业提交 + 基础页面（核心）

- **负责人**：ai14
- **裁决依据**：总裁裁决 §3.6（ai14 P3 功能范围）+ ARB-001 §1.3（ActionState 信封 + 降级模式方案 B）+ ARB-002 §2.2（复用 Shell 暴露清单）+ 02-architecture-design.md v2 §14（考试作答架构设计）
- **交付物**：
  - **AppShell 复用 + 学生端导航**：从 Shell 导入 `AppShell`，覆写学生端视口（myClasses/myExams/myHomework/myGrades/myAttendance/learningPath/dashboard/notifications）
  - **路由守卫**：未登录跳转 `http://localhost:4000/login?redirect=student`，登录后回跳
  - **Dashboard 页**（`/dashboard`）：消费 `studentDashboard` query（upcomingHomework + upcomingExams + recentGrades + attendanceRate + learningStreakDays）
  - **我的班级页**（`/my-classes`）：消费 `myClasses` query
  - **我的考试列表页**（`/my-exams`）：消费 `myExams` query，按状态分组（未开始/进行中/已提交/已批改）
  - **我的作业列表页**（`/my-homework`）：消费 `myHomework` query，按状态分组
  - **考试作答页**（`/my-exams/[id]/take`）：
    - 状态机（NotStarted → InProgress → AutoSaving → Submitting → Submitted，见 02 §14 状态机图）
    - 服务器时间同步（`useServerTimeSync` hook，5 分钟重新同步，倒计时基于服务器时间）
    - IDB 断网恢复队列（`idb-keyval` 存草稿 + 队列，网络恢复后重试）
    - 自动保存（每 30s + blur 事件触发，乐观更新本地状态）
    - DraftRecovery 草稿恢复（进入作答页时检查 IDB 草稿，提示恢复）
    - 防作弊采集（visibilitychange/copy/paste/fullscreen/contextmenu 事件监听 + 记录）
    - BroadcastChannel 多标签检测（`edu-exam-session` channel，检测到多标签警告）
    - 提交防重复（idempotency key + 提交按钮 disabled + 提交中状态）
  - **作业提交页**（`/my-homework/[id]/submit`）：
    - 消费 `submitHomework` mutation
    - 乐观更新（useMutation onMutate 回滚 + invalidateQueries）
    - 附件上传（待 ISSUE-014-05 仲裁后实现，暂走 mock）
  - **我的成绩页**（`/my-grades`）：消费 `myGrades` query，成绩列表 + 趋势图
  - **我的考勤页**（`/my-attendance`）：消费 `myAttendance` query，考勤日历
- **依赖**：
  - student-bff GraphQL schema（ai04 P3，`packages/shared-ts/contracts/graphql/student-bff.graphql`，待 ISSUE-014-02 仲裁）
  - api-gateway 路由（ai01 P3，`/api/v1/student/*` 反向代理 student-bff，待 ISSUE-014-01 仲裁）
  - core-edu gRPC（ai08 P3，提供 ExamService/HomeworkService/GradeService/AttendanceService/ClassService）
  - iam gRPC（ai06 P2，GetUserInfo + GetEffectivePermissions + GetViewports）
  - data-ana gRPC（ai11 P4，但 studentDashboard 聚合需要，P3 用 mock）
- **Mock 策略**：
  - MSW 拦截 `POST /api/v1/student/graphql`，按 operationName 返回 mock 响应
  - mock-socket 模拟 WebSocket 推送（考试延长/强制提交事件）
  - IDB 草稿恢复用真实 idb-keyval（前端可独立测试）
- **验收标准**：
  - Dashboard 页渲染（mock 数据）：upcomingHomework + upcomingExams + recentGrades 三栏
  - 考试作答页状态机完整：进入 → 作答 → 自动保存 → 提交 → 跳转结果页
  - 断网恢复：手动 offline → 作答 → 恢复网络 → 草稿自动提交
  - 防作弊采集：visibilitychange hidden 触发记录（mock 上报）
  - 多标签检测：开第二个 Tab 作答，第一个 Tab 收到警告
  - 作业提交乐观更新：提交后立即 UI 反馈，失败回滚
  - lint + typecheck 零错误

### P4：知识图谱 + 学情诊断

- **负责人**：ai14
- **交付物**：
  - **学习路径页**（`/learning-path`）：消费 `learningPath` query，知识点卡片列表 + 掌握度进度条
  - **学情诊断页**（`/dashboard/weakness`）：消费 `myWeakness` query，薄弱点雷达图（recharts）
  - **学习趋势页**（`/dashboard/trend`）：消费 `myTrend` query，趋势折线图（recharts）
  - **教材章节浏览页**（`/textbooks`、`/textbooks/[id]/chapters`）：消费 `textbooks` + `chapters` query
- **依赖**：
  - student-bff 扩展 content + data-ana gRPC 调用（ai04 P4）
  - content gRPC（ai09 P4，TextbookService + ChapterService + KnowledgeGraphService）
  - data-ana gRPC（ai11 P4，AnalyticsService.GetStudentWeakness + GetLearningTrend）
- **Mock 策略**：MSW 返回固定知识点 + 薄弱点 + 趋势数据
- **验收标准**：
  - 学习路径页渲染知识点卡片 + 掌握度（mock）
  - 学情诊断页雷达图 + 趋势折线图渲染（mock）
  - 教材章节树形导航可用

### P5：实时通知 + AI 辅助

- **负责人**：ai14
- **交付物**：
  - **WebSocket 通知中心**（`/notifications`）：
    - 消费 `myNotifications` query + `markAsRead` mutation
    - WebSocket 连接 `ws://push-gateway:8081/ws`，实时接收通知
    - 通知分类（作业/考试/成绩/系统），未读计数
  - **跨 Tab 通知同步**（BroadcastChannel `edu-notification` channel，新通知在所有 Tab 同步）
  - **AI 辅助答疑**（可选，`/ai-tutor`）：
    - SSE 流式接收 AI 回答
    - 消费 ai 服务（待 ai12 P5 就绪）
- **依赖**：
  - push-gateway WebSocket（ai02 P5，`/ws` 端点）
  - msg gRPC（ai10 P5，NotificationService）
  - ai 服务 gRPC（ai12 P5，AiService.Chat，可选）
- **Mock 策略**：mock-socket 模拟 WS 推送（每 30 秒 1 条通知）+ MSW 返回固定 AI 响应（SSE 用 ReadableStream mock）
- **验收标准**：
  - 通知中心实时接收 WS 推送（mock）
  - 多 Tab 同步：Tab A 收到通知，Tab B 未读计数同步更新
  - AI 辅助答疑流式输出（mock）

### P6：可观测性硬化 + A11y + 性能

- **负责人**：ai14
- **交付物**：
  - **Sentry 错误追踪**（`NEXT_PUBLIC_SENTRY_DSN` + beforeSend PII 过滤，学生隐私合规）
  - **Web Vitals RUM**（LCP/INP/CLS/TTFB → `/api/v1/admin/web-vitals`）
  - **OTel browser SDK**（自动埋点 fetch/XHR/document load → OTLP collector）
  - **A11y 审计**（WCAG 2.2 AA：eslint-plugin-jsx-a11y + @axe-core/playwright + 对比度审计）
  - **性能优化**（bundle analyzer + size-limit CI 门禁：Remote < 80KB / CSS < 50KB）
  - **P3 未尽事项补全**（根据 ISSUE-014-03/04/05/06/07 仲裁结果补全防作弊策略、附件上传、实时事件响应、DataScope 强制执行）
  - **降级策略验证**（02 §18.2 降级策略矩阵的 12 个场景端到端验证）
- **依赖**：
  - push-gateway WebSocket 真实就绪（ai02 P5）
  - Sentry DSN + OTel collector（基础设施）
  - 全部上游就绪（统一集成测试）
- **验收标准**：
  - 99.9% 可用 + WCAG 2.2 AA + LCP < 2.5s / INP < 200ms / CLS < 0.1（P75）
  - Remote bundle < 80KB / CSS < 50KB
  - 12 个降级场景全部验证通过

---

## §4 依赖与就绪信号

### §4.1 我依赖的上游就绪标志

| 上游                                                          | 就绪标志                                                                                  | 阻塞阶段 | 状态        |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -------- | ----------- |
| packages 骨架（ai13 批次 0.15）                               | ui-tokens/ui-components/hooks 可 import                                                   | P2 启动  | ✅ 已就绪   |
| teacher-portal MF Shell（ai13 P2）                            | exposes AppShell/GraphQLProvider/useGraphQLClient/useAuth/usePermission + shared singleton | P2 启动  | ⏳ 待 ai13 P2 |
| api-gateway HTTP :8080（ai01 P3）                             | `/api/v1/student/*` 反向代理 student-bff 可用                                             | P3 启动  | ⏳ 待 ai01 P3 |
| student-bff GraphQL（ai04 P3）                                | `POST /graphql` :3009 + 核心 Query/Mutation 可执行                                        | P3 启动  | ⏳ 待 ai04 P3 |
| student-bff GraphQL schema（ai04 + ISSUE-014-02 仲裁）        | `packages/shared-ts/contracts/graphql/student-bff.graphql` 创建                           | P3 启动  | ⏳ 待仲裁   |
| core-edu gRPC 50053（ai08 P3）                                | ExamService/HomeworkService/GradeService/AttendanceService/ClassService 全部 RPC          | P3 启动  | ⏳ 待 ai08 P3 |
| iam gRPC 50052（ai06 P2）                                     | GetUserInfo + GetEffectivePermissions + GetViewports                                      | P3 启动  | ⏳ 待 ai06 P2 |
| student-bff content/data-ana 扩展（ai04 P4）                  | learningPath/myWeakness/myTrend/textbooks/chapters query 可用                              | P4 启动  | ⏳ 待 ai04 P4 |
| content gRPC 50054（ai09 P4）                                 | TextbookService + ChapterService + KnowledgeGraphService                                  | P4 启动  | ⏳ 待 ai09 P4 |
| data-ana gRPC 50055（ai11 P4）                                | AnalyticsService.GetStudentWeakness + GetLearningTrend                                    | P4 启动  | ⏳ 待 ai11 P4 |
| push-gateway WebSocket :8081/ws（ai02 P5）                    | WS 连接可建立 + 推送可接收                                                                | P5 启动  | ⏳ 待 ai02 P5 |
| msg gRPC 50056（ai10 P5）                                     | NotificationService.ListNotifications + MarkAsRead                                        | P5 启动  | ⏳ 待 ai10 P5 |
| ai 服务 gRPC 50057（ai12 P5，可选）                           | AiService.Chat（SSE 流式）                                                                | P5 启动  | ⏳ 待 ai12 P5 |
| Sentry DSN + OTel collector（基础设施）                       | Sentry 项目创建 + OTel collector 可接收 OTLP                                              | P6 启动  | ⏳ 待基础设施 |

### §4.2 我的就绪信号（供下游消费）

| 信号                            | 就绪标志                                                  | 消费方 |
| ------------------------------- | --------------------------------------------------------- | ------ |
| student-portal dev server :4001 | `pnpm dev` 启动 + 首页可访问                              | 无（最前端，但 teacher-portal Shell 需加载 Remote） |
| MF Remote 可加载                | teacher-portal Shell 可加载 `student-portal/StudentApp`   | teacher-portal（ai13 P3 集成测试） |
| 登录流程可用                    | 未登录跳转 Shell `/login`，登录后回跳 student             | 无     |
| GraphQL 查询可执行              | currentUser/studentDashboard/myClasses 返回数据           | 无     |
| 考试作答链路通                  | 进入作答 → 自动保存 → 提交 → 跳转结果页                   | 无     |
| WebSocket 通知可接收            | 通知中心实时更新（mock）                                  | 无     |

---

## §5 全并行开发说明

按 [matrix.md](../matrix.md) §全并行模式：

1. ai14 一口气完成 P2-P6 全部代码，开发期间用 MSW mock 上游
2. 上游就绪后在 matrix.md §8 更新就绪信号（`student-portal | ai14 | :4001 可访问 + MF Remote | ⏳ → ✅`）
3. 所有模块就绪后统一集成测试（matrix.md §9 检查清单）
4. Mock 切换：`NEXT_PUBLIC_API_MOCKING=enabled` → `disabled`
5. MF 切换：`NEXT_PUBLIC_MF_ENABLED=false`（P2 独立壳）→ `true`（P3 接入 Shell）

---

## §6 阶段能力累积矩阵（与 02-architecture-design.md v2 §20 对齐）

| 阶段 | 能力                                                | 关键页面/功能                                                              |
| ---- | --------------------------------------------------- | -------------------------------------------------------------------------- |
| P2   | 项目骨架 + MF Remote 配置 + MSW 基础设施            | 独立壳首页（占位）                                                         |
| P3   | + 考试作答 + 作业提交 + 基础页面                    | Dashboard / myClasses / myExams / myHomework / myGrades / myAttendance     |
| P4   | + 知识图谱 + 学情诊断 + 教材章节                    | learningPath / myWeakness / myTrend / textbooks / chapters                 |
| P5   | + 实时通知 + 跨 Tab 同步 + AI 辅助（可选）          | notifications / ai-tutor                                                    |
| P6   | + 可观测性 + A11y + 性能 + 降级验证 + 尽事项补全    | Sentry / RUM / OTel / WCAG 2.2 AA / bundle 门禁                            |

---

## §7 关键风险与缓解

| 风险                                                 | 影响 | 缓解措施                                                                                       |
| ---------------------------------------------------- | ---- | ---------------------------------------------------------------------------------------------- |
| student-bff GraphQL schema 未就绪（ai04 P3 延迟）    | 高   | MSW mock 全量 query/mutation，schema 就绪后切换；ai14 自行维护 mock schema 用于 codegen        |
| 考试作答断网恢复逻辑复杂（IDB 队列 + 服务器时间对齐）| 高   | 02 §14 已设计完整状态机 + 时间同步算法；P3 优先实现核心链路，P6 验证降级场景                  |
| MF Remote 加载失败（Shell 未就绪或版本不兼容）       | 中   | 02 §3.2 已设计独立壳回退（`NEXT_PUBLIC_MF_ENABLED=false` 时独立渲染）                          |
| 防作弊策略未仲裁（ISSUE-014-03/04）                  | 中   | P3 先实现采集 + 本地记录，P6 根据仲裁结果补全上报逻辑                                          |
| 附件上传协议未仲裁（ISSUE-014-05）                   | 中   | P3 先实现文本作业提交，附件上传 P6 根据仲裁结果补全                                            |
| 实时事件命名未确认（ISSUE-014-06）                   | 低   | P3 不依赖实时事件（考试作答页基于本地倒计时），P5 根据仲裁结果接入 WebSocket 实时事件          |

---

**AI Agent**: ai14（student-portal）
**Branch**: feat-review-student-portal-docs-9yN6Av
**Coordinator**: coord-ai
