# coord 仲裁结果汇总 > 维护者:coord(协调 AI) > 维护规则:各 AI 在 `objections/[模块名]_issue.md` 提请异议 → coord 审阅 → 在本文件写入仲裁结果 > 关联文档:[president-final-rulings.md](../president-final-rulings.md)、[ai-work-orchestration.md](../ai-work-orchestration.md)、[workline.md](./workline.md)、[matrix.md](./matrix.md) --- ## 仲裁记录索引 | 编号 | 日期 | 提请方 | 主题 | 状态 | 仲裁章节 | | ------- | ---------- | --------------------- | ------------------------------------------------------------------------ | --------- | -------- | | ARB-001 | 2026-07-09 | coord(全并行启动前) | teacher-bff GraphQL schema 第一版 | ✅ 已裁决 | §1 | | ARB-002 | 2026-07-09 | coord(全并行启动前) | MF Shell 暴露清单 | ✅ 已裁决 | §2 | | ARB-003 | 2026-07-10 | ai06 | iam 模块 7 项 ISSUE 仲裁 | ✅ 已裁决 | §3 | | ARB-004 | 2026-07-10 | ai08 | core-edu 模块 7 项 ISSUE 仲裁 | ✅ 已裁决 | §4 | | ARB-005 | 2026-07-10 | ai09 | content 模块 10 项 ISSUE 仲裁 | ✅ 已裁决 | §5 | | ARB-006 | 2026-07-10 | coord(跨模块) | events.proto 补全(跨 iam/core-edu/content) | ✅ 已裁决 | §6 | | ARB-007 | 2026-07-10 | coord(跨模块) | proto 契约补全汇总(iam.proto + core_edu.proto) | ✅ 已裁决 | §7 | | ARB-008 | 2026-07-10 | ai10 | msg 模块 15 项 ISSUE 仲裁 | ✅ 已裁决 | §10 | | ARB-009 | 2026-07-10 | ai11 | data-ana 模块 6 项 ISSUE 仲裁 | ✅ 已裁决 | §11 | | ARB-010 | 2026-07-10 | ai12 | ai 模块 9 项 ISSUE 仲裁 | ✅ 已裁决 | §12 | | ARB-011 | 2026-07-10 | coord(跨模块) | events.proto 扩展补全(msg/data-ana/ai message)+ proto package 命名统一 | ✅ 已裁决 | §13 | | ARB-012 | 2026-07-10 | coord(跨模块) | analytics.proto + ai.proto 补全 | ✅ 已裁决 | §14 | | ARB-013 | 2026-07-10 | coord(跨模块) | Kafka topic 命名统一裁决(跨全模块) | ✅ 已裁决 | §15 | | ARB-014 | 2026-07-10 | ai01 | api-gateway 模块 4 项内联 ISSUE 仲裁 | ✅ 已裁决 | §16 | | ARB-015 | 2026-07-10 | ai02 | push-gateway 模块 7 项 ISSUE 仲裁 | ✅ 已裁决 | §17 | | ARB-016 | 2026-07-10 | ai03 | teacher-bff 模块 3 项 ISSUE 仲裁 | ✅ 已裁决 | §18 | | ARB-017 | 2026-07-10 | ai04 | student-bff 模块 4 项新 ISSUE 仲裁 | ✅ 已裁决 | §19 | | ARB-018 | 2026-07-10 | ai05 | parent-bff 模块 10 项 ISSUE 仲裁 | ✅ 已裁决 | §20 | | ARB-019 | 2026-07-10 | ai14 | student-portal 模块 7 项 ISSUE 仲裁 | ✅ 已裁决 | §21 | | ARB-020 | 2026-07-10 | ai15 | parent-portal 模块 10 项 ISSUE 仲裁 | ✅ 已裁决 | §22 | | ARB-021 | 2026-07-10 | ai16 | admin-portal 模块 7 项 ISSUE 仲裁 | ✅ 已裁决 | §23 | --- ## §1 ARB-001:teacher-bff GraphQL schema 第一版 ### 1.1 背景 全并行启动前,需仲裁 teacher-bff GraphQL schema 第一版,作为 ai03(teacher-bff)和 ai13(teacher-portal)的共同契约。 数据源:ai03 的 [02-architecture-design.md §5](../../services/teacher-bff/docs/02-architecture-design.md#L503) 提供了目标态 schema(P4),但 P2 只需 Must Have 子集。 ### 1.2 仲裁结论 **P2 第一版 schema 范围**(Must Have,对应 ai03 P2 工作量分级 Must Have 13 项): ```graphql # ============ P2 第一版 schema ============ # 存放位置:packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql # 仲裁原则:仅包含 P2 可实现的 Query(iam 已就绪),Mutation 延后到 P3 # 修订(ARB-016 §18):admin 命名空间 P2 预留 schema 占位(总裁 §5.1 + §7.3 裁决优先级 president > coord) # 修订(ARB-016 §18):schema 文件名统一为 .schema.graphql(总裁 §2.17) scalar DateTime enum DataScope { SELF CLASS GRADE SCHOOL SUBJECT ALL } enum ExamStatus { DRAFT PUBLISHED IN_PROGRESS GRADING SCORED ARCHIVED } enum SubmissionStatus { NOT_SUBMITTED SUBMITTED GRADED } type User { id: ID! email: String! name: String! roles: [String!]! dataScope: DataScope! } type ViewportItem { key: String! label: String! route: String! icon: String sortOrder: String! requiredPermission: String } type Class { id: ID! name: String! gradeId: String! studentCount: Int! } type DashboardStats { totalExams: Int! pendingGrading: Int! todayHomework: Int! } type DashboardData { user: User! classes: [Class!]! viewports: [ViewportItem!]! stats: DashboardStats! } # ============ Query(P2 仅读,无 Mutation) ============ type Query { # 仪表盘聚合(并行:iam.me + iam.viewports + iam.permissions + iam.classesByTeacher) dashboard: DashboardData! # 视口配置(导航) viewports: [ViewportItem!]! # 当前用户信息 me: User! # 班级列表(按教师 dataScope 过滤,数据来自 iam gRPC,总裁 §3.5) classes: [Class!]! class(id: ID!): Class } # ============ P2 不包含(P3+ 扩展) ============ # - exams / homework / grades Query → P3(core-edu 就绪后) # - classPerformance / studentWeakness / learningTrend → P4(data-ana 就绪后) # - notifications → P5(msg 就绪后) # - 所有 Mutation → P3+ # - Subscription → P6+ 评估 # ============ admin 命名空间(P2 预留 schema 占位,P6 实现) ============ # 总裁 §5.1:admin-portal 复用 teacher-bff,admin 命名空间 P2 预留 schema 占位 # P2 仅声明类型骨架,Resolver 返 null;P6 实现(ARB-021 ISSUE-005) # 详见 ARB-021 §23.4 admin 命名空间 schema 清单 extend type Query { # adminUsers / adminRoles / adminPermissions / adminViewports # adminOrganization / adminClasses / adminTeachers / adminStudents # auditLogs / adminDashboard # (P6 实现,P2 仅占位) } extend type Mutation { # createUser / updateUser / deleteUser / toggleUserStatus # createRole / updateRolePermissions / updateViewport # (P6 实现,P2 仅占位) } ``` ### 1.3 关键裁决 | 裁决点 | 结论 | 依据 | | ----------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | Schema 存放位置 | `packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql` | 总裁裁决 §2.17 SDL-first + 集中管理 | | schema 文件名格式 | `.schema.graphql`(统一格式,对齐 student-bff/parent-bff) | 总裁裁决 §2.17 + ARB-016 §18.3 | | P2 Query 范围 | dashboard / viewports / me / classes / class(5 个) | 仅依赖 iam(P2 就绪),classes 数据从 iam gRPC 获取(总裁 §3.5) | | P2 Mutation 范围 | **无**(P2 纯读) | Mutation 依赖 core-edu(P3),P2 无下游可写 | | DataLoader | dashboard 内 classes 列表用 DataLoader | N+1 防御(ai03 §5.1 第 4 条) | | 复杂度限制 | depth ≤ 7,cost ≤ 1000 | ai03 §5.1 第 5 条 | | admin 命名空间 | **P2 预留** schema 占位(声明 admin Query/Mutation 类型骨架,Resolver 返 null),P6 实现 | 总裁裁决 §5.1 + §7.3(裁决优先级 president > coord,修正原 ARB-001 "P2 不包含") | | DataScope 枚举 | SELF / CLASS / GRADE / SCHOOL / SUBJECT / ALL(SUBJECT 替代 DISTRICT) | coord DataScope 6 级统一 | | 错误响应 | ActionState 信封(success/errors/data) | coord-final-decisions F9 | | 降级模式 | success=true + error=null + data 内 degraded 字段 | 总裁裁决 §3.4 方案 B | > **修订记录**(ARB-016 §18,2026-07-10): > > 1. admin 命名空间由 "P2 不包含" 修正为 "P2 预留 schema 占位"(总裁 §5.1 + §7.3 优先级 president > coord) > 2. schema 文件名由 `teacher-bff.graphql` 修正为 `teacher-bff.schema.graphql`(统一 `.schema.graphql` 格式,总裁 §2.17) > 3. classes 数据来源明确为 iam gRPC(总裁 §3.5,非 core-edu) ### 1.4 ai03 执行项 1. 在 `packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql` 创建 P2 第一版 schema 文件 2. teacher-bff 实现 Yoga GraphQL endpoint(`POST /graphql`) 3. 实现 5 个 Query Resolver(dashboard / viewports / me / classes / class) 4. dashboard Resolver 并行调用 iam(3 RPC)+ iam.classesByTeacher(1 RPC),用 DataLoader 防御 N+1(总裁 §3.5:classes 数据从 iam gRPC 获取) 5. 实现 ActionState 信封 + 降级模式(方案 B) 6. P2 预留 admin 命名空间 schema 占位(声明类型骨架,Resolver 返 null;P6 实现见 ARB-021 §23.4) ### 1.5 ai13 执行项 1. teacher-portal Shell 暴露 `GraphQLProvider`(urql client 单例) 2. 使用 `useGraphQLClient()` 从 packages/hooks 获取 client 3. P2 页面(dashboard / classes)通过 GraphQL query 拉取数据 4. **不调用 REST 端点**(除登录外,P2 起 all-in GraphQL) --- ## §2 ARB-002:MF Shell 暴露清单 ### 2.1 背景 全并行启动前,需仲裁 teacher-portal 作为 MF Shell 暴露哪些模块给 Remote(student/parent/admin),作为 ai13 的实现依据。 数据源:ai13 的 [03-long-term-architecture.md §1.4](../../apps/teacher-portal/docs/03-long-term-architecture.md) 提供了 GraphQL client 单例设计。 ### 2.2 仲裁结论 **P2 第一版 MF Shell 暴露清单**: ```typescript // teacher-portal/next.config.js — NextFederationPlugin exposes exposes: { // 1. AppShell(布局 + 导航 + 认证守卫) './AppShell': './src/components/AppShell.tsx', // 2. GraphQLProvider(urql client 单例,总裁 §2.17 方案 A) './GraphQLProvider': './src/app/providers.tsx', // 3. 共享 hooks './useAuth': './packages/hooks/src/use-auth.ts', './usePermission': './packages/hooks/src/use-permission.ts', './useGraphQLClient': './packages/hooks/src/use-graphql-client.ts', // 4. 共享 UI 组件 './ErrorBoundary': './packages/ui-components/src/error-boundary.tsx', './Loading': './packages/ui-components/src/loading.tsx', './Empty': './packages/ui-components/src/empty.tsx', './RequirePermission': './packages/ui-components/src/require-permission.tsx', } ``` **MF shared(singleton)配置**: ```typescript shared: { react: { singleton: true, requiredVersion: '^18.3.0' }, 'react-dom': { singleton: true, requiredVersion: '^18.3.0' }, urql: { singleton: true, requiredVersion: '^2.2.0' }, graphql: { singleton: true, requiredVersion: '^16.8.0' }, '@edu/ui-tokens': { singleton: true }, '@edu/ui-components': { singleton: true }, '@edu/hooks': { singleton: true }, } ``` ### 2.3 关键裁决 | 裁决点 | 结论 | 依据 | | ------------------- | ---------------------------------------------- | --------------------------- | | Shell 身份 | teacher-portal 是 MF Shell(非 Remote) | 总裁裁决 §2.17 + ai13 §1.3 | | P2 Remote 数量 | **0**(P2 暂无 Remote,仅配置 exposes/shared) | ai13 §1.3 绞杀者模式 step 3 | | P3 首个 Remote | student-portal | ai13 §1.3 step 4 | | GraphQL client 归属 | Shell 暴露 GraphQLProvider,Remote 复用 | 总裁 §2.17 方案 A | | MF shared singleton | react / react-dom / urql / graphql / @edu/* | 避免多实例 + 缓存不一致 | | AppShell 暴露 | 是(Remote 复用布局 + 导航 + 认证守卫) | ai13 §1.3 | | feature flag | `NEXT_PUBLIC_MF_ENABLED=false`(P2 默认关) | ai13 §1.3 回退策略 | | 登录页 | P2 不走 MF(Shell 独占 `/login`) | 登录是认证前提,MF 依赖认证 | ### 2.4 ai13 执行项 1. teacher-portal `next.config.js` 添加 NextFederationPlugin(exposes + shared,**无 remotes**) 2. 创建 `src/app/providers.tsx`(GraphQLProvider 包裹) 3. AppShell 改造:从 REST `/api/v1/teacher/viewports` 切换为 GraphQL query `viewports` 4. P2 页面(dashboard / classes)全部用 GraphQL 5. feature flag `NEXT_PUBLIC_MF_ENABLED=false`(P2 默认单体路由) ### 2.5 ai03 执行项(联动) 1. teacher-bff 暴露 `POST /graphql` endpoint 2. 提供GraphQL playground(仅开发环境) --- ## §3 ARB-003:iam 模块 7 项 ISSUE 仲裁 ### 3.1 背景 ai06 在 [iam_issue.md](./objections/iam_issue.md) §2 提请 7 项异议,涉及文档回写、events.proto 缺失、Topic 命名不一致、DataScope 枚举冲突、iam.proto 未补全、AI 身份署名错误、双入口策略冲突。coord 对照 [iam_contract.md](./contracts/iam_contract.md)(v1.0,已含双入口策略 + 12 RPC + REST 端点清单)逐条仲裁。 ### 3.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | 001 | 01/02 文档未回写 I1-I8 裁决 | ✅ 支持 ai06 方案:3 个工作日内回写 01/02,删除全部过渡方案,对齐 contract.md v1.0 | ai06 | | 002 | events.proto 缺 UserEvent/RoleEvent/AuditEvent | ✅ coord 批次 0 补全(见 §6 ARB-006 统一处理) | coord | | 003 | Topic 命名三方不一致(edu.identity.* vs edu.iam.*) | ✅ 统一 `edu.iam.*` 域名 + 聚合 topic 风格 | coord 修 004 + matrix.md | | 004 | DataScope 枚举三方不一致 | ✅ 采用 president §3.2 P2.2 方案:ALL/SCHOOL/GRADE/CLASS/SUBJECT/SELF(SUBJECT 替代 DISTRICT) | coord 修 004 + ai06 修源码 + coord 修 ARB-001 GraphQL schema | | 005 | iam.proto 仅 4 RPC,未补全至 12 RPC | ✅ coord 批次 0 补全(见 §7 ARB-007 统一处理) | coord | | 006 | 01/02 文档 AI 身份署名错误 | ✅ 与 ISSUE-001 一并回写,署名改为 ai06 | ai06 | | 007 | contract.md §1.2 与双入口策略冲突 | ✅ contract.md 已修正为双入口策略(REST + gRPC),ai06 回写 02 文档时对齐 | ai06 | ### 3.3 关键裁决 | 裁决点 | 结论 | 依据 | | ----------------- | --------------------------------------------------------- | -------------------------------------------------------------- | | Topic 域名 | `edu.iam.*`(服务名 iam,非 identity) | G16 规则 `edu...`,domain=服务名 | | Topic 粒度 | 聚合 topic(`edu.iam.user.events` 含多 action) | 与 events.proto ClassEvent 模式一致,减少 topic 数量 | | DataScope 枚举 | ALL/SCHOOL/GRADE/CLASS/SUBJECT/SELF(6 级) | president §3.2 P2.2;SUBJECT 替代 DISTRICT(K12 学科级更实用) | | 双入口策略 | REST `/iam/v1/*` 供 gateway 透传 + gRPC 50052 供 BFF 聚合 | president §2.16 | | iam.proto 补全 | 12 RPC(contract.md §1.1 已定义) | coord-final-decisions §5.1 + president §6 批次 0 | | events.proto 补全 | UserEvent/RoleEvent/AuditEvent + schema_version 字段 | coord-final-decisions §5.1 + president §5.5 | | 004 §7.2 修正 | `edu.identity.*` → `edu.iam.*`,改为聚合 topic 风格 | 与 matrix.md §4 / iam_contract.md §1.4 统一 | ### 3.4 ai06 执行项 1. 回写 iam 01/02 文档(3 个工作日内): - 删除全部过渡方案(P2 仅 REST / 自建 Outbox / PermissionGuard 待改造 / AuthMiddleware P2 不注册 / iam_parent_student_relations / 无 /v1 前缀 / HTTP 调用 iam) - 对齐 contract.md v1.0(12 RPC + 双入口 + REST `/iam/v1/*` + gRPC 50052) - 署名从 ai02 改为 ai06 - 02 文档 §3.1.2 表名改为 `iam_student_guardians`(I6 裁决) - 02 文档 §8.1 决策点 5 改为"P2 即启用 gRPC 50052"(I1 裁决) - 02 文档 §8.1 决策点 4 改为"使用 shared-ts Outbox 工具包"(I2 裁决) - 02 文档 §8.1 决策点 9 改为"P2 即 DB 驱动 + Redis 缓存"(I3 裁决) - 02 文档 §1.1/§1.2/§8.1 决策点 10 改为"P2 即注册 AuthMiddleware"(I4 裁决) - 02 文档 §4.1 REST API 加 `/v1` 前缀(I7 裁决) 2. 修改源码 iam.schema.ts DataScope 枚举:DISTRICT → SUBJECT(ISSUE-004) 3. 实现源码 PermissionGuard DB 驱动 + Redis 缓存(I3 裁决) 4. 实现源码 AuthMiddleware 注册(I4 裁决) 5. 实现源码 RS256 密钥(I5 裁决,本地文件 IAM_PRIVATE_KEY_PATH / IAM_PUBLIC_KEY_PATH) 6. 实现源码 iam_student_guardians 表 + GetChildrenByParent RPC + GET /iam/v1/children(I6 裁决) ### 3.5 coord 执行项 1. 补全 iam.proto 至 12 RPC(ARB-007,批次 0) 2. 补全 events.proto UserEvent/RoleEvent/AuditEvent + schema_version(ARB-006,批次 0) 3. 修正 004 §7.2:`edu.identity.*` → `edu.iam.*`,改为聚合 topic 风格 4. 修正 004 §5.3 表:DataScope 枚举 DISTRICT → SUBJECT;行 505 语义命名与枚举表对齐 5. 修正 ARB-001 GraphQL schema DataScope 枚举:去掉 DISTRICT,加 SUBJECT 6. 修正 matrix.md §4:iam topic 已为 `edu.iam.*`(核查无需改);补 DataScope 枚举说明 --- ## §4 ARB-004:core-edu 模块 7 项 ISSUE 仲裁 ### 4.1 背景 ai08 在 [core-edu_issue.md](./objections/core-edu_issue.md) 提请 7 项异议,涉及 proto 实际状态与仲裁声称不符、events.proto 未同步、状态命名跨模块不一致、class.transferred topic 不一致、RPC 数量统计口径冲突、7 项设计决策未仲裁、01 文档审计待核对项。coord 对照 [core-edu_contract.md](./contracts/core-edu_contract.md)(已更新为 P3 目标态 27 RPC)逐条仲裁。 ### 4.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | | 001 | core_edu.proto 实际状态与仲裁声称不符 | ✅ coord 批次 0 补全至 5 Service 27 RPC(见 §7 ARB-007) | coord | | 002 | events.proto 未同步 topic 命名仲裁 | ✅ coord 批次 0 补全(见 §6 ARB-006:AttendanceEvent + schema_version + edu.teaching.* 注释) | coord | | 003 | 考试/作业状态命名跨模块不一致 | ✅ 采用 ai08 方案 A:统一用 `graded`(去掉 `SCORED`);submissions 统一为 `not_submitted/submitted/graded` | ai08 修源码 + coord 修 ARB-001 GraphQL schema | | 004 | class.transferred 事件 topic 三处不一致 | ✅ 统一为 `edu.teaching.class.transferred` | coord 修 matrix.md + ai08 修文档 | | 005 | RPC 数量统计口径不一致 | ✅ 统一为 P3 全量 27 RPC(ClassService 4 + ExamService 8 + HomeworkService 5 + GradeService 6 + AttendanceService 4) | coord 修 matrix.md + ai08 修文档 | | 006 | 7 项设计决策待仲裁 | ✅ 全部采用 ai08 倾向方案(见 §4.4) | ai08 | | 007 | 01 文档审计表"待核对"项 | ✅ 3 项纳入 P3 验收硬性标准 | ai08 | ### 4.3 关键裁决 | 裁决点 | 结论 | 依据 | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | proto 补全范围 | 5 Service 27 RPC(含 ClassService + AttendanceService + P3 新增 5 RPC + Exam/Homework/Grade message 补字段 + SubmitHomeworkRequest 补 answers) | ISSUE-001 建议 | | Topic 命名 | 统一 `edu.teaching..`(含 class.transferred) | coord-cross-review §3.1 | | 聚合 topic | core-edu 采用具体动作 topic(`edu.teaching.exam.created` 等独立 topic,非聚合) | 与 iam 聚合 topic 不同:core-edu 事件量大,独立 topic 利于分区与消费隔离 | | ExamStatus | draft/published/in_progress/grading/graded/archived/cancelled(小写) | 统一为 graded,去掉 SCORED | | SubmissionStatus | not_submitted/submitted/graded(exam + homework 一致) | 统一初始状态为 not_submitted | | GraphQL 枚举映射 | DRAFT/PUBLISHED/IN_PROGRESS/GRADING/GRADED/ARCHIVED/CANCELLED;NOT_SUBMITTED/SUBMITTED/GRADED | 大写映射,去掉 SCORED | | RPC 统计口径 | 27 RPC(P3 全量) | ClassService 4 + ExamService 8 + HomeworkService 5 + GradeService 6 + AttendanceService 4 | > **注**:core-edu topic 策略采用"具体动作 topic"(`edu.teaching.exam.created` 等),与 iam/content 的"聚合 topic"(`edu.iam.user.events` / `edu.content.knowledge_point.events`)不同。原因:core-edu 事件量大(12 个事件类型),独立 topic 利于 Kafka 分区与消费者隔离;iam/content 事件量小,聚合 topic 减少元数据压力。此为 coord 裁决的策略差异,非矛盾。 ### 4.4 ISSUE-006 七项设计决策仲裁 | # | 决策点 | 仲裁结论 | ai08 倾向 | | --- | ------------------- | -------------------------------------------------- | --------- | | 1 | classes 合并时机 | ✅ (a) P3 初期合并 | (a) | | 2 | room_id | ✅ (b) 仅预留字段 | (b) | | 3 | scope 优先级 | ✅ (a) class > subject > school | (a) | | 4 | grace_period | ✅ (b) 300 秒(schema 默认值改为 `.default(300)`) | (b) | | 5 | schema 校验 | ✅ (b) 仅文档约束(P3 不强制) | (b) | | 6 | exam.submitted 事件 | ✅ (b) 仅含 submission_id | (b) | | 7 | archived 考试 | ✅ (b) P3 仅软删除 | (b) | ### 4.5 ai08 执行项 1. 修改 core-edu 01/02 文档: - 01 §L48 补"ClassService 也缺失" - 02 §4.2 对齐 27 RPC(补 ClassService 4 + AttendanceService 4 + P3 新增 5 RPC + message 字段) - 02 §5.1 TOPIC_MAP 对齐 `edu.teaching.*` 命名(具体动作 topic) - 02 §13.3 七项决策按 §4.4 仲裁结论更新(决策 #4 schema `.default(300)`) - class.transferred topic 统一为 `edu.teaching.class.transferred` 2. 修改源码 status 字段值:exam `graded`(非 `scored`);submissions 统一 `not_submitted` 3. P3 实施时补齐 Dockerfile 多阶段 / ActionState traceId / 权限装饰器覆盖(ISSUE-007 验收标准) ### 4.6 coord 执行项 1. 补全 core_edu.proto 至 5 Service 27 RPC(ARB-007,批次 0) 2. 补全 events.proto AttendanceEvent + schema_version + edu.teaching.* 注释(ARB-006,批次 0) 3. 修正 coord-cross-review.md L312:"✅ 已补全" → "⏳ 待 coord 补全(ARB-007)" 4. 修正 matrix.md §2:core-edu 22 RPC → 27 RPC 5. 修正 matrix.md §4:class.transferred topic 统一为 `edu.teaching.class.transferred` 6. 修正 ARB-001 GraphQL schema:ExamStatus 去掉 SCORED 加 CANCELLED;SubmissionStatus 去掉 IN_PROGRESS(如有)确认 NOT_SUBMITTED/SUBMITTED/GRADED 7. 修正 core-edu_contract.md §2.2:UserEvent topic 从 `edu.identity.user.*` 改为 `edu.iam.user.events`(与 iam ISSUE-003 仲裁一致,聚合 topic 风格) --- ## §5 ARB-005:content 模块 10 项 ISSUE 仲裁 ### 5.1 背景 ai09 在 [content_issue.md](./objections/content_issue.md) 提请 10 项异议,涉及 REST 端点设计不一致、事件 topic 命名策略冲突、Textbook/Chapter 事件遗漏、RPC 数量三方不一致、core-edu 失效事件无定义、文档 push main 冲突、created_by 迁移风险、缓存/API 版本化缺失、schema 字段缺失、Sync Worker 链路。coord 对照 [content_contract.md](./contracts/content_contract.md)(v1.1,已更新为 21 RPC + 4 聚合 topic)逐条仲裁。 ### 5.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | | 001 | REST 端点设计与实现不一致 | ✅ P4 重构时统一为 query 参数风格 + 补 DELETE prerequisite 端点;允许 API 路径变更(BFF 走 GraphQL 解耦) | ai09 | | 002 | 事件 topic 命名策略冲突 | ✅ 采用聚合 topic + action 字段策略(4 聚合 topic) | ai09 修文档 + coord 补 events.proto | | 003 | Textbook/Chapter 事件遗漏 | ✅ 补登记 edu.content.textbook.events + chapter.events | ai09 已在 contract.md 补 + coord 同步 matrix.md | | 004 | gRPC RPC 数量三方不一致 | ✅ 统一为 21 RPC(Textbook 5 + Chapter 5 + KG 4 + Question 7) | ai09 修文档 + coord 修 matrix.md | | 005 | core-edu → content 失效事件 topic 无定义 | ✅ 删除 02 文档 §5.2 该条目;联动改用 gRPC 调用 | ai09 | | 006 | "直接 push main"与项目规则冲突 | ✅ 遵循总裁裁决(trunk-based,直接 push main,post-commit review);措辞优化为"trunk-based development" | ai09 | | 007 | questions.created_by 迁移风险 | ✅ schema 用 `created_by varchar(32) NOT NULL DEFAULT 'system'`(历史数据回填 'system') | ai09 | | 008 | 缓存策略与 API 版本化缺失 | ✅ P4 补缓存策略小节 + API 版本化说明 | ai09 | | 009 | knowledge-points schema 缺字段 | ✅ P4 迁移补齐 difficulty + metadata + created_at + updated_at | ai09 | | 010 | Sync Worker 链路 P4 不必要 | ✅ ES Sync Worker 标 P5;Neo4j Sync Worker 输入仅 Outbox 事件;P4 移除 safeCreateNode 同步写 | ai09 | ### 5.3 关键裁决 | 裁决点 | 结论 | 依据 | | ------------------------ | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | REST 端点风格 | query 参数(`GET /knowledge-points?chapterId=`) | RESTful 规范 + 与 design doc 一致 | | 事件 topic 策略 | 聚合 topic + action 字段(4 topic:textbook/chapter/knowledge_point/question) | 与 matrix.md / events.proto ClassEvent 模式一致;减少 topic 数量 | | RPC 总数 | 21(TextbookService 5 + ChapterService 5 + KnowledgeGraphService 4 + QuestionService 7) | contract.md 为契约唯一源 | | content 与 core-edu 关系 | content 是上游(core-edu 调 content),不消费 core-edu 事件 | ISSUE-005 建议 | | Git 工作流 | trunk-based development(直接 push main + post-commit review) | 总裁裁决覆盖 project_rules §8 分支开发规则 | | created_by 迁移 | `NOT NULL DEFAULT 'system'`(历史数据回填 + 新数据应用层校验) | ISSUE-007 方案二 | | 缓存策略 | Redis 缓存教材树/章节树 + Outbox 事件触发失效 | 读多写少场景 | | API 版本化 | REST `/v1/` 前缀 + gRPC proto package version | 破坏性变更隔离 | | Neo4j 同步 | P4 改为 Outbox 事件驱动异步同步(移除 safeCreateNode 同步写) | 禁止业务事务内同步双写 | ### 5.4 ai09 执行项 1. 修改 content 02 文档: - §4.1 REST 端点改 query 参数风格 + 补 DELETE prerequisite 端点 - §5.1 TOPIC_MAP 改为 4 聚合 topic(textbook/chapter/knowledge_point/question events) - §5.2 删除 core-edu 失效事件条目 - §4.2 gRPC RPC 对齐 21 RPC(补 Textbook Update/Delete + Chapter Update/Delete + Question Publish/Search) - §6 补"缓存策略"小节(Redis + Outbox 失效) - §4 补"API 版本化"说明(REST `/v1/` 前缀) - §1.1 图 ES Sync Worker 标 P5(虚线/灰显);Neo4j Sync Worker 输入仅 Outbox 事件 - 文档末尾措辞优化为"trunk-based development(直接 push main,post-commit review)" 2. 修改源码 schema:questions.created_by `NOT NULL DEFAULT 'system'`;knowledge_points 补 difficulty/metadata/created_at/updated_at 3. P4 任务 T6:重构 knowledge-points.service.ts 移除 safeCreateNode 同步写,改为发 Outbox 事件 ### 5.5 coord 执行项 1. 补全 events.proto TextbookEvent/ChapterEvent/KnowledgePointEvent/QuestionEvent + schema_version(ARB-006,批次 0) 2. 修正 matrix.md §2:content 18 RPC → 21 RPC 3. 修正 matrix.md §4:补登记 edu.content.textbook.events + chapter.events(共 4 聚合 topic) --- ## §6 ARB-006:events.proto 补全(跨 iam/core-edu/content) ### 6.1 背景 iam ISSUE-002、core-edu ISSUE-002、content ISSUE-002/003 共同指向 events.proto 不完整。当前 events.proto 仅定义 4 个 message(ClassEvent/ExamEvent/HomeworkEvent/GradeEvent),缺 iam 的 UserEvent/RoleEvent/AuditEvent、core-edu 的 AttendanceEvent、content 的 TextbookEvent/ChapterEvent/KnowledgePointEvent/QuestionEvent,且所有 message 缺 schema_version 字段,文件头注释仍用旧 topic 命名。 ### 6.2 仲裁结论 coord 在批次 0(P2 启动前)补全 events.proto: | 新增 message | 字段 | 来源 | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | UserEvent | event_id/aggregate_id/event_type/occurred_at/user_id/email/name/roles/action(created/updated/deleted/role_changed)/schema_version/metadata | iam 02 §5.2 + president §5.5 | | RoleEvent | event_id/aggregate_id/event_type/occurred_at/role_id/role_name/permissions/action(created/updated)/schema_version/metadata | iam 02 §5.2 | | AuditEvent | event_id/aggregate_id/event_type/occurred_at/user_id/action(create/update/delete/login/logout/permission_change)/resource_type/resource_id/schema_version/metadata | president §5.5 | | AttendanceEvent | event_id/aggregate_id/event_type/occurred_at/attendance_id/student_id/class_id/schedule_id/status/action(recorded)/schema_version/metadata | core-edu 02 §5.1 | | TextbookEvent | event_id/aggregate_id/event_type/occurred_at/textbook_id/title/subject_id/grade_id/version/action(created/updated/published/archived)/schema_version/metadata | content contract.md §1.4 | | ChapterEvent | event_id/aggregate_id/event_type/occurred_at/chapter_id/textbook_id/title/order/action(created/updated/deleted)/schema_version/metadata | content contract.md §1.4 | | KnowledgePointEvent | event_id/aggregate_id/event_type/occurred_at/kp_id/chapter_id/title/difficulty/action(created/updated/prerequisite_added/prerequisite_removed)/prerequisite_id/schema_version/metadata | content contract.md §1.4 | | QuestionEvent | event_id/aggregate_id/event_type/occurred_at/question_id/kp_id/type/difficulty/status/source/created_by/action(created/updated/published/deleted)/schema_version/metadata | content contract.md §1.4 | **同时**: - 所有现有 message(ClassEvent/ExamEvent/HomeworkEvent/GradeEvent)补 `string schema_version = N;` 字段 - 文件头注释改为 `edu.teaching.*` 命名(core-edu 事件)+ `edu.iam.*` 命名(iam 事件)+ `edu.content.*` 命名(content 事件) ### 6.3 Topic 命名策略(跨模块统一) | 服务 | Topic 策略 | 示例 | 原因 | | -------- | ------------------------ | ------------------------------------------------------------------------- | --------------------------------------- | | iam | 聚合 topic + action 字段 | `edu.iam.user.events`(含 created/updated/deleted/role_changed) | 事件量小,聚合减少 topic 数 | | core-edu | 具体动作 topic | `edu.teaching.exam.created`(每事件独立 topic) | 事件量大,独立 topic 利于分区与消费隔离 | | content | 聚合 topic + action 字段 | `edu.content.knowledge_point.events`(含 created/updated/prerequisite_*) | 事件量中等,聚合减少 topic 数 | | msg | 具体动作 topic | `edu.notify.notification.created` | 通知事件量大,独立 topic | > coord 裁决:允许跨服务采用不同 topic 粒度策略(聚合 vs 具体动作),以服务特征为准。所有 topic 命名统一遵循 `edu...` 或 `edu...events` 格式。 --- ## §7 ARB-007:proto 契约补全汇总(iam.proto + core_edu.proto) ### 7.1 背景 iam ISSUE-005 和 core-edu ISSUE-001 共同指向 proto 契约未补全。coord 作为 shared-proto 维护者,在批次 0 统一补全。 ### 7.2 iam.proto 补全(12 RPC) | Service | RPC | 请求 | 响应 | | ---------- | ----------------------- | ------------------------------ | ---------------------------- | | IamService | Register | RegisterRequest | AuthResponse | | IamService | Login | LoginRequest | AuthResponse | | IamService | RefreshToken | RefreshTokenRequest | TokenPair | | IamService | Logout | LogoutRequest | LogoutResponse | | IamService | GetUserInfo | GetUserInfoRequest | UserInfo | | IamService | BatchGetUsers | BatchGetUsersRequest | BatchGetUsersResponse | | IamService | GetEffectivePermissions | GetEffectivePermissionsRequest | EffectivePermissionsResponse | | IamService | GetEffectiveAccess | GetEffectiveAccessRequest | EffectiveAccessResponse | | IamService | GetEffectiveDataScope | GetEffectiveDataScopeRequest | DataScopeResponse | | IamService | GetViewports | GetViewportsRequest | ViewportsResponse | | IamService | GetPublicKey | GetPublicKeyRequest | PublicKeyResponse | | IamService | GetChildrenByParent | GetChildrenByParentRequest | ChildrenResponse | > 对齐 iam_contract.md §1.1 的 12 RPC 清单。新增 8 RPC(Logout/BatchGetUsers/GetEffectivePermissions/GetEffectiveAccess/GetEffectiveDataScope/GetViewports/GetPublicKey/GetChildrenByParent)。 ### 7.3 core_edu.proto 补全(5 Service 27 RPC) | Service | RPC | 状态 | | ----------------- | -------------------------------------------------------------------------------------------------------------------- | --------------- | | ClassService | GetClass / GetClassesByTeacher / BatchGetClasses / ListStudentsByClass | 新增 4 RPC | | ExamService | CreateExam / GetExam / ListExamsByClass / UpdateExam / DeleteExam / **PublishExam** / **SubmitExam** / **GradeExam** | 已有 5 + 新增 3 | | HomeworkService | AssignHomework / GetHomework / ListHomeworkByClass / SubmitHomework / **GradeHomework** | 已有 4 + 新增 1 | | GradeService | RecordGrade / GetGrade / ListGradesByStudent / ListGradesByExam / ListGradesByHomework / **UpdateGrade** | 已有 5 + 新增 1 | | AttendanceService | **RecordAttendance** / **GetAttendance** / **ListAttendanceByStudent** / **ListAttendanceByClass** | 新增 4 RPC | **同时补全 message 字段**: - Exam:补 subject_id / school_id / status_changed_at / status_changed_by / archived_at - Homework:补 subject_id / grace_period / school_id - Grade:补 total_score / school_id / idempotency_key - SubmitHomeworkRequest:补 answers 字段 > 对齐 core-edu_contract.md §1.1 的 27 RPC 清单。 ### 7.4 coord 执行项 1. 补全 iam.proto 至 12 RPC(含全部 message 定义) 2. 补全 core_edu.proto 至 5 Service 27 RPC(含 ClassService + AttendanceService + P3 新增 5 RPC + message 字段补全) 3. 补全 events.proto(ARB-006,7 个新 message + schema_version + 注释更新) 4. 运行 `buf lint` + `buf breaking` 确保零错误 5. 运行 `buf generate` 产出 TS gRPC 代码 6. 修正 coord-cross-review.md L312 状态 7. 更新 matrix.md §2 RPC 统计 --- ## §10 ARB-008:msg 模块 15 项 ISSUE 仲裁 ### 10.1 背景 ai10 在 [msg_issue.md](./objections/msg_issue.md) 提请 15 项异议(ISSUE-001~~005 已有仲裁核查 + ISSUE-006~~015 新发现),涉及 events.proto 字段缺失、proto 包名规则冲突、Kafka topic 三套约定、RPC 数量超预算、权限点不一致、降级方向矛盾、DLQ/幂等防线缺失、events.proto 缺 message、RPC 清单不一致、Kafka 发布事件不一致。 ### 10.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------ | | 001~005 | 已有仲裁核查 | ✅ 核查通过(001/002/003);004 待 coord 同步 events.proto 注释(ARB-006 已覆盖);005 待 coord 修正 004 §4.1 PushGW 方向 | coord | | 006 | events.proto GradeEvent 缺 class_id + 全部事件缺 student_ids[] | ✅ coord 补全:GradeEvent 补 class_id;Exam/Homework/GradeEvent 补 student_ids[](fan-out 广播用) | coord | | 007 | proto 包名规则冲突(project_rules §5 vs 实际) | ✅ 统一为 `next_edu_cloud..v1`(与实际 proto 一致);coord 更新 project_rules §5(见 §13 ARB-011) | coord | | 008 | Kafka topic 命名三套约定并存 | ✅ 统一裁决(见 §15 ARB-013):msg 采用具体动作 topic(`edu.notify.notification.sent` 等,与 core-edu 策略一致) | coord | | 009 | RPC 数量超预算(17 vs 13) | ✅ 采用方案 A:维持 13 RPC 预算,裁剪 4 RPC(BatchSendNotification/GetUnreadCount/BatchMarkAsRead/MarkAllAsRead 降级为 REST only) | ai10 | | 010 | markAsRead 权限点不一致 | ✅ 以 02 文档 §6.1 为准:`MSG_NOTIFICATION_READ`(非 MANAGE) | ai10 | | 011 | DB→ES 降级方向与 ai-allocation 相反 | ✅ 采用双向降级:ES 故障→DB LIKE;DB 故障→ES 只读(仅读操作可降级,写操作必须等 DB 恢复) | ai10 | | 012 | 缺 DLQ 与三层幂等防线 | ✅ 非阻塞,ai10 自行补充设计文档(§3.1 补 msg_idempotency 表 + §5.5 三层幂等 + §5 DLQ 设计) | ai10 | | 013 | events.proto 缺 4 类 message | ✅ coord 补全(见 §13 ARB-011:MasteryEvent/NotificationEvent + UserEvent/RoleEvent 已在 ARB-006 覆盖) | coord | | 014 | msg_contract.md 与 02 文档 RPC 清单不一致 | ✅ 待 ISSUE-009 仲裁后统一为 13 RPC,两文档对齐 | ai10 | | 015 | Kafka 发布事件不一致 | ✅ 待 ISSUE-008 仲裁后统一(见 §15 ARB-013) | ai10 + coord | ### 10.3 关键裁决 | 裁决点 | 结论 | 依据 | | ---------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------- | | msg RPC 总数 | 13(NotificationService 5 + PreferenceService 4 + TemplateService 4) | 维持 ai-allocation 预算;裁剪 4 RPC 降级 REST | | Kafka topic 策略 | 具体动作 topic(`edu.notify.notification.sent` / `.read` / `.recalled` / `.failed`) | 与 core-edu 策略一致;事件量大,独立 topic 利于消费隔离 | | markAsRead 权限 | `MSG_NOTIFICATION_READ` | 02 文档为准 | | 降级策略 | 双向(ES 故障→DB LIKE;DB 故障→ES 只读) | ai-allocation §5 + 02 文档双向覆盖 | | 三层幂等 | L1 Redis SETNX + L2 msg_idempotency 表 + L3 notifications.source_event_id 唯一索引 | known-issues 已记录 | | DLQ | 重试 3 次后投递 `edu.notify.dlq` + 告警 | known-issues 已记录 | | proto package | `next_edu_cloud.msg.v1`(保留现状) | 见 §13 ARB-011 | ### 10.4 ai10 执行项 1. 修改 msg 02 文档: - §4.2 RPC 裁剪至 13(移除 BatchSendNotification/GetUnreadCount/BatchMarkAsRead/MarkAllAsRead,降级 REST only) - §5.2 Kafka topic 改为具体动作 topic(`edu.notify.notification.sent` 等 4 个 per-event topic) - §3.1 补 msg_idempotency 表 schema - §5.5 改为三层幂等防线 - §5 补 DLQ 设计(`edu.notify.dlq` + 重试 3 次 + 告警) - §3.2.2/§3.4 补双向降级策略(DB 故障→ES 只读) - §6.1 markAsRead 权限改为 `MSG_NOTIFICATION_READ` 2. 修改源码 notifications.controller.ts markAsRead 权限点 3. msg_contract.md §1.1 RPC 清单对齐 13 RPC + §1.4 topic 对齐具体动作 topic ### 10.5 coord 执行项 1. 补全 events.proto(ARB-011:NotificationEvent + MasteryEvent + GradeEvent 补 class_id + 全部事件补 student_ids[]) 2. 修正 004 §4.1 PushGW 方向表述为"Msg → push-gateway (gRPC)" 3. 修正 matrix.md §4:msg topic 改为 `edu.notify.notification.*` 具体动作 topic --- ## §11 ARB-009:data-ana 模块 6 项 ISSUE 仲裁 ### 11.1 背景 ai11 在 [data-ana_issue.md](./objections/data-ana_issue.md) 提请 6 项异议,涉及 iam.proto 缺 GetEffectiveDataScope、events.proto 缺 AIUsageEvent、analytics.proto 未补全至 12 RPC、004 章节引用断裂、MasteryEvent topic 不一致、coord-cross-review §8.2 声明与实际不符。 ### 11.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------- | | 001 | iam.proto 缺 GetEffectiveDataScope RPC | ✅ coord 批次 0 补全 iam.proto 12 RPC(ARB-007 已覆盖,含 GetEffectiveDataScope) | coord | | 002 | events.proto 缺 AIUsageEvent message | ✅ coord 补全(见 §13 ARB-011) | coord | | 003 | analytics.proto 仅 3 RPC,声称 12 RPC 未落实 | ✅ coord 批次 0 补全 analytics.proto 至 12 RPC(见 §14 ARB-012) | coord | | 004 | 004 章节引用断裂(coord 整改 #7/#8/#9/#10 未落实) | ✅ coord 补全 004 §7.2/§1.2/§4.1/§12.2 对应章节 | coord | | 005 | MasteryEvent topic 命名三处不一致 | ✅ 统一为 `edu.insight.mastery.updated` + `edu.insight.warning.triggered`(domain=insight 智能洞察领域) | coord 修 matrix.md + ai11 已对齐 | | 006 | coord-cross-review §8.2 声明与实际不符 | ✅ coord 更正 §8.2 状态为"待执行",明确补全时间点 | coord | ### 11.3 关键裁决 | 裁决点 | 结论 | 依据 | | ------------------ | --------------------------------------------------------------- | --------------------------------------------------------------------- | | analytics.proto | 12 RPC(4 端 Dashboard + Warning + Mastery + Server Streaming) | 02 文档 §4.2 已设计,coord 补全 proto | | MasteryEvent topic | `edu.insight.mastery.updated` | 004 §7.2 命名规范 `edu...`,domain=insight | | WarningEvent topic | `edu.insight.warning.triggered` | 同上 | | 004 章节补全 | coord 补全 §7.2/§1.2/§4.1/§12.2 对应段落 | coord-cross-review §6 整改 #7/#8/#9/#10 | | §8.2 声明更正 | "✅ 已完成" → "⏳ 待 coord 补全(ARB-007/012)" | 实际 proto 未补全 | | Python Outbox 豁免 | ✅ 确认(MasteryUpdated/WarningTriggered 派生数据豁免) | coord-cross-review §3.3 | ### 11.4 ai11 执行项 1. data-ana 01/02 文档:将 004 §4.2/§11.4/§11.5/§15.3 引用从 coord-cross-review.md 回切到 004 对应章节(待 coord 补全后) 2. contract.md §1.4 topic 已对齐 `edu.insight.*`(核查通过) ### 11.5 coord 执行项 1. 补全 analytics.proto 至 12 RPC(ARB-012,批次 0) 2. 补全 events.proto AIUsageEvent + MasteryEvent(ARB-011,批次 0) 3. 补全 iam.proto GetEffectiveDataScope(ARB-007 已覆盖) 4. 补全 004 §7.2(补登 6 个 topic + CDC 命名规范)/§1.2(端口列)/§4.1(gRPC 启用阶段矩阵)/§12.2(派生数据事件 Outbox 豁免条款) 5. 更正 coord-cross-review.md §8.2 状态 6. 修正 matrix.md §4:data-ana topic 改为 `edu.insight.*` --- ## §12 ARB-010:ai 模块 9 项 ISSUE 仲裁 ### 12.1 背景 ai12 在 [ai_issue.md](./objections/ai_issue.md) 提请 9 项异议,涉及 matrix.md 端口不同步、ai 用量事件 topic 三义、ai.proto 待补全、events.proto 缺 AIUsageEvent、contract 与设计文档矛盾、Temporal 决策点、iam GetEffectiveDataScope、proto package 命名、ActionState 整改。 ### 12.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | | 01 | matrix.md 端口 50057 vs 50058 不同步 | ✅ 统一为 50058(port-allocation.md §7 为准);coord 修 matrix.md | coord | | 02 | ai 用量事件 topic 三义未决 | ✅ 统一为 `edu.ai.usage`(见 §15 ARB-013) | coord | | 03 | ai.proto 待补全 | ✅ P5 目标 6 RPC(Chat/StreamChat/GenerateQuestion/StreamGenerateQuestion/OptimizeExpression/GenerateLessonPlan);备课状态查询/确认用 HTTP 端点(见 §14 ARB-012) | coord 补 proto | | 04 | events.proto 缺 AIUsageEvent | ✅ coord 补全(见 §13 ARB-011) | coord | | 05 | contract 与设计文档矛盾 | ✅ ai12 自纠重写 contract(端口 50058 / 补 HTTP 端点 / topic 待 §15 裁决后填 / 错误码对齐 02 §6.2 / 删除消费事件) | ai12 | | 06 | 备课工作流 Temporal(P6 决策点) | ✅ P5 用 BackgroundTasks + Redis;P6 由 coord 评估 Temporal 引入(roadmap 标注 P6 决策点) | ai12 P5 + coord P6 | | 07 | iam GetEffectiveDataScope 待 P4 补全 | ✅ coord 批次 0 补全 iam.proto 12 RPC(ARB-007 已覆盖) | coord | | 08 | proto package 命名不符合 project_rules §5 | ✅ 统一为 `next_edu_cloud..v1`(见 §13 ARB-011) | coord | | 09 | 响应信封偏离 ActionState | ✅ P5 实施时整改:所有返回值改为 ActionState;degraded 移至 `error.details.degraded` | ai12 | ### 12.3 关键裁决 | 裁决点 | 结论 | 依据 | | ------------- | --------------------------------------------- | ----------------------------------------- | | ai gRPC 端口 | 50058 | port-allocation.md §7 为准 | | ai RPC 总数 | 6(P5 目标) | 避免 RPC 膨胀;备课状态查询/确认用 HTTP | | ai 用量 topic | `edu.ai.usage` | 最简短,符合 `edu..` 约定 | | proto package | `next_edu_cloud.ai.v1`(保留现状) | 见 §13 ARB-011 | | Temporal | P5 不引入(BackgroundTasks + Redis);P6 评估 | 避免过早引入复杂度 | | ActionState | P5 强制整改(degraded 移至 error.details) | 004 §11.5 | ### 12.4 ai12 执行项 1. 重写 ai_contract.md 对齐设计文档(端口 50058 / 补 HTTP 端点 / topic `edu.ai.usage` / 错误码对齐 02 §6.2 / 删除消费事件或标注 P6+) 2. P5 实施时整改 ActionState(main.py 返回值改为 `{success, data, error:{code,message,details,traceId}}`;degraded 移至 `error.details.degraded`) 3. P5 备课工作流用 BackgroundTasks + Redis(02 文档 §2.4 状态机已设计) 4. 修正 01/02 文档引用:004 §7.2/§1.2 引用失实,改引 port-allocation.md + coord 仲裁 ### 12.5 coord 执行项 1. 补全 ai.proto 至 6 RPC(ARB-012,批次 0) 2. 补全 events.proto AIUsageEvent(ARB-011,批次 0) 3. 修正 matrix.md §2/§8:ai gRPC 端口 50057 → 50058 4. 在 roadmap 标注 P6 决策点(Temporal 引入评估) 5. 在 known-issues §2.9 ai 分区记录 ActionState 整改约束 --- ## §13 ARB-011:events.proto 扩展补全 + proto package 命名统一 ### 13.1 背景 msg ISSUE-013、data-ana ISSUE-002、ai ISSUE-04 共同指向 events.proto 还缺 msg/data-ana/ai 相关 message(ARB-006 已覆盖 iam/core-edu/content 的 7 个 message)。msg ISSUE-007 + ai ISSUE-08 共同指向 proto package 命名规则冲突。 ### 13.2 events.proto 扩展补全(在 ARB-006 基础上) | 新增 message | 字段 | 来源 | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | | MasteryEvent | event_id/aggregate_id/event_type/occurred_at/student_id/subject_id/mastery_score/action(updated)/schema_version/metadata | data-ana 02 文档 | | WarningEvent | event_id/aggregate_id/event_type/occurred_at/student_id/warning_type/severity/action(triggered)/schema_version/metadata | data-ana 02 文档 | | NotificationEvent | event_id/aggregate_id/event_type/occurred_at/notification_id/user_id/channel/action(sent/read/recalled/failed)/schema_version/metadata | msg 02 文档 | | AIUsageEvent | event_id/request_id/user_id/school_id/provider/model/operation/prompt_tokens/completion_tokens/total_tokens/latency_ms/success/degraded/action(usage)/schema_version/metadata | ai 02 文档 §3.3 | **同时**: - GradeEvent 补 `class_id` 字段 - ExamEvent/HomeworkEvent/GradeEvent 补 `student_ids[]` 字段(复数,fan-out 广播用) > events.proto 最终包含 15 个 message:ClassEvent/ExamEvent/HomeworkEvent/GradeEvent(原有 4 + 补字段)+ UserEvent/RoleEvent/AuditEvent/AttendanceEvent/TextbookEvent/ChapterEvent/KnowledgePointEvent/QuestionEvent(ARB-006 新增 8)+ MasteryEvent/WarningEvent/NotificationEvent/AIUsageEvent(本节新增 4)= 4+8+4 = 16 个 message(含原有 4)。 ### 13.3 proto package 命名统一 | 裁决点 | 结论 | 依据 | | --------------------- | ------------------------------------------------ | --------------------------------------- | | proto package 命名 | `next_edu_cloud..v1`(保留现状) | 所有 proto 文件已采用此格式,改动成本高 | | project_rules §5 更新 | `edu..v1` → `next_edu_cloud..v1` | 与实际 proto 一致 | ### 13.4 coord 执行项 1. 补全 events.proto 4 个新 message(MasteryEvent/WarningEvent/NotificationEvent/AIUsageEvent) 2. 补全 GradeEvent class_id + 全部事件 student_ids[] 字段 3. 更新 project_rules §5 包名规范为 `next_edu_cloud..v1`(需人类审批,project_rules §15.7 敏感文件) 4. 运行 `buf lint` + `buf breaking` 确保零错误 --- ## §14 ARB-012:analytics.proto + ai.proto 补全 ### 14.1 背景 data-ana ISSUE-003 和 ai ISSUE-03 共同指向 proto 契约未补全。coord 作为 shared-proto 维护者,在批次 0 统一补全。 ### 14.2 analytics.proto 补全(12 RPC) | Service | RPC | 说明 | | ---------------- | ---------------------- | ----------------------------- | | AnalyticsService | GetClassPerformance | 班级表现 | | AnalyticsService | GetStudentWeakness | 学生薄弱点 | | AnalyticsService | GetLearningTrend | 学习趋势 | | AnalyticsService | StreamClassPerformance | Server Streaming 班级实时表现 | | AnalyticsService | GetStudentDashboard | 学生仪表盘 | | AnalyticsService | GetTeacherDashboard | 教师仪表盘 | | AnalyticsService | GetAdminDashboard | 管理员仪表盘 | | AnalyticsService | GetParentDashboard | 家长仪表盘 | | AnalyticsService | TriggerWarning | 触发预警 | | AnalyticsService | GetWarnings | 查询预警列表 | | AnalyticsService | UpdateMastery | 更新掌握度 | | AnalyticsService | GetMasteryByStudent | 查询学生掌握度 | > 对齐 data-ana 02 文档 §4.2 的 12 RPC 清单(含 1 Server Streaming)。 ### 14.3 ai.proto 补全(6 RPC) | Service | RPC | 说明 | | --------- | ---------------------- | ------------ | | AiService | Chat | 单轮对话 | | AiService | StreamChat | 流式对话 | | AiService | GenerateQuestion | 生成题目 | | AiService | StreamGenerateQuestion | 流式生成题目 | | AiService | OptimizeExpression | 优化表达 | | AiService | GenerateLessonPlan | 生成教案 | **同时扩展 message 字段**: - GenerateQuestionRequest:补 grade / knowledge_point_ids / question_type / count - ChatRequest:补 user_id / session_id / data_scope(可选) **备课工作流状态查询/确认用 HTTP 端点**(非 gRPC): - `GET /ai/v1/lesson/preparation/{id}`:查询备课状态 - `POST /ai/v1/lesson/preparation/{id}/confirm`:确认入库 ### 14.4 coord 执行项 1. 补全 analytics.proto 至 12 RPC(含 Server Streaming) 2. 补全 ai.proto 至 6 RPC + message 字段扩展 3. 运行 `buf lint` + `buf breaking` 确保零错误 4. 运行 `buf generate` 产出 TS/Go/Python gRPC 代码 --- ## §15 ARB-013:Kafka topic 命名统一裁决(跨全模块) ### 15.1 背景 msg ISSUE-008/015、data-ana ISSUE-005、ai ISSUE-02 共同指向 Kafka topic 命名跨模块不一致。需 coord 统一裁定。 ### 15.2 仲裁结论 **统一命名规则**:`edu...` 或 `edu...events` **Topic 粒度策略**(按服务特征区分,coord 裁决允许差异): | 服务 | Topic 策略 | Topic 清单 | 原因 | | -------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | iam | 聚合 topic + action 字段 | `edu.iam.user.events` / `edu.iam.role.events` / `edu.iam.audit.created` | 事件量小,聚合减少 topic 数 | | core-edu | 具体动作 topic | `edu.teaching.exam.created` / `.updated` / `.deleted` / `.published` / `.submitted` / `edu.teaching.homework.assigned` / `.submitted` / `.graded` / `edu.teaching.grade.recorded` / `.updated` / `edu.teaching.attendance.recorded` / `edu.teaching.class.transferred` | 事件量大,独立 topic 利于分区 | | content | 聚合 topic + action 字段 | `edu.content.textbook.events` / `edu.content.chapter.events` / `edu.content.knowledge_point.events` / `edu.content.question.events` | 事件量中等,聚合减少 topic 数 | | msg | 具体动作 topic | `edu.notify.notification.sent` / `.read` / `.recalled` / `.failed` | 通知事件量大,独立 topic | | data-ana | 具体动作 topic | `edu.insight.mastery.updated` / `edu.insight.warning.triggered` | 派生数据事件(Outbox 豁免) | | ai | 具体动作 topic | `edu.ai.usage` | 派生数据事件(Outbox 豁免) | ### 15.3 域名映射 | 服务 | domain | 依据 | | -------- | ---------- | --------------------------------- | | iam | `iam` | 服务名 | | core-edu | `teaching` | 教学领域(非服务名 core_edu) | | content | `content` | 内容领域 | | msg | `notify` | 通知领域(非服务名 msg) | | data-ana | `insight` | 智能洞察领域(非服务名 data_ana) | | ai | `ai` | AI 领域 | ### 15.4 matrix.md §4 同步更新 coord 修正 matrix.md §4 Kafka 事件矩阵,全部 topic 对齐上述清单。 ### 15.5 各 AI 执行项 各 AI 检查自身 02 文档 TOPIC_MAP + contract.md §1.4,对齐本仲裁的 topic 命名。具体差异见各模块 ARB 章节。 --- ## §16 ARB-014:api-gateway 模块 4 项内联 ISSUE 仲裁 ### 16.1 背景 ai01 的 [api-gateway_issue.md](./objections/api-gateway_issue.md) 文件仅含标题未填写实质内容(文件截断,仅 2 行),但其 [api-gateway_contract.md](./contracts/api-gateway_contract.md) v2 内联了 4 项待仲裁 ISSUE(§1.2.2 注 3 + §2.4 + §3.1)。coord 提取 contract.md 中的内联 ISSUE 逐条仲裁。 ### 16.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------- | | 001 | JWKS 拉取方式(gRPC vs HTTP) | ✅ 已确认 HTTP JWKS(contract v2 §2.3 已执行:`GET /.well-known/jwks.json`,TTL 5min 缓存) | ai01(已完成) | | 002 | shared-go 包接入 | ✅ shared-go 包骨架已完成(contract §3.1 显示 ✅);ai01 直接 import `packages/shared-go` 的 jwks/logger/tracer/env 4 模块 | ai01(已就绪) | | 003 | API 版本化路由方案(双 /v1 前缀) | ✅ 采纳方案 A:前端调用 `/api/v1//v1/*`(双 /v1 前缀,Gateway 纯透传无路径重写) | ai01 | | 004 | zap vs slog 日志库选型 | ✅ 遵循 project_rules §12 使用 **zap**(project_rules 明确规定 Go 日志用 zap) | ai01 | ### 16.3 关键裁决 | 裁决点 | 结论 | 依据 | | ----------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | JWKS 拉取 | HTTP `GET /.well-known/jwks.json`(非 gRPC) | president §2.16 + contract v2 §2.3 | | Gateway gRPC 消费 | **无**(Gateway 不消费任何 gRPC,纯 HTTP 透传) | president §2.16 + B3 裁决(权限由下游 Controller 自校验) | | API 版本化 | 方案 A:`/api/v1//v1/*` 双前缀,Gateway 不做路径重写 | 纯透传最简,避免路径重写 bug;`/api/v1` 是 Gateway API 前缀,`//v1` 是服务内部 API 前缀 | | Go 日志库 | zap(对齐 project_rules §12) | project_rules 强制规定;Go 1.22 slog 为备选,需 project_rules 变更后评估 | | matrix.md §2 修正 | 移除 api-gateway 为 iam gRPC 消费方(contract §2.1 勘误已指出) | Gateway 不消费 gRPC | ### 16.4 ISSUE-003 方案 A 路径规范 | 层级 | 路径格式 | 示例 | | ------------ | ----------------------------------------------------- | -------------------------------------- | | 前端调用 | `/api/v1//v1/` | `/api/v1/iam/v1/register` | | Gateway 透传 | 原样转发到 `://v1/` | iam:3002`/iam/v1/register` | | 服务内部路由 | `//v1/` | iam Controller 注册 `/iam/v1/register` | > **双 /v1 语义**:外层 `/api/v1` 是 Gateway 层 API 版本(全局),内层 `/v1` 是服务内部 API 版本(独立演进)。此设计允许 Gateway 和服务各自独立版本化。 ### 16.5 ai01 执行项 1. P2.7 任务统一迁移路由至 `/api/v1//v1/*` 双前缀格式(当前 P1 代码为 `/api/v1//*` 单前缀) 2. 使用 zap 日志库(import `packages/shared-go/logger`) 3. ISSUE-001/002 已落地,无需额外动作 4. 补充 issue.md 文件内容(当前为空,后续如有新问题需按格式追加) ### 16.6 coord 执行项 1. 修正 matrix.md §2 gRPC 接口提供方矩阵:移除 api-gateway 为 iam gRPC 消费方 2. 确认 shared-go 4 模块骨架已就绪(contract §3.1 已标 ✅) --- ## §17 ARB-015:push-gateway 模块 7 项 ISSUE 仲裁 ### 17.1 背景 ai02 在 [push-gateway_issue.md](./objections/push-gateway_issue.md) 提请 7 项异议,涉及 SSE 端点冲突、内部 API 鉴权命名、容量目标、端点路径、审计表设计、Redis /readyz 冲突、02 文档缺 ADR/NFR。coord 对照 [push-gateway_contract.md](./contracts/push-gateway_contract.md) v2 逐条仲裁。 ### 17.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | 001 | SSE 端点三方冲突 | ✅ 采纳 ai02 建议:**不支持 SSE,仅 WebSocket**。移除 contract.md §1.2 的 `/sse` 端点 + matrix.md §5 SSE 行 | coord 修 contract + matrix + ai02 确认 | | 002 | 内部 API 鉴权命名不一致 | ✅ 统一为 `X-Internal-Token` 头 + `INTERNAL_API_TOKEN` 环境变量(对齐总裁 §7.2) | ai02 改代码 + coord 修 contract | | 003 | 容量目标 50k vs 10w+ | ✅ 统一为 **10w+**(对齐 02 文档 + pending-features 权威) | coord 修 modules/README §7 | | 004 | /internal/send vs /internal/push | ✅ 统一为 `/internal/push`(ai02 已自行修复,contract v2 已对齐) | ai02(已完成) | | 005 | 审计表设计缺失 | ✅ 方案 2:审计由 msg 服务维护(msg 已落库),push-gateway 保持无 DB 定位 | ai10 确认审计字段 + ai02 无需引入 DB | | 006 | ISSUE-058 与 055 Redis /readyz 冲突 | ✅ **Redis 软失败**(仅告警 + `degraded: true` + 返 200,不返 503);从 ISSUE-055 必需依赖列表中移除 push-gateway → Redis | coord 澄清两裁决优先级 | | 007 | 02 文档缺 ADR/NFR/容量/失败模式 | ✅ P5(批次 4)补全 02 文档 §14-§17 四章节(ADR/非功能性需求/失败模式/容量估算) | ai02 | ### 17.3 关键裁决 | 裁决点 | 结论 | 依据 | | ------------- | ----------------------------------------------------- | ---------------------------------------------------------------------- | | SSE 端点 | **不支持**,仅 WebSocket | 单一协议降低维护成本;SSE 单向下行不适合双向协议 | | 内部鉴权 | `X-Internal-Token` + `INTERNAL_API_TOKEN`(共享密钥) | 总裁 §7.2;mTLS P5 成本过高,K8s NetworkPolicy 已隔离 | | 容量目标 | 10w+ 连接/单实例 | pending-features 权威;Go goroutine-per-connection 约 2-3GB/10w 连接 | | 审计表归属 | msg 服务维护(push-gateway 无 DB) | 保持 push-gateway 无 DB 定位,避免引入持久化层 | | Redis /readyz | **软失败**(仅告警不阻塞,返 200 + degraded) | push-gateway 重启不解决 Redis 故障;Redis 故障时单实例仍能服务本地连接 | | Kafka /readyz | 软失败(仅告警 + degraded) | ISSUE-055 裁决 | | 心跳协议 | RFC 6455 控制帧(Ping/Pong,30s 间隔) | 02 文档 §10 | ### 17.4 ISSUE-006 Redis 软失败裁决详情 **冲突**: - ISSUE-055(president §3.3):Redis 列为"必需依赖",失败返 503 - ISSUE-058(president §4.3):Redis /readyz "仅告警不阻塞,避免雪崩" **coord 裁决**:以 ISSUE-058 为准(后裁决优先),Redis 对 push-gateway 为**软失败**。 **理由**: 1. push-gateway 重启不解决 Redis 故障(Redis 是跨实例广播依赖,非本地状态) 2. Redis 故障时单实例仍能服务本地连接(仅跨实例广播失效) 3. 重启会丢失本地连接表,加剧雪崩风险 4. ISSUE-055 的"必需依赖"列表应排除 push-gateway → Redis(Redis 故障不触发 Pod 重启) **修正**:004 §7.2 / coord-cross-review 中 ISSUE-055 必需依赖列表,push-gateway → Redis 标注为"软失败(ISSUE-058 裁决覆盖)"。 ### 17.5 ai02 执行项 1. 修改源码鉴权头:`X-Internal-Key` → `X-Internal-Token`;`INTERNAL_API_KEY` → `INTERNAL_API_TOKEN`(ISSUE-002) 2. 02 文档 §3.1 补 Hub 启动重建机制(SADD + EXPIRE 60s + 清空旧 instanceID 成员,ISSUE-058 回写) 3. 02 文档 §6.7 /readyz Redis 检查改为软失败(返 200 + degraded,不返 503,ISSUE-006) 4. 02 文档 §5.4 添加"设计决策记录:gRPC vs HTTP 协议选型"章节,标注"coord 已采纳 P1"(ISSUE-056 回写) 5. 02 文档 §5.1 topic 已对齐 `edu.notification.requested`(ISSUE-053 回写确认) 6. 02 文档补 §14-§17 四章节(ADR/NFR/失败模式/容量估算,P5 批次 4 补全,ISSUE-007) 7. 02 文档补 `push_gateway_redis_set_rebuild_total` 指标 + 60s 不一致窗口文档说明(ISSUE-058 回写) 8. ISSUE-001/003/004/005 由 coord 修文档,ai02 确认 ### 17.6 coord 执行项 1. 修正 contract.md §1.2:移除 `/sse` 端点(ISSUE-001) 2. 修正 matrix.md §5:移除 push-gateway SSE 行(ISSUE-001) 3. 修正 modules/push-gateway/README.md §7:50k → 10w+(ISSUE-003) 4. 修正 contract.md §1.2:鉴权头统一为 `X-Internal-Token`(ISSUE-002,contract v2 已部分对齐,确认最终) 5. 修正 004 §7.2 / coord-cross-review:ISSUE-055 必需依赖列表中 push-gateway → Redis 标注"软失败" 6. ISSUE-005 协调 ai10 确认 msg 审计表覆盖 push-gateway 推送结果字段 --- ## §18 ARB-016:teacher-bff 模块 3 项 ISSUE 仲裁 ### 18.1 背景 ai03 在 [teacher-bff_issue.md](./objections/teacher-bff_issue.md) 提请 3 项异议,涉及 admin 命名空间 P2 预留与 ARB-001 冲突、dashboard classes 数据来源与调用链冲突、GraphQL schema 文件命名不一致。coord 对照 [teacher-bff_contract.md](./contracts/teacher-bff_contract.md) v2 逐条仲裁。 ### 18.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------- | | 001 | admin 命名空间 P2 预留与 ARB-001 "P2 不包含" 冲突 | ✅ 以总裁裁决为准(president > coord),修正 ARB-001 §1.3 为 "P2 预留 admin schema 命名空间占位" | coord 修 ARB-001 | | 002 | P2 dashboard classes 数据来源与调用链冲突 | ✅ 采纳 president §3.5:P2 classes 数据从 iam gRPC 获取(GetViewports/GetEffectiveAccess),不调 classes 服务 | coord 修 ARB-001 + ai03 修文档 | | 003 | GraphQL schema 文件命名不一致 | ✅ 以总裁 §2.17 为准:统一为 `teacher-bff.schema.graphql` | coord 修 ARB-001 + ai03 创建文件 | ### 18.3 关键裁决 | 裁决点 | 结论 | 依据 | | -------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | | admin 命名空间 P2 | **P2 预留** schema 占位(声明 `admin` Query/Mutation 类型骨架,Resolver 返 null),P6 实现 | president §5.1 + §7.3(裁决优先级 president > coord) | | P2 classes 数据来源 | **iam gRPC**(GetViewports/GetEffectiveAccess 返回关联班级),不调 classes 服务 | president §3.5 + B2 裁决(classes P2 无 gRPC,禁止 REST 过渡) | | P3+ classes 数据来源 | 切换为 `core-edu.ClassService.GetClassesByTeacher` RPC(core-edu gRPC 50053 就绪后) | ARB-007 已补全 ClassService 4 RPC | | schema 文件名 | `teacher-bff.schema.graphql`(统一 `.schema.graphql` 格式) | president §2.17 | | 裁决优先级 | president > coord(ARB-001 修正为对齐总裁裁决) | 总裁裁决覆盖 coord 仲裁 | ### 18.4 ISSUE-002 P2 dashboard 调用链修正 **原 ARB-001 §1.4 第 4 条**: > dashboard Resolver 并行调用 iam(3 RPC)+ classes(1 RPC),用 DataLoader 防御 N+1 **修正为**: > dashboard Resolver 并行调用 iam gRPC(GetUserInfo + GetViewports + GetEffectiveAccess),classes 列表从 iam 返回数据推导,P3 core-edu gRPC 就绪后切换为 `GetClassesByTeacher` RPC **理由**: 1. classes P2 无 gRPC server(classes.proto 注释 "P3 起转 gRPC") 2. B2 裁决禁止 REST 过渡 3. president §3.5 裁决 P2 班级列表数据来自 iam ### 18.5 ai03 执行项 1. 创建 `packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql`(文件名用 `.schema.graphql`,ISSUE-003) 2. schema 中预留 `admin` 命名空间占位(`admin.*` Query/Mutation 类型骨架,Resolver 返 null,ISSUE-001) 3. dashboard Resolver P2 实现:调 iam gRPC 获取 classes 数据(不调 classes 服务,ISSUE-002) 4. P3+ 切换 dashboard classes 数据源为 `core-edu.ClassService.GetClassesByTeacher` ### 18.6 coord 执行项 1. 修正 ARB-001 §1.3:admin 命名空间改为 "P2 预留 schema 占位" 2. 修正 ARB-001 §1.3/§1.4:文件名改为 `teacher-bff.schema.graphql` 3. 修正 ARB-001 §1.4 第 4 条:dashboard classes 数据来源改为 iam gRPC(不调 classes 服务) 4. 修正 ARB-001 §1.2 GraphQL schema 代码块:DataScope 枚举去掉 DISTRICT 改 SUBJECT(ARB-003 ISSUE-004 已裁决,需同步 ARB-001) --- ## §19 ARB-017:student-bff 模块 4 项新 ISSUE 仲裁 ### 19.1 背景 ai04 在 [student-bff_issue.md](./objections/student-bff_issue.md) §1 提请 4 项新异议(STU-001~004),涉及 01 文档与 B1/B2/B5 裁决冲突、02 引用不存在的 004 章节、02 §8.3 八项已裁决决策未更新、GraphQL schema 第一版未起草。coord 对照 [student-bff_contract.md](./contracts/student-bff_contract.md) v2 逐条仲裁。 ### 19.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------ | | STU-001 | 01 文档与 B1/B2/B5 裁决冲突 | ✅ 与 ISSUE-028 合并处理:01 文档随 02 文档一并回写(删除 REST 端点清单、改 GraphQL、错误码改 BFF_STUDENT_) | ai04 | | STU-002 | 02 引用不存在的 004 §11.4/§11.5 | ✅ coord 补全 004 §11.4(错误码前缀矩阵)+ §11.5(ActionState 信封规范)章节 | coord | | STU-003 | 02 §8.3 八项已裁决决策未更新 | ✅ 02 文档回写时删除已裁决项的"待仲裁"标注,改为"已裁决(见 coord-final-decisions §2 BX)" | ai04 | | STU-004 | GraphQL schema 第一版未起草 | ✅ ai04 在批次 1 等待期产出 schema 草案,存放 `packages/shared-ts/contracts/graphql/student-bff.schema.graphql` | ai04 | ### 19.3 关键裁决 | 裁决点 | 结论 | 依据 | | -------------------- | ---------------------------------------------------------- | ------------------------------------------ | | 01 文档回写范围 | 01 + 02 一并回写(01 不作为历史快照保留,必须对齐裁决) | ISSUE-028 + STU-001 合并 | | 004 §11.4/§11.5 补全 | coord 补全错误码前缀矩阵 + ActionState 信封规范章节 | 004 作为架构设计意图唯一源,不应有断裂引用 | | schema 仲裁时机 | ai04 批次 1 等待期起草 → coord 批次 2 启动前仲裁第一版 | president §2.2 | | schema 文件名 | `student-bff.schema.graphql`(统一格式,对齐 teacher-bff) | president §2.17 | | 02 §8.3 已裁决项 | B1/B2/B3/B4/B5/B6/B7/B8 全部已裁决,删除"待仲裁"标注 | coord-final-decisions §2 | ### 19.4 ISSUE-028 回写范围确认 ai04 须在批次 2 启动前完成 02 文档回写(president §3.4 裁决),回写范围: 1. **§4 API 设计**:21 个 REST 端点 → GraphQL Query/Mutation 清单 2. **§9.2 演进路线**:删除"REST→GraphQL 演进"(违反"不分阶段"原则) 3. **§9.3 通信协议演进**:删除"HTTP→gRPC 演进"(违反 B2) 4. **§3.1 下游通信**:"HTTP fetch(当前阶段)" → "gRPC 调用下游(@grpc/grpc-js + @bufbuild/protobuf)" 5. **§3.3/§6 错误码**:`STUDENT_BFF_` → `BFF_STUDENT_` 6. **§8.3 未决决策**:8 项已裁决项标注"已裁决",仅保留 #7/#10/#11/#12 合理设计决策 7. **01 文档**:同步回写(删除 REST 假设、对齐错误码前缀、删除已裁决项重复提请) ### 19.5 ai04 执行项 1. 批次 1 等待期产出 `student-bff.schema.graphql` 草案(ISSUE-STU-004) 2. 批次 2 启动前回写 01 + 02 文档(ISSUE-028 + STU-001/003,范围见 §19.4) 3. 02 文档引用源修正:004 §11.4/§11.5 → coord 补全后引用(或暂引 coord-final-decisions G14/G8) 4. 实现 DownstreamClient 回写 teacher-bff(B8 裁决) ### 19.6 coord 执行项 1. 补全 004 §11.4(错误码前缀矩阵:GW_/IAM_/CORE_EDU_/BFF_TEACHER_/BFF_STUDENT_/BFF_PARENT_/MSG_/PUSH_/DATA_ANA_/AI_)+ §11.5(ActionState 信封规范:`{success, data, error:{code,message,details,traceId}}` + degraded 放 error.details) 2. 批次 2 启动前仲裁 student-bff schema 第一版(president §2.2) --- ## §20 ARB-018:parent-bff 模块 10 项 ISSUE 仲裁 ### 20.1 背景 ai05 在 [parent-bff_issue.md](./objections/parent-bff_issue.md) 提请 10 项异议,涉及 01 文档未同步、ChildGuard TTL 不一致、契约引用错误、004 依赖图未同步、parent-portal REST vs GraphQL 跨模块冲突、proto 包名缺失、Notification.childId 缺失、ClassService 缺失、责任方过时、02 缺 ADR/NFR。coord 对照 [parent-bff_contract.md](./contracts/parent-bff_contract.md) 逐条仲裁。 ### 20.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | | 001 | 01 文档未同步 ai05 接手 + U3/U4/C1 仲裁 | ✅ 01 作为阶段 1 历史快照保留原样,以 02 为准(02 已执行 U3/U4/C1) | ai05 标注 01 为历史快照 | | 002 | 02 文档 ChildGuard TTL 三处不一致(60s/30s) | ✅ 统一为 **30s**(§3.1.1 表格改为 30s,对齐 §9 #2 + §13 #7) | ai05 修文档勘误 | | 003 | contract.md 引用 I3 → 应为 I6 | ✅ 修正为 I6 裁决(coord-final-decisions §1 I6:家长-学生关联) | ai05 修 contract 引用 | | 004 | 004 §4 + matrix.md §1 未同步 C6 仲裁(缺 DataAna + Msg) | ✅ coord 补全 004 §4 服务依赖图 + matrix.md §1 依赖矩阵(加 PBFF → DataAna + PBFF → Msg) | coord | | 005 | parent-portal 01 文档按 REST 消费 parent-bff(跨模块冲突) | ✅ coord 协调 ai15 将 parent-portal 01/02 改为 GraphQL 消费(`POST /api/v1/parent/v1/graphql`) | coord 协调 ai15 | | 006 | proto 包名引用缺 next_edu_cloud 前缀 | ✅ 统一补 `next_edu_cloud.` 前缀(ARB-011 已裁决,ai05 修 02 §3.3 DTO 映射表) | ai05 | | 007 | GraphQL Notification.childId 在 msg.proto 缺失 | ✅ coord 协调 ai10 在 msg.proto Notification message 补 `string child_id = 9;`(可选,非家长通知为空) | coord 协调 ai10 | | 008 | core_edu.proto 缺 ClassService | ✅ coord 已在 ARB-007 补全 ClassService 4 RPC(GetClass/GetClassesByTeacher/BatchGetClasses/ListStudentsByClass);02 §7.1 状态改 "✅ 已有";Grade.score string→Float 转换规则补 §3.3 | ai05 修 02 §7.1 + §3.3 | | 009 | ai-allocation iam 责任方 ai02 → ai06 | ✅ 修正为 ai06(iam 现归属 ai06,ai-allocation §3.2 确认) | ai05 修 01/02 引用 | | 010 | 02 缺 ADR/NFR/容量规划/威胁建模 | ✅ P6 硬化阶段补全(当前不阻塞 P4 实施) | ai05 P6 补全 | ### 20.3 关键裁决 | 裁决点 | 结论 | 依据 | | ------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------- | | 01 文档定位 | 历史快照保留原样,02 为权威源 | 避免回写成本;01 标注"阶段 1 历史快照,以 02 为准" | | ChildGuard TTL | 30s + 主动失效(统一三处) | §9 #2 + §13 #7 已调整,§3.1.1 表格勘误 | | 契约引用 | I6(非 I3),ISSUE-047 编号虚构,删除 | coord-final-decisions §1 I6 | | C6 依赖图同步 | coord 补 004 §4 + matrix.md §1:PBFF → IAM + CoreEdu + DataAna + Msg | C6 仲裁 | | parent-portal 消费方式 | GraphQL(`POST /api/v1/parent/v1/graphql`),非 REST | U3 仲裁 + parent-bff 02 §4.1 不实现 REST | | proto 包名 | `next_edu_cloud..v1`(全引用补前缀) | ARB-011 已裁决 | | msg.proto Notification.child_id | 补 `string child_id = 9;`(可选字段) | ISSUE-007 家长场景需按孩子过滤通知 | | ClassService 归属 | core-edu(ARB-007 已补全 4 RPC) | coord 批次 0 补全 | | Grade.score 类型转换 | BFF response-mapper 做 `Number.parseFloat(score)`,失败抛 BFF_PARENT_BAD_GATEWAY | ai05 建议 | | iam 责任方 | ai06(非 ai02) | ai-allocation §3.2 | ### 20.4 ISSUE-005 跨模块契约冲突处理 **冲突**:parent-portal(ai15)01 文档 §3.1 按 REST 消费 parent-bff,但 parent-bff 02 §4.1 明确"不实现 REST 业务端点"。 **coord 仲裁**:按 project_rules §14.4 跨模块变更顺序处理: 1. parent-bff 契约已定义(GraphQL `POST /api/v1/parent/v1/graphql`) 2. coord 协调 ai15 将 parent-portal 01/02 文档的 parent-bff 消费契约从 REST 改为 GraphQL 3. 同步 C4 仲裁:iam 路径 `/iam/permissions/effective`(非 `/iam/effective-permissions`) 4. parent-portal §3.1 标注 "BFF 对接:parent-bff(ai05 设计)" ### 20.5 ISSUE-007 msg.proto Notification 字段补全 coord 协调 ai10 在 msg.proto Notification message 补字段: ```proto message Notification { string id = 1; string user_id = 2; string type = 3; string title = 4; string content = 5; string channel = 6; bool is_read = 7; int64 created_at = 8; string child_id = 9; // 新增:关联孩子 ID(可选,非家长通知为空) } ``` > parent-bff GraphQL `Notification.childId` 映射自此字段。ai10 在 msg 02 文档同步补字段说明。 ### 20.6 ISSUE-008 ClassService + Grade.score 处理 **ClassService**:coord 已在 ARB-007 补全 core_edu.proto ClassService 4 RPC(GetClass/GetClassesByTeacher/BatchGetClasses/ListStudentsByClass)。parent-bff 02 §7.1 状态从 "❌ 待补" 改为 "✅ 已有"。 **Grade.score 类型转换**:parent-bff 02 §3.3 DTO 映射表补转换规则说明: - `core_edu.v1.Grade.score`(string)→ GraphQL `Grade.score`(Float!) - BFF response-mapper 执行 `Number.parseFloat(score)` - 转换失败(NaN)抛 `BFF_PARENT_BAD_GATEWAY` + i18n key `error.bffParent.bad_gateway` ### 20.7 ai05 执行项 1. 02 §3.1.1 ChildGuard TTL 改为 30s(ISSUE-002 勘误) 2. 02 §3.3 DTO 映射表补 `next_edu_cloud.` 前缀(ISSUE-006) 3. 02 §3.3 补 Grade.score string→Float 转换规则(ISSUE-008) 4. 02 §7.1 ClassService.GetClass 状态改 "✅ 已有"(ISSUE-008,ARB-007 已补全) 5. contract.md §2.1 引用 I3 → I6 修正(ISSUE-003) 6. 01 §7.1/§7.3 + 02 §7.3 #1 责任方 ai02 → ai06(ISSUE-009) 7. 01 文档头部标注"阶段 1 历史快照,以 02 为准"(ISSUE-001) 8. P6 硬化阶段补 02 ADR/NFR/容量规划/威胁建模(ISSUE-010,非阻塞) ### 20.8 coord 执行项 1. 补全 004 §4 服务依赖图:加 `PBFF --> DataAna` + `PBFF --> Msg`(ISSUE-004,C6 仲裁同步) 2. 补全 matrix.md §1 服务依赖矩阵:加 `PBFF --> DataAna` + `PBFF --> Msg`(ISSUE-004) 3. 协调 ai10 在 msg.proto Notification 补 `child_id = 9` 字段(ISSUE-007) 4. 协调 ai15 将 parent-portal 01/02 改为 GraphQL 消费 parent-bff(ISSUE-005,跨模块变更) 5. 确认 ClassService 已在 ARB-007 补全(ISSUE-008 已覆盖) --- ## §21 ARB-019:student-portal 模块 7 项 ISSUE 仲裁 ### 21.1 背景 ai14 在 [student-portal_issue.md](./objections/student-portal_issue.md) 提请 7 项异议,涉及 GraphQL endpoint 路径、schema 文件存放位置、考试防作弊策略、主观题粘贴策略、附件上传协议、实时事件命名、DataScope L0 强制执行层。coord 对照 [student-portal_contract.md](./contracts/student-portal_contract.md) v2 + [student-bff_contract.md](./contracts/student-bff_contract.md) v2 + ARB-001/ARB-002/ARB-014 逐条仲裁。 ### 21.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ------ | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | | 014-01 | GraphQL endpoint 路径不一致 | ✅ 统一为 `POST /api/v1/student/graphql`(对齐 matrix.md §5 + ARB-014 方案 A 双 /v1 前缀) | ai14 修 contract.md §2.3 路径 + ai01 确认路由 | | 014-02 | student-bff GraphQL schema 存放位置不一致 | ✅ 统一为 `packages/shared-ts/contracts/graphql/student-bff.schema.graphql`(对齐 president §2.17 + ARB-016/017) | ai04 创建并维护 | | 014-03 | 考试作答页全屏策略与防作弊检测边界 | ✅ P3 不强制全屏 + visibilitychange 仅记录 + 多标签警告不阻止 + 走 student-bff GraphQL mutation `recordExamViolation` | ai14 + ai04 | | 014-04 | 主观题粘贴策略(防作弊 vs 学生体验) | ✅ 客观题禁止 + 主观题允许记录 + 作文题允许不记录;复用 recordExamViolation(type=PASTE) | ai14 + ai04 | | 014-05 | 作业附件上传协议 | ✅ 方案 A:api-gateway REST `POST /api/v1/student/upload` → 对象存储 → GraphQL mutation 提交 URL | ai01 路由 + ai04 mutation 接受 attachmentUrls | | 014-06 | 考试延长/题目重排等实时事件命名 | ✅ ai08 发布 ExamExtended + ExamForceSubmitted;题目重排 P3 不实现 P4 评估 | ai08 发布 + ai10 推送 | | 014-07 | 学生端 DataScope L0 边界强制执行层 | ✅ 方案 A:student-bff Resolver 从 JWT x-user-id 提取 studentId,前端 query 不传 studentId | ai14 修 query 设计 + ai04 实现 | ### 21.3 关键裁决 | 裁决点 | 结论 | 依据 | | ---------------- | ------------------------------------------------------------------------- | --------------------------------------------- | | GraphQL endpoint | `POST /api/v1/student/graphql`(双 /v1 前缀,对齐 ARB-014 方案 A) | matrix.md §5 + ARB-014 §16.4 | | schema 文件路径 | `packages/shared-ts/contracts/graphql/student-bff.schema.graphql` | president §2.17 + ARB-017 §19.3 | | 全屏策略 | P3 推荐不强制(提示"建议全屏作答");P4 基于教师反馈评估升级 | 防止误伤合法场景 | | 离开页面策略 | visibilitychange hidden 仅记录,累计 3 次警告教师端可见;不自动提交 | 误触发风险高 | | 多标签检测 | BroadcastChannel 警告 + 记录,不阻止作答 | 合法场景如查词典 | | 防作弊事件上报 | student-bff GraphQL mutation `recordExamViolation(examId, type, payload)` | GraphQL 统一入口;不走 push-gateway | | 粘贴策略分层 | 客观题禁止 / 主观题允许记录 / 作文题允许不记录 | 防作弊与学生体验平衡 | | 附件上传协议 | api-gateway REST + 对象存储 + GraphQL mutation 提交 URL | GraphQL 不适合大文件;REST + 对象存储业界通用 | | 实时事件命名 | ExamExtended + ExamForceSubmitted(ai08 发布到 `edu.exam.events` topic) | 事件命名规范 `.` | | 题目重排 | P3 不实现(题目顺序固定),P4 评估实时重排需求 | 降低 P3 复杂度 | | DataScope L0 | student-bff Resolver 层从 JWT 强制过滤(方案 A),前端不传 studentId | 前端无法绕过;gRPC 层重新校验 | ### 21.4 ISSUE-014-03 防作弊策略详情 **全屏 API**:P3 不强制(提示"建议全屏作答"),P4 评估是否升级为强制(基于教师反馈) **visibilitychange 策略**: - hidden 触发时仅记录(不自动提交) - 累计 3 次警告后教师端可见(走 `recordExamViolation` mutation 上报) - 避免误伤合法场景(如切到词典查询) **多标签检测**: - BroadcastChannel 检测到多标签时警告 + 记录 - 不阻止作答(避免误伤) **事件上报链路**: ``` student-portal → POST /api/v1/student/graphql (recordExamViolation mutation) → student-bff Resolver → core-edu gRPC ExamService.RecordViolation(ai08 在 P3 补全 RPC) → 落库 + 教师端可见 ``` ### 21.5 ISSUE-014-05 附件上传协议详情 **方案 A(采纳)**: 1. 前端:`POST /api/v1/student/upload`(multipart/form-data)→ api-gateway 鉴权 → 对象存储(MinIO/OSS)→ 返回 signed URL 2. 前端:GraphQL mutation `submitHomework(input: { homeworkId, answers, attachmentUrls: [String!] })` 提交作业 + 附件 URL 3. student-bff Resolver 接收 attachmentUrls 字段,透传给 core-edu **路由配置**: - api-gateway:`/api/v1/student/upload` → `student-bff:3009/upload`(或直接到对象存储代理) - 由 ai01(api-gateway)确认路由配置 + 大小限制(建议 20MB)+ 类型白名单(图片/PDF/文档) ### 21.6 ISSUE-014-06 实时事件命名详情 | 事件 | 发布方 | topic | 消费链路 | 阶段 | | --------------------- | ---------------- | ----------------- | --------------------------------------------------- | ---- | | ExamExtended | ai08(core-edu) | `edu.exam.events` | msg 消费 → push-gateway → student-portal 更新倒计时 | P3 | | ExamForceSubmitted | ai08(core-edu) | `edu.exam.events` | msg 消费 → push-gateway → student-portal 触发提交 | P3 | | ExamQuestionReordered | ai08(core-edu) | `edu.exam.events` | P3 不实现,P4 评估 | P4 | ### 21.7 ISSUE-014-07 DataScope L0 强制执行详情 **方案 A(采纳)**:student-bff Resolver 层从 JWT 提取 studentId,强制过滤 **ai14 修改 02-architecture-design.md §4.2**: - 移除所有 query 的 `studentId` 参数(如 `myClasses(studentId: ID!)` → `myClasses`) - 所有 query 改为无参或仅含分页/筛选参数 - 前端不传 studentId(无法绕过 L0 边界) **ai04 实现**: - 所有 student-bff Query Resolver 从 JWT `x-user-id` 提取 studentId - 强制过滤(`WHERE student_id = :jwtStudentId`) - 不接受前端传入的 studentId 参数(GraphQL schema 层不暴露) ### 21.8 ai14 执行项 1. 修 contract.md §2.3:统一路径为 `POST /api/v1/student/graphql`(ISSUE-014-01) 2. 02 §4.2 GraphQL query 定义:移除所有 `studentId` 参数(ISSUE-014-07) 3. 02 §14 防作弊策略:补全屏策略 + visibilitychange + 多标签 + 事件上报链路(ISSUE-014-03) 4. 02 §14 粘贴策略:补客观题/主观题/作文题分层(ISSUE-014-04) 5. 02 §16 实时事件:补 ExamExtended + ExamForceSubmitted 命名(ISSUE-014-06) 6. 02 §4.2 mutation 域:确认 recordExamViolation + recordPasteEvent 参数(依赖 ai04 补全) ### 21.9 ai04 执行项 1. 创建 `packages/shared-ts/contracts/graphql/student-bff.schema.graphql`(ISSUE-014-02) 2. 所有 Query Resolver 从 JWT 提取 studentId,不接受前端参数(ISSUE-014-07) 3. P3 提供 `recordExamViolation(input: RecordExamViolationInput!): RecordExamViolationPayload!` mutation(ISSUE-014-03) 4. P3 提供 `recordPasteEvent` mutation 或复用 recordExamViolation(type=PASTE)(ISSUE-014-04) 5. submitHomework mutation 接受 `attachmentUrls: [String!]` 字段(ISSUE-014-05) ### 21.10 ai01 执行项 1. 确认路由 `/api/v1/student/*` → `student-bff:3009/*`(ISSUE-014-01) 2. 确认 `/api/v1/student/upload` 路由配置(大小限制 + 类型白名单)(ISSUE-014-05) ### 21.11 ai08 执行项 1. P3 发布 ExamExtended 事件到 `edu.exam.events` topic(ISSUE-014-06) 2. P3 发布 ExamForceSubmitted 事件到 `edu.exam.events` topic(ISSUE-014-06) 3. P3 补全 ExamService.RecordViolation RPC(防作弊违规落库)(ISSUE-014-03) ### 21.12 coord 执行项 1. 确认 matrix.md §5 路径前缀对齐 `/api/v1/student/*`(ISSUE-014-01) 2. 协调 ai08 补全 ExamService.RecordViolation RPC(ISSUE-014-03) --- ## §22 ARB-020:parent-portal 模块 10 项 ISSUE 仲裁 ### 22.1 背景 ai15 在 [parent-portal_issue.md](./objections/parent-portal_issue.md) 提请 10 项异议,涉及 01/02 文档 REST 消费与 ARB-001 冲突、MF shared 配置缺 urql、switch-child 端点不一致、登录端点三方不一致、未决决策过时、contract §1.2 误标 HTTP 端点、MF 配置文件位置不一致、GraphQL 路径缺 v1、switchChild Mutation 未明确、iam GetChildrenByParent 缺失。coord 对照 [parent-portal_contract.md](./contracts/parent-portal_contract.md) + [parent-bff_contract.md](./contracts/parent-bff_contract.md) + ARB-001/ARB-002/ARB-018 逐条仲裁。 ### 22.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------ | | 001 | 01/02 文档 REST 消费 parent-bff 与 ARB-001 冲突 | ✅ 统一 GraphQL 消费(对齐 ARB-018 ISSUE-005 跨模块裁决) | ai15 修 01/02 | | 002 | MF shared 配置缺 urql/graphql/@edu/* | ✅ 补全 7 项 singleton(react/react-dom/urql/graphql/@edu/ui-tokens/@edu/ui-components/@edu/hooks) | ai15 修 02 §1.2 | | 003 | switch-child 端点在 01/02 不一致 | ✅ GraphQL Mutation `switchChild(childId: ID!): SwitchChildPayload!`(走 GraphQL,对齐 ISSUE-001) | ai15 修 01/02 + ai05 补 schema | | 004 | 登录端点三方不一致 | ✅ 统一为 `POST /api/v1/iam/login`(对齐 matrix.md §5);登录走 REST,其余走 GraphQL | ai15 修 contract §2.3 | | 005 | 02 §11.3 未决决策 #2 已由 ARB-001 裁决 | ✅ 移除未决项,改为"已裁决:见 ARB-001" | ai15 修 02 §11.3 | | 006 | contract §1.2 误标前端路由为 HTTP 端点 | ✅ §1.2 改为"无(parent-portal 是前端 Remote,不对外提供 HTTP API)" | ai15 修 contract §1.2 | | 007 | contract §1.6 MF 配置文件位置不一致 | ✅ 统一为 `apps/parent-portal/next.config.js`(对齐 02 + teacher-portal Shell) | ai15 修 contract §1.6 | | 008 | contract §2.3 GraphQL 路径缺 v1 | ✅ 统一为 `POST /api/v1/parent/graphql`(对齐 matrix.md §5) | ai15 修 contract §2.3 + §2.4 | | 009 | parent-bff GraphQL schema 是否含 switchChild | ✅ parent-bff 提供 `switchChild` Mutation(后端记录选中子女用于审计),同时前端 Zustand + localStorage 缓存 | ai05 补 schema + ai15 前端实现 | | 010 | iam GetChildrenByParent 缺失(P0 阻塞) | ✅ ai06 P3 收尾前补全(I6 裁决);补全前用 mock(固定 2 个孩子 student-001 + student-002) | ai06 补全 + ai15 mock | ### 22.3 关键裁决 | 裁决点 | 结论 | 依据 | | ----------------------- | ----------------------------------------------------------------------- | ----------------------------- | | parent-portal 消费方式 | GraphQL(`POST /api/v1/parent/graphql`),非 REST | ARB-001 + ARB-018 ISSUE-005 | | MF shared | 7 项 singleton 全补齐(含 urql/graphql/@edu/*) | ARB-002 §2.2 | | switchChild 归属 | parent-bff GraphQL Mutation(后端审计)+ 前端 Zustand 缓存 | 双层记录,避免状态不一致 | | 登录端点 | `POST /api/v1/iam/login`(REST),登录前无 JWT 不能走 GraphQL | matrix.md §5 + ARB-014 方案 A | | 前端路由分类 | 前端页面路由不进 contract §1.2 HTTP 端点表 | parent-portal 是前端 Remote | | MF 配置文件 | `apps/parent-portal/next.config.js`(NextFederationPlugin) | 对齐 teacher-portal Shell | | GraphQL 路径 | `POST /api/v1/parent/graphql`(双 /v1 前缀,对齐 ARB-014) | ARB-014 + matrix.md §5 | | iam GetChildrenByParent | ai06 P3 收尾前补全(I6 裁决,P0 阻塞) | coord-final-decisions §1 I6 | | mock 数据一致性 | parent-portal mock 与 parent-bff mock 一致(student-001 + student-002) | ChildGuard 越权校验依赖 | ### 22.4 ISSUE-003 switchChild 端点裁决详情 **裁决**:switchChild 走 GraphQL Mutation(对齐 ISSUE-001 GraphQL 消费方式) **GraphQL schema**(ai05 补 parent-bff schema): ```graphql type SwitchChildPayload { childId: ID! childName: String! selectedAt: DateTime! } type Mutation { switchChild(childId: ID!): SwitchChildPayload! } ``` **后端职责**(parent-bff): - 记录选中子女用于审计(写 Redis `parent:selected:{parentId}` TTL 30s) - ChildGuard 校验基于 iam.GetChildrenByParent 返回列表 **前端职责**(parent-portal): - Zustand store 缓存当前选中子女(`selectedChildId`) - localStorage 持久化(避免刷新丢失) - 切换子女时同时调 mutation(后端审计)+ 更新 Zustand ### 22.5 ISSUE-009 switchChild Mutation 归属裁决 **裁决**:parent-bff 提供 `switchChild` Mutation(后端记录审计),同时前端 Zustand + localStorage 缓存 **理由**: 1. 纯前端方案无法记录审计日志(谁在何时切换了哪个子女) 2. 后端记录用于异常行为检测(频繁切换可能暗示越权尝试) 3. 前端缓存提升用户体验(刷新不丢失选中状态) 4. 双层记录:后端审计 + 前端缓存,Redis TTL 30s 与 ChildGuard 对齐 ### 22.6 ISSUE-010 iam GetChildrenByParent P0 阻塞处理 **裁决**:ai06 在 P3 收尾前补全(I6 裁决),补全前用 mock **mock 数据要求**: - 返回固定 2 个孩子:`student-001`(李同学)+ `student-002`(李妹妹) - 与 parent-bff mock 数据一致(ChildGuard 校验依赖) - parent-portal 启动时校验 myChildren 返回的 user_id 与下游查询的 student_id 一致性 **补全时间点**: - ai06 P3 收尾前(parent-portal P4 启动前) - coord 在 workline.md §4 跟踪 ai06 进度 ### 22.7 ai15 执行项 1. 01 §3.1 + 02 §4.1:REST → GraphQL 消费(ISSUE-001) 2. 02 §1.2 MF shared:补齐 7 项 singleton(ISSUE-002) 3. 01 §3.1 + 02 §2.2/§4.1:switch-child → GraphQL Mutation `switchChild`(ISSUE-003) 4. contract.md §2.3:登录端点改为 `POST /api/v1/iam/login`(ISSUE-004) 5. 02 §11.3 #2:移除未决项,标注"已裁决:见 ARB-001"(ISSUE-005) 6. contract.md §1.2:改为"无(前端 Remote,不对外提供 HTTP API)"(ISSUE-006) 7. contract.md §1.6:MF 配置文件改为 `apps/parent-portal/next.config.js`(ISSUE-007) 8. contract.md §2.3 + §2.4:GraphQL 路径改为 `POST /api/v1/parent/graphql`(ISSUE-008) 9. 前端实现 `useChildSwitcher` hook:调 mutation + Zustand + localStorage(ISSUE-009) 10. mock 数据与 parent-bff 一致(student-001 + student-002)(ISSUE-010) ### 22.8 ai05 执行项 1. parent-bff GraphQL schema 补 `switchChild(childId: ID!): SwitchChildPayload!` Mutation(ISSUE-003/009) 2. switchChild Resolver:写 Redis `parent:selected:{parentId}` TTL 30s + 审计记录 ### 22.9 ai06 执行项 1. P3 收尾前补全 iam GetChildrenByParent RPC + iam_student_guardians 表(ISSUE-010,I6 裁决) ### 22.10 coord 执行项 1. 协调 ai05 补 switchChild Mutation schema(ISSUE-003/009) 2. 跟踪 ai06 GetChildrenByParent 补全进度(ISSUE-010,P0 阻塞) 3. 确认 matrix.md §5 路径前缀对齐 `/api/v1/parent/*`(ISSUE-008) --- ## §23 ARB-021:admin-portal 模块 7 项 ISSUE 仲裁 ### 23.1 背景 ai16 在 [admin-portal_issue.md](./objections/admin-portal_issue.md) 提请 7 项异议,涉及 01/02 文档归属错误(ai07→ai16)、端口错误(3003→4003)、通信协议与 ARB-001/002 不一致、遗漏审计日志与学校设置、teacher-bff 缺 admin 命名空间 schema、推送策略与同类 portal 不一致、matrix.md §4 将 admin-portal 列为 Kafka 直消费方。coord 对照 [admin-portal_contract.md](./contracts/admin-portal_contract.md) + ARB-001/ARB-002 逐条仲裁。 ### 23.2 仲裁结论 | ISSUE | 标题 | 仲裁结论 | 执行方 | | ----- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | 001 | 01/02 模块文档归属错误(ai07 → ai16) | ✅ 修正为 ai16;ai07 产出视为历史草稿 | ai16 修 01/02 头部 | | 002 | 01/02 端口错误(3003 → 4003) | ✅ 确认 admin-portal 端口 4003;同步更新 full-stack-runbook §2.1 补齐 4 个 portal 4000 段 | ai16 修 01/02 + coord 修 runbook | | 003 | 01/02 通信协议与 ARB-001/002 不一致(REST → GraphQL) | ✅ 统一 GraphQL(`POST /api/admin/graphql` → teacher-bff admin 命名空间);删除 useApi/ApiClient | ai16 修 01/02 全文 | | 004 | 01/02 遗漏审计日志与学校设置 | ✅ 视口补齐为 11 个:dashboard/users/roles/permissions/viewports/organization/classes/teachers/students/audit-logs/system | ai16 修 01/02 | | 005 | teacher-bff 缺 admin 命名空间 GraphQL schema | ✅ ai03 在 P6 启动前补齐 teacher-bff admin 命名空间 schema(参照 contract §2.4) | ai03 补 schema | | 006 | 01/02 推送策略与同类 portal 不一致(轮询 → WebSocket) | ✅ admin-portal 接入 push-gateway WebSocket(审计告警/异常登录/系统异常);保留轮询仅用于监控指标 | ai16 修 01/02 | | 007 | matrix.md §4 将 admin-portal 列为 Kafka 直消费方 | ✅ 修正为 teacher-bff(admin-portal 经 teacher-bff 间接消费,链路:iam → Kafka → teacher-bff → GraphQL → admin-portal) | coord 修 matrix.md §4 | ### 23.3 关键裁决 | 裁决点 | 结论 | 依据 | | --------------------- | ------------------------------------------------------------------------- | ----------------------------------- | | 模块归属 | ai16(非 ai07);ai07 产出视为历史草稿 | ai-allocation §5 | | 端口 | 4003(非 3003,3003 与 teacher-bff 冲突) | matrix.md §1 + ai-allocation §5 | | 通信协议 | GraphQL(`POST /api/admin/graphql`),非 REST | ARB-001 + ARB-002 | | GraphQL 端点路径 | `POST /api/admin/graphql`(对齐 contract §2.3,非双 /v1 前缀) | admin 走 teacher-bff,非独立 BFF | | 视口数量 | 11 个(补齐审计日志 + 学校设置) | ai-allocation §5 + contract §1.2 | | admin 命名空间 schema | ai03 在 P6 启动前补齐 teacher-bff admin schema | ARB-001 §1.3 P6 新增 admin 命名空间 | | 推送策略 | WebSocket(审计告警/异常登录/系统异常)+ 轮询(监控指标 60s / 统计 5min) | 同类 portal 一致 + 低频数据轮询合理 | | Kafka 消费链路 | iam → Kafka → teacher-bff 消费 → GraphQL auditLogs Query → admin-portal | 前端不直连 Kafka,经 BFF 聚合 | ### 23.4 ISSUE-005 teacher-bff admin 命名空间 schema 补全 **裁决**:ai03 在 P6 启动前补齐 teacher-bff admin 命名空间 GraphQL schema **补全范围**(参照 admin-portal contract §2.4): ```graphql # teacher-bff.graphql admin 命名空间部分(ai03 在 P6 补齐) type Query { # 用户管理 adminUsers(filter: AdminUserFilter, page: PageInput): AdminUserConnection! adminUser(id: ID!): AdminUser # 角色权限 adminRoles: [AdminRole!]! adminPermissions: [AdminPermissionGroup!]! # 视口配置 adminViewports(scope: ViewportScope): [ViewportItem!]! # 组织管理 adminOrganization(parentId: ID): [OrganizationNode!]! # 全局管理 adminClasses(filter: ClassFilter): [Class!]! adminTeachers(filter: TeacherFilter): [Teacher!]! adminStudents(filter: StudentFilter): [Student!]! # 审计日志 auditLogs(filter: AuditLogFilter, page: PageInput): AuditLogConnection! # 仪表盘 adminDashboard: AdminDashboard! } type Mutation { createUser(input: CreateUserInput!): User! updateUser(id: ID!, input: UpdateUserInput!): User! deleteUser(id: ID!): Boolean! toggleUserStatus(id: ID!): User! createRole(input: CreateRoleInput!): AdminRole! updateRolePermissions(id: ID!, permissions: [String!]!): AdminRole! updateViewport(key: String!, input: UpdateViewportInput!): ViewportItem! } ``` **存放位置**:`packages/shared-ts/contracts/graphql/teacher-bff.graphql`(admin 命名空间部分,对齐 ARB-001 §1.3 集中管理) **就绪信号**: - ai03 P6 启动前完成 - 作为 admin-portal P6 的前置就绪信号 - 更新 matrix.md §3 teacher-bff 行的 schema 文件状态 ### 23.5 ISSUE-006 推送策略裁决详情 **裁决**:admin-portal 接入 push-gateway WebSocket + 保留轮询低频数据 **WebSocket 消费场景**: - 审计告警(异常权限变更、敏感操作) - 异常登录(非工作时间登录、异地登录) - 系统异常(服务健康检查异常、资源告警) **轮询保留场景**: - 监控指标(60s 间隔,Prometheus 数据) - 统计数据(5min 间隔,全校统计) **实现**: - `ws://push-gateway:8081/ws`(与同类 portal 一致) - JWT 鉴权 - 事件类型:审计告警 / 异常登录 / 系统异常 ### 23.6 ISSUE-007 Kafka 消费链路修正 **裁决**:matrix.md §4 该行消费方更正为 teacher-bff(admin-portal 经 teacher-bff 间接消费) **实际链路**: ``` iam → Kafka edu.iam.audit.created → teacher-bff 消费 ↓ GraphQL auditLogs Query ↓ admin-portal 消费 ``` **修正范围**: - matrix.md §4 第 111 行:`admin-portal` → `teacher-bff` - 避免误导架构分层(前端不直连 Kafka) ### 23.7 GraphQL 端点路径说明 **admin-portal 路径**:`POST /api/admin/graphql`(非双 /v1 前缀) **与 ARB-014 方案 A 的关系**: - ARB-014 方案 A 适用于独立服务(iam/core-edu 等):`/api/v1//v1/*` - admin-portal 走 teacher-bff admin 命名空间:`POST /api/admin/graphql`(teacher-bff 已有 `/api/v1/teacher/*` 前缀,admin 命名空间作为 teacher-bff 子路径) - 由 ai01 确认 api-gateway 路由:`/api/admin/*` → `teacher-bff:3003/admin/*` ### 23.8 ai16 执行项 1. 01/02 头部:ai07 → ai16;分支名更正(ISSUE-001) 2. 01 §1 + 02 §12.1:端口 3003 → 4003(ISSUE-002) 3. 01 §3.1 + 02 §1/§4:REST → GraphQL(useApi → useGraphQLClient)(ISSUE-003) 4. 01 §2.1/§L1 导航/§L2 路由表:补齐 11 个视口(含 audit-logs + system)(ISSUE-004) 5. 01 §3.3 + 02 §5:推送策略改为 WebSocket + 轮询低频数据(ISSUE-006) 6. 02 §11.3:移除已裁决的"GraphQL vs REST"未决项(ISSUE-003) ### 23.9 ai03 执行项 1. P6 启动前补齐 teacher-bff admin 命名空间 schema(参照 §23.4 清单)(ISSUE-005) 2. schema 存放 `packages/shared-ts/contracts/graphql/teacher-bff.graphql` admin 部分 ### 23.10 coord 执行项 1. 修正 matrix.md §4 第 111 行:`admin-portal` → `teacher-bff`(ISSUE-007) 2. 同步 full-stack-runbook §2.1:补齐 4 个 portal 4000 段端口(ISSUE-002) 3. 确认 ai03 admin 命名空间 schema 作为 admin-portal P6 前置就绪信号(ISSUE-005) 4. 协调 ai01 确认 `/api/admin/*` → `teacher-bff:3003/admin/*` 路由配置 --- ## §8 仲裁流程说明 ### 8.1 提请异议 各 AI 在自己模块的 `objections/[模块名]_issue.md` 中追加异议条目,格式: ```markdown ### ISSUE-[编号]-[AI标识]:[标题] - **提请方**:aiXX - **日期**:YYYY-MM-DD - **类型**:契约不明确 / 工作量超批 / 前置依赖缺失 / 编号冲突 / 其他 - **描述**:[详细描述问题] - **建议方案**:[AI 的建议] - **状态**:待 coord 仲裁 / 已裁决(见 coord.md §X) ``` ### 8.2 coord 仲裁 coord 审阅各 `objections/[模块名]_issue.md` 后,在本文件(coord.md)追加仲裁章节: ```markdown ## §N ARB-XXX:[主题] ### N.1 背景 ### N.2 仲裁结论 ### N.3 关键裁决(表格) ### N.4 相关 AI 执行项 ``` ### 8.3 状态同步 - 仲裁完成后,coord 在对应 `objections/[模块名]_issue.md` 中更新状态为"已裁决(见 coord.md §N)" - coord 在 [workline.md](./workline.md) §8 就绪信号跟踪表中更新进度 ### 8.4 目录结构 ``` issues/ ├── coord.md # 本文件(仲裁汇总) ├── workline.md # 总工作安排 ├── matrix.md # 上下游对接总矩阵 ├── objections/ # 各模块问题/异议 │ ├── [模块名]_issue.md │ └── cross_issue.md # 跨模块问题 ├── worklines/ # 各模块工作排期 │ └── [模块名]_workline.md └── contracts/ # 各模块对接契约 └── [模块名]_contract.md ``` --- ## §9 历史仲裁(已迁移) 以下仲裁已在此前完成,原始记录见 [coord-final-decisions.md](../coord-final-decisions.md) 和 [president-final-rulings.md](../president-final-rulings.md): - I1-I8:iam P2 契约(coord-final-decisions.md §1) - F1-F9:BFF 设计裁决(coord-final-decisions.md §2) - G1-G3:Gateway 裁决(coord-final-decisions.md §3) - N1-N3:content 裁决(coord-final-decisions.md §4) - 总裁裁决 70+ 项(president-final-rulings.md §1-§5) 本文件仅记录**新流程启动后**(2026-07-09 起)的仲裁。