Files
Edu/docs/architecture/issues/contracts/student-portal_contract.md

19 KiB
Raw Blame History

student-portal 对接契约

负责人ai14 关联:matrix.mdcoord.md §1 ARB-001coord.md §2 ARB-002student-bff_contract.mdteacher-portal_contract.md 版本v2ai14 接管审计与补全版2026-07-10 修订摘要GraphQL endpoint 路径修正为 /api/v1/student/graphql(对齐 matrix.md §5+ 补全 24 个 GraphQL query/mutation对齐 02 §4.2+ 补充 ARB-002 MF Shell 暴露清单 + 补充就绪信号明细


§1 我提供什么(对外接口)

1.1 gRPC 接口(如有)

无。student-portal 是前端微前端 Remote。

1.2 HTTP 端点(如有)

Method Path 用途 认证
GET / 学生门户首页 JWT 必需(前端路由守卫)
GET /my-classes 我的班级 JWT 必需
GET /my-exams 我的考试 JWT 必需
GET /my-exams/[id]/take 考试作答页 JWT 必需
GET /my-exams/[id]/result 考试结果页 JWT 必需
GET /my-homework 我的作业 JWT 必需
GET /my-homework/[id]/submit 作业提交页 JWT 必需
GET /my-grades 我的成绩 JWT 必需
GET /my-attendance 我的考勤 JWT 必需
GET /learning-path 学习路径 JWT 必需
GET /dashboard 学生仪表盘 JWT 必需
GET /dashboard/weakness 学情诊断 JWT 必需
GET /dashboard/trend 学习趋势 JWT 必需
GET /textbooks 教材列表 JWT 必需
GET /textbooks/[id]/chapters 章节列表 JWT 必需
GET /notifications 通知中心 JWT 必需
GET /ai-tutor AI 辅助答疑P5 可选) JWT 必需

路由前缀:无 /student/ 前缀student-portal 作为 MF Remote由 Shell 路由 /student/* 加载,内部路由无前缀)。

1.3 GraphQL schema如 BFF

不适用。student-portal 消费 student-bff GraphQL自身不提供 schema。

消费的 schema 文件packages/shared-ts/contracts/graphql/student-bff.graphql(已裁决 ARB-019 §21由 ai04 创建,对齐 ARB-001 §1.3 集中管理原则)

1.4 Kafka 事件发布(如有)

无。

1.5 错误码前缀

无(前端不定义错误码前缀,透传 BFF 错误码 BFF_STUDENT_*,见 matrix.md §6)。

1.6 微前端架构MF RemoteARB-002 对齐)

角色 说明
MF Remote student-portal 是微前端远程模块P3 首个 RemoteARB-002 §2.3),由 teacher-portal AppShell 加载
暴露的 remote 模块 ./StudentApp(学生端完整应用)
module federation 配置 apps/student-portal/next.config.jsNextFederationPlugin
Shell 暴露清单(复用) AppShell / GraphQLProvider / useAuth / usePermission / useGraphQLClient / ErrorBoundary / Loading / Empty / RequirePermissionARB-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-tsARB-002 §2.2
feature flag NEXT_PUBLIC_MF_ENABLEDP2=false 独立壳P3=true 接入 Shell
登录页 不实现,未登录跳转 http://localhost:4000/login?redirect=studentARB-002 §2.3 登录由 Shell 独占)

1.7 WebSocket 消费push-gateway

端点 用途 认证 事件类型
ws://push-gateway:8081/ws 实时通知推送 JWT 作业通知 / 考试通知 / 成绩通知 / 系统通知 / 考试延长ExamExtended / 考试强制提交ExamForceSubmittedARB-019 §21.6 已裁决)

§2 我消费什么(依赖上游)

2.1 gRPC 调用(同步)

无。前端不直接调 gRPC。

2.2 Kafka 事件订阅(异步)

无。前端不直接订阅 Kafka。

2.3 HTTP 调用(如有)

被调用方 Method.Path 用途 mock 策略
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 学生登录Shell 独占student-portal 不直接调用,仅跳转) api-gateway 就绪前由 Shell 处理
api-gateway (ai01) POST /api/v1/student/upload 作业附件上传ARB-019 §21.5 方案 A 按方案 A 实现REST + 对象存储 + GraphQL 提交 URL
push-gateway (ai02) GET /wsWebSocket 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/* 保持命名一致性
  • 由 ai01api-gateway确认路由配置/api/v1/student/*student-bff:3009/*

2.4 GraphQL 查询域(经 api-gateway 代理到 student-bff

对齐 02-architecture-design.md v2 §4.2 GraphQL 操作清单(共 24 个)

2.4.1 Query16 个)

Query 用途 mock 策略
currentUser 当前学生信息 MSW 返回固定学生id=student-001, roles=[student]
myClasses 我的班级 MSW 返回固定 1 个班级
myExams 我的考试列表 MSW 返回固定 2 个考试
examDetail(id: ID!) 考试详情(含题目) MSW 返回固定考试 + 5 道题
myHomework 我的作业列表 MSW 返回固定 3 个作业1 个待提交)
homeworkDetail(id: ID!) 作业详情 MSW 返回固定作业 + 题目
myGrades 我的成绩 MSW 返回固定 5 个成绩
myAttendance 我的考勤 MSW 返回固定 10 条考勤
textbooks 教材列表 MSW 返回固定 5 个教材
chapters(textbookId: ID!) 章节列表 MSW 返回固定章节树
learningPath 学习路径 MSW 返回固定 8 个知识点推荐顺序
studentDashboard 学生仪表盘 MSW 返回固定仪表盘avg_score=85.0, class_rank=5
myWeakness 我的薄弱点 MSW 返回固定 3 个 weak_points
myTrend 学习趋势 MSW 返回固定趋势数据
myNotifications(first: Int, after: String) 通知列表 MSW 返回固定 10 条通知
serverTime 服务器时间(考试倒计时对齐) MSW 返回当前时间 + 100ms 延迟

2.4.2 Mutation8 个)

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!) 记录防作弊违规ARB-019 §21.4 MSW 返回 success=true
recordPasteEvent(input: RecordPasteEventInput!) 记录粘贴事件ARB-019 §21.4 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 层会重新校验)

§3 就绪信号

3.1 我依赖的上游就绪标志

上游 就绪标志 阻塞阶段 状态
packages 骨架ai13 批次 0.15 ui-tokens / ui-components / hooks 可 import P2 启动 已就绪
teacher-portal MF Shellai13 P2 exposes AppShell/GraphQLProvider/useGraphQLClient/useAuth/usePermission + shared singleton P2 启动 待 ai13 P2
api-gateway HTTP :8080ai01 P3 /api/v1/student/* 反向代理 student-bff 可用 P3 启动 待 ai01 P3
student-bff GraphQLai04 P3 POST /graphql :3009 + 核心 Query/Mutation 可执行 P3 启动 待 ai04 P3
student-bff GraphQL schema packages/shared-ts/contracts/graphql/student-bff.graphql 创建ARB-019 §21 已裁决) P3 启动 已裁决
core-edu gRPC 50053ai08 P3 ExamService/HomeworkService/GradeService/AttendanceService/ClassService P3 启动 待 ai08 P3
iam gRPC 50052ai06 P2 GetUserInfo + GetEffectivePermissions + GetViewports P3 启动 待 ai06 P2
content gRPC 50054ai09 P4 TextbookService + ChapterService + KnowledgeGraphService P4 启动 待 ai09 P4
data-ana gRPC 50055ai11 P4 AnalyticsService.GetStudentWeakness + GetLearningTrend P4 启动 待 ai11 P4
push-gateway WebSocket :8081/wsai02 P5 WS 连接可建立 + 推送可接收 P5 启动 待 ai02 P5
msg gRPC 50056ai10 P5 NotificationService.ListNotifications + MarkAsRead P5 启动 待 ai10 P5
ai 服务 gRPC 50058ai12 P5可选 AiService.ChatSSE 流式) P5 启动 待 ai12 P5

3.2 我的就绪标志(供下游消费)

  • student-portal dev server :4001 启用(pnpm dev 可访问)
  • MF Remote 可被 AppShell 加载(暴露 ./StudentApp 模块teacher-portal Shell 可加载)
  • 独立壳渲染(NEXT_PUBLIC_MF_ENABLED=false 时首页 + 导航 + 路由守卫独立可用)
  • 登录流程可用(未登录跳转 Shell /login,登录后回跳 student
  • GraphQL 查询可执行currentUser / studentDashboard / myClasses 返回数据)
  • 考试作答链路通(进入作答 → 自动保存 → 提交 → 跳转结果页)
  • WebSocket 通知可接收(通知中心实时更新)
  • lint + typecheck 零错误

§4 Mock 策略

4.1 我提供的 mock

student-portal 是前端,无下游消费方。但对开发体验提供:

  • Storybook:各组件独立 storyapps/student-portal/.storybook/
  • MSW handlersapps/student-portal/src/mocks/handlers.ts,拦截所有 GraphQL/HTTP 请求
  • Mock fixturesapps/student-portal/src/mocks/fixtures/*.json,与 student-bff mock 数据一致

4.2 我消费的 mock

在真实上游就绪前student-portal 使用以下 mock

4.2.1 HTTP / GraphQL mockMSW

  • POST /api/v1/student/graphql → 按 operationName 返回对应 mock 响应(见 §2.4
  • POST /api/auth/login → 返回固定 JWT + UserInfostudent 角色)由 Shell 处理
  • POST /api/v1/student/upload → 返回固定 signed URLARB-019 §21.5 方案 A 已裁决)
  • 所有 mock 响应定义在 apps/student-portal/src/mocks/fixtures/*.json

4.2.2 WebSocket mockmock-socket

  • 连接 ws://localhost:8081/ws 后每 30 秒推送 1 条 mock 通知
  • 通知类型轮询:作业通知 / 考试通知 / 成绩通知 / 系统通知
  • 支持模拟考试延长事件 ExamExtended + 考试强制提交 ExamForceSubmittedARB-019 §21.6 已裁决)

4.2.3 JWT mock

  • 使用固定 mock JWTeyJhbGciOiJSUzI1NiIs...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=falseP2 独立壳)→ trueP3 接入 Shell

4.2.5 IDB 草稿恢复(真实 idb-keyval

  • 考试作答草稿使用真实 idb-keyval 存储(前端可独立测试断网恢复逻辑)
  • 不需要 mockIDB 在浏览器原生支持

§5 与 student-bff 契约对齐核查

参考 student-bff_contract.mdai04 维护)

对齐项 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/*.graphqlARB-019 §21 已裁决,统一为集中管理) 已裁决
Query 域16 个) 见 §2.4.1 见 student-bff §1.3auth/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 已裁决 ARB-019 §21.7(方案 AResolver 从 JWT 提取) 已裁决

§6 异议引用

详见 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: ai14student-portal Branch: feat-review-student-portal-docs-9yN6Av Coordinator: coord-ai