Files
Edu/docs/architecture/issues/objections/student-portal_issue.md
SpecialX c179af64a6 docs(docs): coord 完成 15 模块 issue 仲裁与基础设施同步
coord.md 新增 ARB-019/020/021 三章仲裁章节,修正 ARB-001。

- coord.md: 新增 ARB-019/020/021(student/parent/admin-portal 24 项)
- coord.md: 修正 ARB-001(admin P2 预留/schema 文件名/classes 数据源)
- 004 §4: 依赖图加 PBFF→DataAna+Msg
- 004 §7.2: push-gateway→Redis 软失败标注
- 004 §11.4: 错误码前缀矩阵(11 服务+i18n key)
- 004 §11.5: ActionState 信封规范(降级模式方案 B)
- matrix §1: 依赖矩阵加 PBFF 边
- matrix §2: 移除 api-gateway 为 iam gRPC 消费方
- matrix §4: admin-portal→teacher-bff
- matrix §5: 移除 /sse+鉴权头统一
- matrix §6: 错误码表补 i18n key 列
- 15 个 issue.md: 仲裁结论回写
- push-gateway_contract: 移除 /sse+鉴权头改 X-Internal-Token
- packages/contracts: 新建包 ADMIN_* 权限点常量

AI: coord
2026-07-10 16:30:51 +08:00

20 KiB
Raw Blame History

student-portal 问题记录

负责人ai14 关联:coord.mdcontracts/student-portal_contract.mdmatrix.md 规则AI 遇到问题时在此追加条目coord 仲裁后更新状态


§1 已有仲裁核查ARB-001 / ARB-002 对 student-portal 的影响)

1.1 ARB-001teacher-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 全量 QuerycurrentUser/myClasses/myExams/myHomework/myGrades/myAttendance/studentDashboard 已落实
P2 Mutation 范围 ⚠️ 部分参考。student-portal P3 起步即需要 submitHomework mutation作业提交是 P3 核心场景) ai14 P3 即消费 submitHomework mutationai04 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 已设计扁平 query 已落实
ActionState 信封 适用。student-bff 必须返回 ActionState 信封success/errors/data ai14 在 GraphQL 请求层02 §3.2)已处理信封解包 + 降级字段识别 已落实
降级模式(方案 B 适用。部分聚合失败时 success=true + data 内 extensions.degraded: true ai14 在 02 §18.2 降级策略矩阵 已设计 12 个降级场景 已落实
admin 命名空间 不适用。student-portal 不涉及 admin 命名空间 - -

核查结论ARB-001 是 teacher-bff 的 P2 仲裁但其设计原则Schema 集中管理、ActionState 信封、降级模式方案 B、复杂度限制适用于所有 BFFstudent-portal 已在 02-architecture-design.md v2 中全面落实。


1.2 ARB-002MF Shell 暴露清单)对 student-portal 的影响核查

裁决点 对 student-portal 的适用性 ai14 落实方案 状态
Shell 身份 适用。teacher-portal 是 MF Shellstudent-portal 是 P3 首个 Remote ai14 在 02 §3.2 MF 配置 已声明 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 暴露 GraphQLProviderstudent-portal 复用,不重复创建 client ai14 在 02 §3.2 GraphQL 请求层 已使用 useGraphQLClient()@edu/hooks 获取 已落实
MF shared singleton 配置 适用。student-portal 必须将 react/react-dom/urql/graphql/@edu/* 声明为 singleton ai14 在 02 §3.2 next.config.js 已声明全部 singleton 已落实
AppShell 复用 适用。student-portal 不重复实现 AppShell复用 Shell 暴露的 AppShell ai14 在 02 §3.2 已设计 <AppShell> 包裹 + 学生端导航覆写 已落实
useAuth / usePermission 复用 适用。student-portal 复用 Shell 暴露的 useAuth/usePermission ai14 在 01-understanding.md §6 已声明权限校验走 usePermission 已落实
ErrorBoundary / Loading / Empty 复用 适用。student-portal 复用 Shell 暴露的共享 UI 组件 ai14 在 02 §6 组件设计已使用 @edu/ui-components 已落实
feature flag 适用。NEXT_PUBLIC_MF_ENABLED 控制是否走 MFP3 默认 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-ai14GraphQL 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
    • 由 ai01api-gateway确认路由/api/v1/student/*student-bff:3009/*(即 /api/v1/student/graphqlstudent-bff:3009/graphql
    • 由 ai04student-bff确认 GraphQL endpoint 路径为 POST /graphql(与 teacher-bff 一致)
  • 状态:待 coord 仲裁

ISSUE-014-02-ai14student-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 类型
    • 由 ai04student-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
    • 这些决策影响 ai04student-bff是否需要提供 recordExamViolation mutation以及 ai08core-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 事件拦截,但学生作答主观题时可能需要粘贴(如从草稿本粘贴长文本)
    • 策略不明确:全部禁止粘贴?仅主观题允许?仅客观题禁止?
    • 影响学生体验和防作弊效果平衡
  • 建议方案
    • 客观题:禁止粘贴(防作弊优先)
    • 主观题(简答/论述):允许粘贴,但记录粘贴事件 + 粘贴内容长度,教师端批改时可见
    • 作文题:允许粘贴(学生体验优先),不记录
    • 由 ai04student-bff在 P3 提供 recordPasteEvent mutation或复用 ISSUE-014-03 的 recordExamViolationtype=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 multipartgraphql-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 鉴权
    • 由 ai01api-gateway确认是否提供 /api/v1/student/upload 路由,由 ai04student-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?由 ai08core-edu发布
      2. 题目重排(教师重排题目顺序):事件名 ExamQuestionReordered?是否需要前端实时重排?
      3. 考试强制提交(教师强制收卷):事件名 ExamForceSubmitted?前端收到后立即提交?
    • 这些事件影响 student-portal 考试作答页的实时响应逻辑
  • 建议方案
    • 考试延长ai08core-edu发布 ExamExtended 事件到 edu.exam.events topicmsgai10消费后通过 push-gateway 推送student-portal 收到后更新倒计时
    • 题目重排P3 不实现题目顺序固定P4 评估是否需要实时重排
    • 考试强制提交ai08 发布 ExamForceSubmitted 事件student-portal 收到后立即触发提交流程
    • 由 ai08core-edu确认事件命名由 ai10msg确认推送路径
  • 状态:待 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 强制执行矛盾
  • 建议方案
    • 统一为方案 Astudent-bff 在 Resolver 层从 JWT x-user-id 提取 studentId强制过滤前端 query 不传 studentId 参数
    • ai14 修改 02-architecture-design.md §4.2 的 GraphQL query 定义,移除 studentId 参数(如 myClasses 改为无参 query
    • 由 ai04student-bff确认所有学生端 Query 均从 JWT 提取 studentId不接受前端传入
  • 状态:待 coord 仲裁

§3 异议状态汇总

编号 类型 标题 状态
ISSUE-014-01 契约不明确 GraphQL endpoint 路径不一致 已裁决(见 coord.md §21 ARB-019
ISSUE-014-02 契约不明确 student-bff GraphQL schema 存放位置不一致 已裁决(见 coord.md §21 ARB-019
ISSUE-014-03 契约不明确 考试作答页全屏策略与防作弊检测边界 已裁决(见 coord.md §21 ARB-019
ISSUE-014-04 契约不明确 主观题粘贴策略(防作弊 vs 学生体验) 已裁决(见 coord.md §21 ARB-019
ISSUE-014-05 契约不明确 作业附件上传协议GraphQL mutation vs REST multipart 已裁决(见 coord.md §21 ARB-019
ISSUE-014-06 契约不明确 考试延长/题目重排等实时事件命名未确认 已裁决(见 coord.md §21 ARB-019
ISSUE-014-07 契约不明确 学生端 DataScope L0 边界的强制执行层 已裁决(见 coord.md §21 ARB-019

§4 仲裁结论coord 2026-07-10

详见 coord.md §21 ARB-019 完整仲裁章节

ISSUE 仲裁结论摘要 执行方
014-01 统一为 POST /api/v1/student/graphql(双 /v1 前缀,对齐 ARB-014 方案 A ai14 修 contract + ai01 确认路由
014-02 统一为 packages/shared-ts/contracts/graphql/student-bff.schema.graphql ai04 创建并维护
014-03 P3 不强制全屏 + visibilitychange 仅记录 + 多标签警告不阻止 + recordExamViolation mutation ai14 + ai04 + ai08 补 RPC
014-04 客观题禁止 / 主观题允许记录 / 作文题允许不记录;复用 recordExamViolationtype=PASTE ai14 + ai04
014-05 方案 Aapi-gateway REST POST /api/v1/student/upload → 对象存储 → GraphQL mutation 提交 URL ai01 路由 + ai04 mutation
014-06 ExamExtended + ExamForceSubmittedai08 发布到 edu.exam.events);题目重排 P3 不实现 P4 评估 ai08 发布 + ai10 推送
014-07 方案 Astudent-bff Resolver 从 JWT x-user-id 提取 studentId前端 query 不传 studentId ai14 修 query 设计 + ai04 实现