docs(student-portal): add arbitration check and new objections to issue record
add verification of ARB-001 and ARB-002 impacts, and submit seven new disputed issues for coord arbitration
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,9 @@
|
|||||||
# student-portal 对接契约
|
# student-portal 对接契约
|
||||||
|
|
||||||
> 负责人:ai14
|
> 负责人:ai14
|
||||||
> 关联:[matrix.md](./matrix.md)
|
> 关联:[matrix.md](./matrix.md)、[coord.md §1 ARB-001](../coord.md)、[coord.md §2 ARB-002](../coord.md)、[student-bff_contract.md](./student-bff_contract.md)、[teacher-portal_contract.md](./teacher-portal_contract.md)
|
||||||
|
> 版本:v2(ai14 接管审计与补全版,2026-07-10)
|
||||||
|
> 修订摘要:GraphQL endpoint 路径修正为 `/api/v1/student/graphql`(对齐 matrix.md §5)+ 补全 24 个 GraphQL query/mutation(对齐 02 §4.2)+ 补充 ARB-002 MF Shell 暴露清单 + 补充就绪信号明细
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -18,32 +20,54 @@
|
|||||||
| GET | / | 学生门户首页 | JWT 必需(前端路由守卫) |
|
| GET | / | 学生门户首页 | JWT 必需(前端路由守卫) |
|
||||||
| GET | /my-classes | 我的班级 | JWT 必需 |
|
| GET | /my-classes | 我的班级 | JWT 必需 |
|
||||||
| GET | /my-exams | 我的考试 | JWT 必需 |
|
| GET | /my-exams | 我的考试 | JWT 必需 |
|
||||||
|
| GET | /my-exams/[id]/take | 考试作答页 | JWT 必需 |
|
||||||
|
| GET | /my-exams/[id]/result | 考试结果页 | JWT 必需 |
|
||||||
| GET | /my-homework | 我的作业 | JWT 必需 |
|
| GET | /my-homework | 我的作业 | JWT 必需 |
|
||||||
|
| GET | /my-homework/[id]/submit | 作业提交页 | JWT 必需 |
|
||||||
| GET | /my-grades | 我的成绩 | JWT 必需 |
|
| GET | /my-grades | 我的成绩 | JWT 必需 |
|
||||||
| GET | /my-attendance | 我的考勤 | JWT 必需 |
|
| GET | /my-attendance | 我的考勤 | JWT 必需 |
|
||||||
| GET | /learning-path | 学习路径 | JWT 必需 |
|
| GET | /learning-path | 学习路径 | JWT 必需 |
|
||||||
| GET | /dashboard | 学生仪表盘 | JWT 必需 |
|
| GET | /dashboard | 学生仪表盘 | JWT 必需 |
|
||||||
|
| GET | /dashboard/weakness | 学情诊断 | JWT 必需 |
|
||||||
|
| GET | /dashboard/trend | 学习趋势 | JWT 必需 |
|
||||||
|
| GET | /textbooks | 教材列表 | JWT 必需 |
|
||||||
|
| GET | /textbooks/[id]/chapters | 章节列表 | JWT 必需 |
|
||||||
| GET | /notifications | 通知中心 | JWT 必需 |
|
| GET | /notifications | 通知中心 | JWT 必需 |
|
||||||
|
| GET | /ai-tutor | AI 辅助答疑(P5 可选) | JWT 必需 |
|
||||||
|
|
||||||
|
> **路由前缀**:无 `/student/` 前缀(student-portal 作为 MF Remote,由 Shell 路由 `/student/*` 加载,内部路由无前缀)。
|
||||||
|
|
||||||
### 1.3 GraphQL schema(如 BFF)
|
### 1.3 GraphQL schema(如 BFF)
|
||||||
|
|
||||||
不适用。student-portal 消费 student-bff GraphQL,自身不提供 schema。
|
不适用。student-portal 消费 student-bff GraphQL,自身不提供 schema。
|
||||||
|
|
||||||
|
> **消费的 schema 文件**:`packages/shared-ts/contracts/graphql/student-bff.graphql`(待 ISSUE-014-02 仲裁后由 ai04 创建,对齐 ARB-001 §1.3 集中管理原则)
|
||||||
|
|
||||||
### 1.4 Kafka 事件发布(如有)
|
### 1.4 Kafka 事件发布(如有)
|
||||||
|
|
||||||
无。
|
无。
|
||||||
|
|
||||||
### 1.5 错误码前缀
|
### 1.5 错误码前缀
|
||||||
|
|
||||||
无(前端不定义错误码前缀,透传 BFF 错误码)。
|
无(前端不定义错误码前缀,透传 BFF 错误码 `BFF_STUDENT_*`,见 [matrix.md §6](../matrix.md))。
|
||||||
|
|
||||||
### 1.6 微前端架构(补充)
|
### 1.6 微前端架构(MF Remote,ARB-002 对齐)
|
||||||
|
|
||||||
| 角色 | 说明 |
|
| 角色 | 说明 |
|
||||||
| ---------------------- | ----------------------------------------------------------------- |
|
| ---------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||||
| MF Remote | 学生门户是微前端远程模块,由 teacher-portal AppShell 或独立壳加载 |
|
| MF Remote | student-portal 是微前端远程模块(P3 首个 Remote,ARB-002 §2.3),由 teacher-portal AppShell 加载 |
|
||||||
| 暴露的 remote 模块 | StudentApp(学生端完整应用)、shared 学生端组件 |
|
| 暴露的 remote 模块 | `./StudentApp`(学生端完整应用) |
|
||||||
| module federation 配置 | `apps/student-portal/module-federation.config.ts` |
|
| module federation 配置 | `apps/student-portal/next.config.js`(NextFederationPlugin) |
|
||||||
|
| Shell 暴露清单(复用) | AppShell / GraphQLProvider / useAuth / usePermission / useGraphQLClient / ErrorBoundary / Loading / Empty / RequirePermission(ARB-002 §2.2) |
|
||||||
|
| shared singleton | react / react-dom / urql / graphql / @tanstack/react-query / zustand / nuqs / @edu/ui-tokens / @edu/ui-components / @edu/hooks / @edu/contracts / @edu/shared-ts(ARB-002 §2.2) |
|
||||||
|
| feature flag | `NEXT_PUBLIC_MF_ENABLED`(P2=false 独立壳,P3=true 接入 Shell) |
|
||||||
|
| 登录页 | 不实现,未登录跳转 `http://localhost:4000/login?redirect=student`(ARB-002 §2.3 登录由 Shell 独占) |
|
||||||
|
|
||||||
|
### 1.7 WebSocket 消费(push-gateway)
|
||||||
|
|
||||||
|
| 端点 | 用途 | 认证 | 事件类型 |
|
||||||
|
| --------------------- | ----------------------- | ---- | ------------------------------------------------------------------------ |
|
||||||
|
| `ws://push-gateway:8081/ws` | 实时通知推送 | JWT | 作业通知 / 考试通知 / 成绩通知 / 系统通知 / 考试延长(待 ISSUE-014-06 仲裁) / 考试强制提交(待 ISSUE-014-06 仲裁) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -60,26 +84,58 @@
|
|||||||
### 2.3 HTTP 调用(如有)
|
### 2.3 HTTP 调用(如有)
|
||||||
|
|
||||||
| 被调用方 | Method.Path | 用途 | mock 策略 |
|
| 被调用方 | Method.Path | 用途 | mock 策略 |
|
||||||
| ------------------- | ------------------------- | --------------------------------------------- | ----------------------------------------------------------------- |
|
| ------------------- | ------------------------------ | --------------------------------------------- | ----------------------------------------------------------------- |
|
||||||
| api-gateway (ai01) | POST /api/student/graphql | 学生 GraphQL 查询(经网关代理到 student-bff) | api-gateway/student-bff 就绪前使用 MSW 拦截返回 mock GraphQL 响应 |
|
| api-gateway (ai01) | POST /api/v1/student/graphql | 学生 GraphQL 查询(经网关代理到 student-bff :3009/graphql) | api-gateway/student-bff 就绪前使用 MSW 拦截返回 mock GraphQL 响应 |
|
||||||
| api-gateway (ai01) | POST /api/auth/login | 学生登录 | api-gateway 就绪前使用 MSW 返回固定 JWT |
|
| api-gateway (ai01) | POST /api/auth/login | 学生登录(Shell 独占,student-portal 不直接调用,仅跳转) | api-gateway 就绪前由 Shell 处理 |
|
||||||
| push-gateway (ai02) | GET /ws | WebSocket 实时通知 | push-gateway 就绪前使用 mock-socket 模拟 WS 推送 |
|
| api-gateway (ai01) | POST /api/v1/student/upload | 作业附件上传(待 ISSUE-014-05 仲裁) | 待仲裁后实现 |
|
||||||
|
| push-gateway (ai02) | GET /ws(WebSocket) | WebSocket 实时通知 | push-gateway 就绪前使用 mock-socket 模拟 WS 推送 |
|
||||||
|
|
||||||
|
> **路径说明**(ISSUE-014-01):
|
||||||
|
> - `POST /api/v1/student/graphql` 经 api-gateway 反向代理到 student-bff `POST /graphql`(:3009)
|
||||||
|
> - 路径前缀 `/api/v1/student/*` 与 matrix.md §5、teacher-portal `/api/v1/teacher/*` 保持命名一致性
|
||||||
|
> - 由 ai01(api-gateway)确认路由配置:`/api/v1/student/*` → `student-bff:3009/*`
|
||||||
|
|
||||||
### 2.4 GraphQL 查询域(经 api-gateway 代理到 student-bff)
|
### 2.4 GraphQL 查询域(经 api-gateway 代理到 student-bff)
|
||||||
|
|
||||||
| Query/Mutation | 用途 | mock 策略 |
|
> 对齐 [02-architecture-design.md v2 §4.2](../../../apps/student-portal/docs/02-architecture-design.md) GraphQL 操作清单(共 24 个)
|
||||||
| ----------------------------------- | --------------- | -------------------------------------------------- |
|
|
||||||
| currentUser | 当前学生信息 | MSW 返回固定学生 |
|
#### 2.4.1 Query(读,16 个)
|
||||||
|
|
||||||
|
| Query | 用途 | mock 策略 |
|
||||||
|
| ------------------------------ | --------------------- | -------------------------------------------------- |
|
||||||
|
| currentUser | 当前学生信息 | MSW 返回固定学生(id=student-001, roles=[student])|
|
||||||
| myClasses | 我的班级 | MSW 返回固定 1 个班级 |
|
| myClasses | 我的班级 | MSW 返回固定 1 个班级 |
|
||||||
| myExams | 我的考试 | MSW 返回固定 2 个考试 |
|
| myExams | 我的考试列表 | MSW 返回固定 2 个考试 |
|
||||||
| myHomework / submitHomework | 我的作业 + 提交 | MSW 返回固定作业 + submitHomework success |
|
| examDetail(id: ID!) | 考试详情(含题目) | MSW 返回固定考试 + 5 道题 |
|
||||||
|
| myHomework | 我的作业列表 | MSW 返回固定 3 个作业(1 个待提交) |
|
||||||
|
| homeworkDetail(id: ID!) | 作业详情 | MSW 返回固定作业 + 题目 |
|
||||||
| myGrades | 我的成绩 | MSW 返回固定 5 个成绩 |
|
| myGrades | 我的成绩 | MSW 返回固定 5 个成绩 |
|
||||||
| myAttendance | 我的考勤 | MSW 返回固定 10 条考勤 |
|
| myAttendance | 我的考勤 | MSW 返回固定 10 条考勤 |
|
||||||
| textbooks / chapters / learningPath | 学习内容 | MSW 返回固定内容 + 学习路径 |
|
| textbooks | 教材列表 | MSW 返回固定 5 个教材 |
|
||||||
|
| chapters(textbookId: ID!) | 章节列表 | MSW 返回固定章节树 |
|
||||||
|
| learningPath | 学习路径 | MSW 返回固定 8 个知识点推荐顺序 |
|
||||||
| studentDashboard | 学生仪表盘 | MSW 返回固定仪表盘(avg_score=85.0, class_rank=5) |
|
| studentDashboard | 学生仪表盘 | MSW 返回固定仪表盘(avg_score=85.0, class_rank=5) |
|
||||||
| myWeakness | 我的薄弱点 | MSW 返回固定 3 个 weak_points |
|
| myWeakness | 我的薄弱点 | MSW 返回固定 3 个 weak_points |
|
||||||
| myTrend | 学习趋势 | MSW 返回固定趋势数据 |
|
| myTrend | 学习趋势 | MSW 返回固定趋势数据 |
|
||||||
| myNotifications / markAsRead | 通知中心 | MSW 返回固定通知 |
|
| myNotifications(first: Int, after: String) | 通知列表 | MSW 返回固定 10 条通知 |
|
||||||
|
| serverTime | 服务器时间(考试倒计时对齐) | MSW 返回当前时间 + 100ms 延迟 |
|
||||||
|
|
||||||
|
#### 2.4.2 Mutation(写,8 个)
|
||||||
|
|
||||||
|
| Mutation | 用途 | mock 策略 |
|
||||||
|
| --------------------------------------- | ------------------- | -------------------------------------- |
|
||||||
|
| submitHomework(input: SubmitHomeworkInput!) | 提交作业 | MSW 返回 success=true |
|
||||||
|
| submitExam(input: SubmitExamInput!) | 提交考试作答 | MSW 返回 success=true + submittedAt |
|
||||||
|
| saveExamDraft(input: SaveExamDraftInput!) | 保存考试草稿 | MSW 返回 success=true |
|
||||||
|
| markAsRead(notificationId: ID!) | 标记通知已读 | MSW 返回 success=true |
|
||||||
|
| markAllAsRead | 全部标记已读 | MSW 返回 success=true |
|
||||||
|
| recordExamViolation(input: RecordExamViolationInput!) | 记录防作弊违规(待 ISSUE-014-03 仲裁) | MSW 返回 success=true |
|
||||||
|
| recordPasteEvent(input: RecordPasteEventInput!) | 记录粘贴事件(待 ISSUE-014-04 仲裁) | MSW 返回 success=true |
|
||||||
|
| updateNotificationPreference(input: UpdateNotificationPreferenceInput!) | 更新通知偏好(P5) | MSW 返回 success=true |
|
||||||
|
|
||||||
|
> **DataScope L0 强制执行**(ISSUE-014-07):
|
||||||
|
> - 所有学生端 Query 不传 `studentId` 参数,由 student-bff 在 Resolver 层从 JWT `x-user-id` 提取并强制过滤
|
||||||
|
> - 前端无法绕过 L0 边界(前端篡改 JWT 无效,gRPC 层会重新校验)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -87,18 +143,31 @@
|
|||||||
|
|
||||||
### 3.1 我依赖的上游就绪标志
|
### 3.1 我依赖的上游就绪标志
|
||||||
|
|
||||||
- [ ] api-gateway HTTP :8080 启用(ai01)—— 前端请求入口
|
| 上游 | 就绪标志 | 阻塞阶段 | 状态 |
|
||||||
- [ ] student-bff GraphQL :3009 启用(ai04)—— 数据来源
|
| --------------------------------- | ------------------------------------------------------------------------- | -------- | ------------ |
|
||||||
- [ ] push-gateway WebSocket :8081/ws 启用(ai02)—— 实时通知
|
| 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 | `packages/shared-ts/contracts/graphql/student-bff.graphql` 创建(待 ISSUE-014-02 仲裁) | P3 启动 | ⏳ 待仲裁 |
|
||||||
|
| core-edu gRPC 50053(ai08 P3) | ExamService/HomeworkService/GradeService/AttendanceService/ClassService | P3 启动 | ⏳ 待 ai08 P3 |
|
||||||
|
| iam gRPC 50052(ai06 P2) | GetUserInfo + GetEffectivePermissions + GetViewports | P3 启动 | ⏳ 待 ai06 P2 |
|
||||||
|
| 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 |
|
||||||
|
|
||||||
### 3.2 我的就绪标志(供下游消费)
|
### 3.2 我的就绪标志(供下游消费)
|
||||||
|
|
||||||
- [ ] student-portal dev server :4001 启用
|
- [ ] student-portal dev server :4001 启用(`pnpm dev` 可访问)
|
||||||
- [ ] MF Remote 可被 AppShell 加载(暴露 StudentApp 模块)
|
- [ ] MF Remote 可被 AppShell 加载(暴露 `./StudentApp` 模块,teacher-portal Shell 可加载)
|
||||||
- [ ] 独立壳渲染(首页 + 导航 + 路由守卫)
|
- [ ] 独立壳渲染(`NEXT_PUBLIC_MF_ENABLED=false` 时首页 + 导航 + 路由守卫独立可用)
|
||||||
- [ ] 登录流程可用(POST /api/auth/login 获取 JWT 存入 cookie)
|
- [ ] 登录流程可用(未登录跳转 Shell `/login`,登录后回跳 student)
|
||||||
- [ ] GraphQL 查询可执行(currentUser / myClasses / studentDashboard 返回数据)
|
- [ ] GraphQL 查询可执行(currentUser / studentDashboard / myClasses 返回数据)
|
||||||
- [ ] WebSocket 通知可接收
|
- [ ] 考试作答链路通(进入作答 → 自动保存 → 提交 → 跳转结果页)
|
||||||
|
- [ ] WebSocket 通知可接收(通知中心实时更新)
|
||||||
|
- [ ] lint + typecheck 零错误
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -108,18 +177,78 @@
|
|||||||
|
|
||||||
student-portal 是前端,无下游消费方。但对开发体验提供:
|
student-portal 是前端,无下游消费方。但对开发体验提供:
|
||||||
|
|
||||||
- **Storybook**:各组件独立 story
|
- **Storybook**:各组件独立 story(`apps/student-portal/.storybook/`)
|
||||||
- **MSW handlers**:`apps/student-portal/src/mocks/handlers.ts`,拦截所有 GraphQL/HTTP 请求
|
- **MSW handlers**:`apps/student-portal/src/mocks/handlers.ts`,拦截所有 GraphQL/HTTP 请求
|
||||||
|
- **Mock fixtures**:`apps/student-portal/src/mocks/fixtures/*.json`,与 student-bff mock 数据一致
|
||||||
|
|
||||||
### 4.2 我消费的 mock
|
### 4.2 我消费的 mock
|
||||||
|
|
||||||
在真实上游就绪前,student-portal 使用以下 mock:
|
在真实上游就绪前,student-portal 使用以下 mock:
|
||||||
|
|
||||||
- **HTTP/GraphQL mock**:使用 MSW 拦截所有请求
|
#### 4.2.1 HTTP / GraphQL mock(MSW)
|
||||||
- POST /api/auth/login → 返回固定 JWT + UserInfo(student 角色)
|
|
||||||
- POST /api/student/graphql → 根据 operationName 返回对应 mock 响应(与 student-bff mock 数据一致)
|
- `POST /api/v1/student/graphql` → 按 operationName 返回对应 mock 响应(见 §2.4)
|
||||||
|
- `POST /api/auth/login` → 返回固定 JWT + UserInfo(student 角色)由 Shell 处理
|
||||||
|
- `POST /api/v1/student/upload` → 返回固定 signed URL(待 ISSUE-014-05 仲裁后实现)
|
||||||
- 所有 mock 响应定义在 `apps/student-portal/src/mocks/fixtures/*.json`
|
- 所有 mock 响应定义在 `apps/student-portal/src/mocks/fixtures/*.json`
|
||||||
- **WebSocket mock**:使用 mock-socket 库
|
|
||||||
- 连接后每 30 秒推送 1 条 mock 通知
|
#### 4.2.2 WebSocket mock(mock-socket)
|
||||||
- **JWT mock**:使用固定 mock JWT,存入 httpOnly cookie
|
|
||||||
- **环境切换**:通过 `NEXT_PUBLIC_API_MOCKING=enabled` 环境变量控制,上游就绪后设为 `disabled`
|
- 连接 `ws://localhost:8081/ws` 后每 30 秒推送 1 条 mock 通知
|
||||||
|
- 通知类型轮询:作业通知 / 考试通知 / 成绩通知 / 系统通知
|
||||||
|
- 支持模拟考试延长事件(待 ISSUE-014-06 仲裁后实现)
|
||||||
|
|
||||||
|
#### 4.2.3 JWT mock
|
||||||
|
|
||||||
|
- 使用固定 mock JWT(`eyJhbGciOiJSUzI1NiIs...`),payload 含 `sub=student-001, roles=[student], dataScope=SELF`
|
||||||
|
- 存入 httpOnly cookie(由 Shell 登录流程设置)
|
||||||
|
|
||||||
|
#### 4.2.4 环境切换
|
||||||
|
|
||||||
|
- 通过 `NEXT_PUBLIC_API_MOCKING=enabled` 环境变量控制
|
||||||
|
- 上游就绪后设为 `disabled`,切换到真实请求
|
||||||
|
- MF 切换:`NEXT_PUBLIC_MF_ENABLED=false`(P2 独立壳)→ `true`(P3 接入 Shell)
|
||||||
|
|
||||||
|
#### 4.2.5 IDB 草稿恢复(真实 idb-keyval)
|
||||||
|
|
||||||
|
- 考试作答草稿使用真实 `idb-keyval` 存储(前端可独立测试断网恢复逻辑)
|
||||||
|
- 不需要 mock,IDB 在浏览器原生支持
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §5 与 student-bff 契约对齐核查
|
||||||
|
|
||||||
|
> 参考 [student-bff_contract.md](./student-bff_contract.md)(ai04 维护)
|
||||||
|
|
||||||
|
| 对齐项 | student-portal 期望 | student-bff 提供 | 状态 |
|
||||||
|
| ----------------------- | ---------------------------------------------------- | ----------------------------------------------------------------- | ---- |
|
||||||
|
| GraphQL endpoint | `POST /api/v1/student/graphql`(经 api-gateway 代理)| `POST /graphql` :3009 | ✅ 对齐(api-gateway 代理) |
|
||||||
|
| GraphQL schema 文件 | `packages/shared-ts/contracts/graphql/student-bff.graphql` | `apps/student-bff/src/schema/*.graphql`(待 ISSUE-014-02 仲裁) | ⏳ 待仲裁 |
|
||||||
|
| Query 域(16 个) | 见 §2.4.1 | 见 student-bff §1.3(auth/myClasses/myExams/myHomework/myGrades/myAttendance/content/dashboard/weakness/trend/notifications) | ⏳ 待 ai04 确认 serverTime/examDetail/homeworkDetail |
|
||||||
|
| Mutation 域(8 个) | 见 §2.4.2 | student-bff §1.3 仅列 submitHomework + markAsRead | ⏳ 待 ai04 补全 submitExam/saveExamDraft/recordExamViolation/recordPasteEvent/updateNotificationPreference |
|
||||||
|
| 错误码前缀 | 透传 `BFF_STUDENT_*` | `BFF_STUDENT_`(student-bff §1.5) | ✅ 对齐 |
|
||||||
|
| ActionState 信封 | success/errors/data + extensions.degraded | 待 ai04 实现(ARB-001 §1.3 原则) | ⏳ 待 ai04 |
|
||||||
|
| DataLoader 防 N+1 | 依赖 student-bff 实现 | 待 ai04 实现(ARB-001 §1.3 原则) | ⏳ 待 ai04 |
|
||||||
|
| DataScope L0 强制执行 | student-bff Resolver 层从 JWT 提取 studentId | 待 ISSUE-014-07 仲裁 | ⏳ 待仲裁 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §6 异议引用
|
||||||
|
|
||||||
|
> 详见 [objections/student-portal_issue.md](../objections/student-portal_issue.md)
|
||||||
|
|
||||||
|
| 编号 | 标题 | 影响 |
|
||||||
|
| ------------ | -------------------------------------------------------- | --------------------------------------------- |
|
||||||
|
| ISSUE-014-01 | GraphQL endpoint 路径不一致 | 影响 §2.3 路径配置 |
|
||||||
|
| ISSUE-014-02 | student-bff GraphQL schema 存放位置不一致 | 影响 §1.3 schema 文件路径 |
|
||||||
|
| ISSUE-014-03 | 考试作答页全屏策略与防作弊检测边界 | 影响 §2.4.2 recordExamViolation mutation 实现 |
|
||||||
|
| ISSUE-014-04 | 主观题粘贴策略(防作弊 vs 学生体验) | 影响 §2.4.2 recordPasteEvent mutation 实现 |
|
||||||
|
| ISSUE-014-05 | 作业附件上传协议(GraphQL mutation vs REST multipart) | 影响 §2.3 `/api/v1/student/upload` 端点 |
|
||||||
|
| ISSUE-014-06 | 考试延长/题目重排等实时事件命名未确认 | 影响 §1.7 WebSocket 事件类型 |
|
||||||
|
| ISSUE-014-07 | 学生端 DataScope L0 边界的强制执行层 | 影响 §2.4 GraphQL 查询域参数设计 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**AI Agent**: ai14(student-portal)
|
||||||
|
**Branch**: feat-review-student-portal-docs-9yN6Av
|
||||||
|
**Coordinator**: coord-ai
|
||||||
|
|||||||
@@ -1,12 +1,208 @@
|
|||||||
# student-portal 问题记录
|
# student-portal 问题记录
|
||||||
|
|
||||||
> 负责人:ai14
|
> 负责人:ai14
|
||||||
> 关联:[coord.md](../coord.md)、[contracts/student-portal_contract.md](../contracts/student-portal_contract.md)
|
> 关联:[coord.md](../coord.md)、[contracts/student-portal_contract.md](../contracts/student-portal_contract.md)、[matrix.md](../matrix.md)
|
||||||
> 规则:AI 遇到问题时在此追加条目,coord 仲裁后更新状态
|
> 规则:AI 遇到问题时在此追加条目,coord 仲裁后更新状态
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 问题列表
|
## §1 已有仲裁核查(ARB-001 / ARB-002 对 student-portal 的影响)
|
||||||
|
|
||||||
|
### 1.1 ARB-001(teacher-bff GraphQL schema 第一版)对 student-portal 的影响核查
|
||||||
|
|
||||||
|
| 裁决点 | 对 student-portal 的适用性 | ai14 落实方案 | 状态 |
|
||||||
|
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------ |
|
||||||
|
| Schema 存放位置 | ✅ 适用(原则一致)。student-bff GraphQL schema 应存放于 `packages/shared-ts/contracts/graphql/student-bff.graphql`(集中管理,与 teacher-bff 同源) | ai14 在 contract.md §1.3 已标注预期路径;实际由 ai04 创建,ai14 仅消费 | ⏳ 待 ai04 |
|
||||||
|
| P2 Query 范围 | ⚠️ 部分参考。ARB-001 是 teacher-bff 的 P2 范围;student-portal 起步于 P3(不在 P2),因此 student-bff 直接以 P3 全量 Query 起步 | ai14 在 P3 直接消费 student-bff 全量 Query(currentUser/myClasses/myExams/myHomework/myGrades/myAttendance/studentDashboard) | ✅ 已落实 |
|
||||||
|
| P2 Mutation 范围 | ⚠️ 部分参考。student-portal P3 起步即需要 submitHomework mutation(作业提交是 P3 核心场景) | ai14 P3 即消费 submitHomework mutation;ai04 P3 必须提供 | ⏳ 待 ai04 |
|
||||||
|
| DataLoader 防 N+1 | ✅ 适用。student-bff 聚合多 gRPC 时(如 studentDashboard 聚合 iam+core-edu+data-ana)必须使用 DataLoader | ai14 不直接实现,但依赖 student-bff 返回结构稳定(无 N+1 慢查询) | ⏳ 待 ai04 |
|
||||||
|
| 复杂度限制(depth ≤ 7) | ✅ 适用。student-portal 发起的 GraphQL query 深度必须 ≤ 7 | ai14 在 [02-architecture-design.md §4.2](../../../apps/student-portal/docs/02-architecture-design.md) 已设计扁平 query | ✅ 已落实 |
|
||||||
|
| ActionState 信封 | ✅ 适用。student-bff 必须返回 ActionState 信封(success/errors/data) | ai14 在 GraphQL 请求层(02 §3.2)已处理信封解包 + 降级字段识别 | ✅ 已落实 |
|
||||||
|
| 降级模式(方案 B) | ✅ 适用。部分聚合失败时 success=true + data 内 `extensions.degraded: true` | ai14 在 [02 §18.2 降级策略矩阵](../../../apps/student-portal/docs/02-architecture-design.md) 已设计 12 个降级场景 | ✅ 已落实 |
|
||||||
|
| admin 命名空间 | ❌ 不适用。student-portal 不涉及 admin 命名空间 | - | - |
|
||||||
|
|
||||||
|
**核查结论**:ARB-001 是 teacher-bff 的 P2 仲裁,但其设计原则(Schema 集中管理、ActionState 信封、降级模式方案 B、复杂度限制)适用于所有 BFF,student-portal 已在 02-architecture-design.md v2 中全面落实。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.2 ARB-002(MF Shell 暴露清单)对 student-portal 的影响核查
|
||||||
|
|
||||||
|
| 裁决点 | 对 student-portal 的适用性 | ai14 落实方案 | 状态 |
|
||||||
|
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
|
||||||
|
| Shell 身份 | ✅ 适用。teacher-portal 是 MF Shell,student-portal 是 P3 首个 Remote | ai14 在 [02 §3.2 MF 配置](../../../apps/student-portal/docs/02-architecture-design.md) 已声明 `remotes: { teacher: 'teacher@http://localhost:4000/_next/static/chunks/remoteEntry.js' }` | ✅ 已落实 |
|
||||||
|
| P3 首个 Remote | ✅ 适用。ARB-002 §2.3 明确 P3 首个 Remote 是 student-portal | ai14 P3 任务启动即接入 MF Remote | ✅ 已落实 |
|
||||||
|
| GraphQL client 归属 | ✅ 适用。Shell 暴露 GraphQLProvider,student-portal 复用,**不重复创建 client** | ai14 在 [02 §3.2 GraphQL 请求层](../../../apps/student-portal/docs/02-architecture-design.md) 已使用 `useGraphQLClient()` 从 `@edu/hooks` 获取 | ✅ 已落实 |
|
||||||
|
| MF shared singleton 配置 | ✅ 适用。student-portal 必须将 react/react-dom/urql/graphql/@edu/* 声明为 singleton | ai14 在 [02 §3.2 next.config.js](../../../apps/student-portal/docs/02-architecture-design.md) 已声明全部 singleton | ✅ 已落实 |
|
||||||
|
| AppShell 复用 | ✅ 适用。student-portal 不重复实现 AppShell,复用 Shell 暴露的 AppShell | ai14 在 02 §3.2 已设计 `<AppShell>` 包裹 + 学生端导航覆写 | ✅ 已落实 |
|
||||||
|
| useAuth / usePermission 复用 | ✅ 适用。student-portal 复用 Shell 暴露的 useAuth/usePermission | ai14 在 [01-understanding.md §6](../../../apps/student-portal/docs/01-understanding.md) 已声明权限校验走 usePermission | ✅ 已落实 |
|
||||||
|
| ErrorBoundary / Loading / Empty 复用 | ✅ 适用。student-portal 复用 Shell 暴露的共享 UI 组件 | ai14 在 02 §6 组件设计已使用 `@edu/ui-components` | ✅ 已落实 |
|
||||||
|
| feature flag | ✅ 适用。`NEXT_PUBLIC_MF_ENABLED` 控制是否走 MF;P3 默认 true | ai14 在 02 §3.2 已设计独立壳回退(MF 关闭时独立渲染) | ✅ 已落实 |
|
||||||
|
| 登录页 | ✅ 适用。P2 登录页由 Shell 独占;student-portal 不实现登录页,未登录跳转 Shell `/login` | ai14 在 02 §3.2 已设计未认证 → 跳转 `window.location.href = 'http://localhost:4000/login?redirect=student'` | ✅ 已落实 |
|
||||||
|
|
||||||
|
**核查结论**:ARB-002 是 student-portal 接入 MF 的直接依据,ai14 已在 02-architecture-design.md v2 中全面落实。无异议。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.3 ARB-001 / ARB-002 核查总结
|
||||||
|
|
||||||
|
| 仲裁 | 对 student-portal 的影响 | ai14 落实情况 | 异议 |
|
||||||
|
| ------ | ------------------------ | ------------- | ---- |
|
||||||
|
| ARB-001 | 设计原则适用(GraphQL + ActionState + 降级模式) | ✅ 已落实 | 无 |
|
||||||
|
| ARB-002 | 直接适用(P3 首个 Remote + Shell 暴露清单) | ✅ 已落实 | 无 |
|
||||||
|
|
||||||
|
> **ai14 声明**:ARB-001 / ARB-002 已在 02-architecture-design.md v2 中全面落实,无需新增仲裁。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §2 新提请异议(待 coord 仲裁)
|
||||||
|
|
||||||
|
### ISSUE-014-01-ai14:GraphQL endpoint 路径不一致(`/api/student/graphql` vs `/api/v1/student/graphql`)
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- `student-portal_contract.md` §2.3 当前写 `POST /api/student/graphql`(无 `/v1/` 前缀)
|
||||||
|
- `matrix.md` §5 HTTP 接口矩阵明确写 `api-gateway` 反向代理 `student-portal` 的路径是 `/api/v1/student/*`
|
||||||
|
- `01-understanding.md` v2 §3.1 和 `02-architecture-design.md` v2 §4.1 已统一为 `POST /api/v1/student/graphql`
|
||||||
|
- 三处不一致,需要 coord 仲裁统一为 `/api/v1/student/graphql`(与 matrix.md §5 对齐,与 teacher-portal `/api/v1/teacher/graphql` 保持命名一致性)
|
||||||
|
- **建议方案**:
|
||||||
|
- 统一为 `POST /api/v1/student/graphql`
|
||||||
|
- 由 ai01(api-gateway)确认路由:`/api/v1/student/*` → `student-bff:3009/*`(即 `/api/v1/student/graphql` → `student-bff:3009/graphql`)
|
||||||
|
- 由 ai04(student-bff)确认 GraphQL endpoint 路径为 `POST /graphql`(与 teacher-bff 一致)
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ISSUE-014-02-ai14:student-bff GraphQL schema 文件存放位置不一致(集中管理 vs 应用内管理)
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- ARB-001 §1.3 关键裁决明确:teacher-bff GraphQL schema 存放于 `packages/shared-ts/contracts/graphql/teacher-bff.graphql`(集中管理,总裁裁决 §2.17 SDL-first + 集中管理)
|
||||||
|
- `student-bff_contract.md` §1.3 写:`apps/student-bff/src/schema/*.graphql`(应用内管理,与 ARB-001 原则不一致)
|
||||||
|
- `matrix.md` §3 GraphQL 接口提供方矩阵写:`packages/shared-ts/contracts/graphql/student-bff.graphql`(与 ARB-001 一致)
|
||||||
|
- 两处不一致,需要 coord 仲裁统一
|
||||||
|
- **建议方案**:
|
||||||
|
- 统一为 `packages/shared-ts/contracts/graphql/student-bff.graphql`(与 ARB-001 原则对齐,集中管理便于前端 codegen)
|
||||||
|
- ai14 在 student-portal 端使用 `graphql-codegen` 从该 schema 生成 TypeScript 类型
|
||||||
|
- 由 ai04(student-bff)创建该 schema 文件并维护
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ISSUE-014-03-ai14:考试作答页全屏策略与防作弊检测边界
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- student-portal 02-architecture-design.md §14 设计了防作弊检测(visibilitychange/copy/paste/fullscreen/contextmenu),但未明确以下边界:
|
||||||
|
1. **全屏 API 强制策略**:是否强制全屏(Fullscreen API)?退出全屏是否触发警告/记录?
|
||||||
|
2. **离开页面策略**:visibilitychange hidden 触发时,是仅记录还是自动提交?
|
||||||
|
3. **多标签检测**:BroadcastChannel 检测到多标签时,是警告还是阻止作答?
|
||||||
|
4. **防作弊事件上报**:前端采集的防作弊事件如何上报?走 student-bff GraphQL mutation 还是 push-gateway WebSocket?
|
||||||
|
- 这些决策影响 ai04(student-bff)是否需要提供 `recordExamViolation` mutation,以及 ai08(core-edu)是否需要存储违规记录
|
||||||
|
- **建议方案**:
|
||||||
|
- **全屏策略**:P3 推荐但不强制(提示"建议全屏作答"),P4 评估是否升级为强制(基于教师反馈)
|
||||||
|
- **离开页面策略**:visibilitychange hidden 触发时仅记录(不自动提交),累计 3 次警告后教师端可见
|
||||||
|
- **多标签检测**:警告 + 记录,不阻止作答(避免误伤合法场景如查词典)
|
||||||
|
- **防作弊事件上报**:走 student-bff GraphQL mutation `recordExamViolation(examId, type, payload)`,由 ai04 在 P3 提供
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ISSUE-014-04-ai14:主观题粘贴策略(防作弊 vs 学生体验)
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- 02-architecture-design.md §14 防作弊检测包含 `paste` 事件拦截,但学生作答主观题时可能需要粘贴(如从草稿本粘贴长文本)
|
||||||
|
- 策略不明确:全部禁止粘贴?仅主观题允许?仅客观题禁止?
|
||||||
|
- 影响学生体验和防作弊效果平衡
|
||||||
|
- **建议方案**:
|
||||||
|
- **客观题**:禁止粘贴(防作弊优先)
|
||||||
|
- **主观题(简答/论述)**:允许粘贴,但记录粘贴事件 + 粘贴内容长度,教师端批改时可见
|
||||||
|
- **作文题**:允许粘贴(学生体验优先),不记录
|
||||||
|
- 由 ai04(student-bff)在 P3 提供 `recordPasteEvent` mutation(或复用 ISSUE-014-03 的 `recordExamViolation`,type=`PASTE`)
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ISSUE-014-05-ai14:作业附件上传协议(GraphQL mutation vs REST multipart)
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- 学生提交作业时可能需要上传附件(图片/PDF/文档),GraphQL mutation 不适合处理大文件上传(multipart/form-data)
|
||||||
|
- 当前 contract.md 未明确附件上传协议
|
||||||
|
- 选项:
|
||||||
|
- A. 走 api-gateway REST 端点(`POST /api/v1/student/upload` → 对象存储),返回 URL,再走 GraphQL mutation 提交 URL
|
||||||
|
- B. 走 student-bff GraphQL multipart(graphql-upload,需要 ai04 支持)
|
||||||
|
- C. 走独立上传服务(如 push-gateway 扩展或新建 upload-service)
|
||||||
|
- **建议方案**:
|
||||||
|
- **推荐 A**:走 api-gateway REST `POST /api/v1/student/upload` → 对象存储(MinIO/OSS),返回 signed URL,再走 GraphQL `submitHomework(attachmentUrls: [String!])` mutation 提交
|
||||||
|
- 理由:GraphQL 不适合大文件传输;REST + 对象存储是业界通用方案;api-gateway 已有 JWT 鉴权
|
||||||
|
- 由 ai01(api-gateway)确认是否提供 `/api/v1/student/upload` 路由,由 ai04(student-bff)确认 `submitHomework` mutation 是否接受 `attachmentUrls` 字段
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ISSUE-014-06-ai14:考试延长/题目重排等实时事件命名未确认
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- student-portal 02-architecture-design.md §16 设计了 WebSocket 实时通知,但以下事件命名未在 matrix.md §4 Kafka 事件矩阵中确认:
|
||||||
|
1. **考试延长**(教师延长考试时间):事件名 `ExamExtended`?还是 `ExamUpdated`?由 ai08(core-edu)发布?
|
||||||
|
2. **题目重排**(教师重排题目顺序):事件名 `ExamQuestionReordered`?是否需要前端实时重排?
|
||||||
|
3. **考试强制提交**(教师强制收卷):事件名 `ExamForceSubmitted`?前端收到后立即提交?
|
||||||
|
- 这些事件影响 student-portal 考试作答页的实时响应逻辑
|
||||||
|
- **建议方案**:
|
||||||
|
- **考试延长**:ai08(core-edu)发布 `ExamExtended` 事件到 `edu.exam.events` topic,msg(ai10)消费后通过 push-gateway 推送,student-portal 收到后更新倒计时
|
||||||
|
- **题目重排**:P3 不实现(题目顺序固定),P4 评估是否需要实时重排
|
||||||
|
- **考试强制提交**:ai08 发布 `ExamForceSubmitted` 事件,student-portal 收到后立即触发提交流程
|
||||||
|
- 由 ai08(core-edu)确认事件命名,由 ai10(msg)确认推送路径
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ISSUE-014-07-ai14:学生端 DataScope L0 边界(仅能查看自己数据)的强制执行层
|
||||||
|
|
||||||
|
- **提请方**:ai14
|
||||||
|
- **日期**:2026-07-10
|
||||||
|
- **类型**:契约不明确
|
||||||
|
- **描述**:
|
||||||
|
- 01-understanding.md §8 和 02-architecture-design.md §6 声明学生 DataScope L0(仅能查看自己数据)
|
||||||
|
- 但强制执行层不明确:
|
||||||
|
- A. student-bff 在 Resolver 层基于 JWT 的 `x-user-id` 强制过滤(推荐,前端无法绕过)
|
||||||
|
- B. student-portal 在 GraphQL query 中显式传 `studentId`(不安全,前端可篡改)
|
||||||
|
- 当前 02-architecture-design.md §4.2 的 GraphQL query 设计中,部分 query 显式传 `studentId`(如 `myClasses(studentId: ID!)`),这与 L0 强制执行矛盾
|
||||||
|
- **建议方案**:
|
||||||
|
- **统一为方案 A**:student-bff 在 Resolver 层从 JWT `x-user-id` 提取 studentId,强制过滤,前端 query 不传 `studentId` 参数
|
||||||
|
- ai14 修改 02-architecture-design.md §4.2 的 GraphQL query 定义,移除 `studentId` 参数(如 `myClasses` 改为无参 query)
|
||||||
|
- 由 ai04(student-bff)确认所有学生端 Query 均从 JWT 提取 studentId,不接受前端传入
|
||||||
|
- **状态**:待 coord 仲裁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §3 异议状态汇总
|
||||||
|
|
||||||
|
| 编号 | 类型 | 标题 | 状态 |
|
||||||
|
| ------------- | ------------ | -------------------------------------------------------- | ------------ |
|
||||||
|
| ISSUE-014-01 | 契约不明确 | GraphQL endpoint 路径不一致 | 待 coord 仲裁 |
|
||||||
|
| ISSUE-014-02 | 契约不明确 | student-bff GraphQL schema 存放位置不一致 | 待 coord 仲裁 |
|
||||||
|
| ISSUE-014-03 | 契约不明确 | 考试作答页全屏策略与防作弊检测边界 | 待 coord 仲裁 |
|
||||||
|
| ISSUE-014-04 | 契约不明确 | 主观题粘贴策略(防作弊 vs 学生体验) | 待 coord 仲裁 |
|
||||||
|
| ISSUE-014-05 | 契约不明确 | 作业附件上传协议(GraphQL mutation vs REST multipart) | 待 coord 仲裁 |
|
||||||
|
| ISSUE-014-06 | 契约不明确 | 考试延长/题目重排等实时事件命名未确认 | 待 coord 仲裁 |
|
||||||
|
| ISSUE-014-07 | 契约不明确 | 学生端 DataScope L0 边界的强制执行层 | 待 coord 仲裁 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
追加条目格式:
|
追加条目格式:
|
||||||
@@ -20,5 +216,3 @@
|
|||||||
- **建议方案**:[AI 的建议]
|
- **建议方案**:[AI 的建议]
|
||||||
- **状态**:待 coord 仲裁 / 已裁决(见 coord.md §X)
|
- **状态**:待 coord 仲裁 / 已裁决(见 coord.md §X)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
(暂无问题)
|
|
||||||
|
|||||||
@@ -1,45 +1,271 @@
|
|||||||
# student-portal 工作排期
|
# student-portal 工作排期
|
||||||
|
|
||||||
> 负责人:ai14
|
> 负责人:ai14
|
||||||
> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/student-portal_contract.md](../contracts/student-portal_contract.md)
|
> 关联:[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 全部代码,最后统一集成测试)
|
> 模式:全并行(各 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 总览
|
## §1 总览
|
||||||
|
|
||||||
student-portal 是学生端微前端,通过 MF Remote 接入主应用,覆盖考试作答、作业提交等场景。全阶段目标:P2 MF Remote 骨架 → P3 考试作答+作业提交 → P4-P6 持续优化。
|
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,各 AI 自行细化)
|
## §2 全阶段甘特图(P2-P6)
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
gantt
|
gantt
|
||||||
title ai14 student-portal 全阶段排期
|
title ai14 student-portal 全阶段排期(全并行)
|
||||||
dateFormat YYYY-MM-DD
|
dateFormat YYYY-MM-DD
|
||||||
axisFormat %m-%d
|
axisFormat %m-%d
|
||||||
|
|
||||||
section P2-P6
|
section P2 预埋
|
||||||
[阶段任务] :a14a, 2026-07-10, Xd
|
项目骨架+设计令牌三层+独立壳路由 :crit, a14p0, 2026-07-10, 2d
|
||||||
```
|
MF Remote配置(NextFederationPlugin remotes) :crit, a14a, after a14p0, 2d
|
||||||
|
MSW基础设施+GraphQL请求层骨架 :a14b, after a14a, 2d
|
||||||
|
|
||||||
> **注意**:以上为 coord 初始规划,ai14 接管后必须自行细化为完整 P2-P6 排期。
|
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 详细任务
|
## §3 详细任务
|
||||||
|
|
||||||
### 全阶段任务
|
### P2:MF Remote 骨架预埋
|
||||||
|
|
||||||
- **负责人**:ai14
|
- **负责人**:ai14
|
||||||
- **交付物**:⚠️ 由 ai14 自行补充
|
- **裁决依据**:ARB-002 §2.3(P3 首个 Remote,但 P2 可预埋骨架)+ 总裁裁决 §3.6(ai14 P3 起步)+ §2.17(MF GraphQL client 单例方案 A)
|
||||||
- **依赖**:见 [contracts/student-portal_contract.md](../contracts/student-portal_contract.md)
|
- **交付物**:
|
||||||
- **验收标准**:⚠️ 由 ai14 自行补充
|
- 项目骨架(`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 依赖与就绪信号
|
||||||
|
|
||||||
- **我依赖**:⚠️ 由 ai14 自行补充(见 contract.md)
|
### §4.1 我依赖的上游就绪标志
|
||||||
- **我的就绪信号**:⚠️ 由 ai14 自行补充
|
|
||||||
|
| 上游 | 就绪标志 | 阻塞阶段 | 状态 |
|
||||||
|
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -------- | ----------- |
|
||||||
|
| 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
|
||||||
|
|||||||
Reference in New Issue
Block a user