70 KiB
总裁最终裁决(President Final Rulings)
版本:1.0(历史文档) 日期:2026-07-09 决策者:总裁(用户) 执行者:coord(统一落实) 适用范围:Edu 微服务架构全部 15 个 AI(ai01-ai06, ai08-ai16)+ coord 维护的 shared-* 包与文档
⚠️ 历史声明:本文件为批次模式时期(2026-07-09)的总裁裁决记录。项目已于 2026-07-10 切换为全并行开发模式(15 AI 一口气完成 P2-P6,开发期间用 mock,最后统一集成测试)。
- 本文件正文保留原始裁决内容(含 ai07/classes 交接、6 批次时间线等),作为历史追溯凭证
- 当前权威文档:ai-allocation.md v2.0 + issues/README.md + issues/matrix.md
- ai07 已移除(classes 合并到 core-edu,ai08 负责)
- 6 批次时间线已被全并行模式取代
关联文档:
- coord-final-decisions.md(80+ 项强制裁决,本文件为其上层总裁裁决)
- ai-work-orchestration.md(6 批次并行规划,本文件调整其时间线)
- issues.md(70+ 问题汇总,本文件逐个裁决)
- 004 架构影响地图
- port-allocation.md
- ai-allocation.md
0. 裁决原则
0.1 总裁授权范围
本文件是用户作为总裁对全部已汇总问题(ISSUE-001 ~ ISSUE-066,含编号冲突)的最终裁决,覆盖:
- coord-final-decisions.md 80+ 项裁决的最终确认(无推翻)
- ai-work-orchestration.md 6 批次时间线的最终调整
- issues.md 70+ 问题的逐个裁决(状态全部转为"总裁已裁决")
- 文档同步遗漏的修复指令
- 编号冲突的整理规则
- 各 AI 工作内容的最终边界
0.2 裁决优先级
裁决按以下优先级分组,AI 执行时按优先级处理:
- P0 立即执行:文档同步遗漏修复 + 编号冲突整理
- P1 批次 0 启动前完成:设计契约明确 + 工具包产出
- P2 各批次启动前完成:文档回写 + 工作量分级
- P3 各阶段执行中持续:跨阶段扩展例外执行
0.3 "不分阶段"与"批次"的最终澄清
针对 ISSUE-021(ai08)/ ISSUE-015 §0.1(ai15)表述歧义问题,总裁最终澄清:
| 概念 | 适用层级 | 含义 | 禁止事项 |
|---|---|---|---|
| 不分阶段 | 代码实现层面 | 服务首次落地即采用最终方案,禁止"前期简化版后期重构" | 禁止 P2 写 REST 后期切 GraphQL;禁止 P2 mock 数据后期接真实 gRPC |
| 批次 | 工作排序层面 | 因服务依赖需串行启动(下游未就绪时上游无法启动) | 批次时间线允许调整,但不得作为"先简化后重构"的借口 |
| 跨阶段扩展例外 | 唯一允许的"分阶段"场景 | BFF /readyz 探针列表 / Dashboard Resolver 字段填充 / AuthorizationGuard 内部实现允许按阶段扩展 | 见 §2.3 详细验收标准 |
核心规则:批次规划保证下游就绪后再启动上游;不分阶段保证每个服务首次实现即最终方案。两者不冲突。
0.4 编号冲突整理规则(ISSUE-031/035 处理)
针对 issues.md 严重的编号冲突(ISSUE-024/025 ai11 与 ai09 重复 / ISSUE-028030 ai04 与 ai11 重复 / ISSUE-031 ai04 与 ai15 重复 / ISSUE-032035 ai03 与 ai15 重复 / ISSUE-036 ai03 与 ai13 重复 / ISSUE-044~048 ai16 与 ai06 重复),总裁裁决:
- 保留所有 issues 原始内容不删除(避免信息丢失)
- 不再重新编号(重编号工作量大,且 AI 已在文档中引用现有编号)
- 在本文件 §10 问题索引表中统一映射,每个 issue 用
ISSUE-XXX-<提请AI>格式唯一定位(如 ISSUE-024-ai11 / ISSUE-024-ai09) - coord 在 issues.md §0.5 添加索引指针指向本文件,AI 查询时先看本文件索引表
1. P0 立即修复:文档同步遗漏
1.1 port-allocation.md §5 iam 行修正(ISSUE-001/015)
裁决:修正 port-allocation.md §5(行 77 附近)iam 行:
- 修改前:
IamService(P3 启用) | P3 - 修改后:
IamService(P2 启用,I1 裁决) | P2
理由:对齐 coord-final-decisions.md I1 裁决(iam P2 即启用 gRPC server 50052)+ port-allocation.md §3 已修正的内容。
执行者:coord 完成期限:本裁决发布后立即
1.2 004 §4.2 gRPC 启用矩阵修正(ISSUE-003)
裁决:修正 004 §4.2 gRPC 启用阶段矩阵,iam 行从"P3 启用"改为"P2 启用"。
理由:对齐 I1 裁决。
执行者:coord 完成期限:本裁决发布后立即
1.3 004 §16.7.4 P4 清单补 QuestionService(ISSUE-016)
裁决:004 §16.7.4 P4 启动前整改清单补充 content QuestionService:
- 修改前:仅列"ChapterService / TextbookService.ListTextbooks"
- 修改后:补充"+ QuestionService(N3 裁决,P4 即补全,不等到 P5)"
理由:对齐 coord-final-decisions.md N3 裁决(QuestionService proto P4 即补全)。
执行者:coord 完成期限:本裁决发布后立即
1.4 004 §16.7.5 P5 清单删 QuestionService(ISSUE-016)
裁决:004 §16.7.5 P5 启动前整改清单删除"ai09 content 补 QuestionService RPC(阻塞 ai 出题)"项。
理由:QuestionService 已在 P4 补全,P5 不再重复。
执行者:coord 完成期限:本裁决发布后立即
1.5 004 §7.2 Kafka topic 表格修订(ISSUE-043/053)
裁决:修订 004 §7.2 Kafka topic 路由表:
- 删除:
| edu.notification.events | 通知事件 | Msg | push-gateway | - 新增 3 行:
| edu.notification.sent | 通知发送 | Msg | push-gateway、DataAna |
| edu.notification.read | 通知已读 | Msg | DataAna |
| edu.notification.recalled | 通知撤回 | Msg | DataAna |
| edu.notification.requested | 通知投递请求 | Msg | push-gateway |
- 在表格下方追加注释:"本表已对齐 §16.3.2 + G16 裁决,禁止抽象名
edu.*.events"
理由:对齐 G16 裁决(topic 命名统一 edu.<domain>.<aggregate>.<action>,禁止抽象名)+ ai10 msg 02 §5 已设计的具体动作名 + ai02 push-gateway 消费 edu.notification.requested(ISSUE-053)。
执行者:coord 完成期限:本裁决发布后立即
1.6 coord-final-decisions.md + ai-work-orchestration.md 相对路径修正(ISSUE-031-ai15)
裁决:修正两份文档 L7 关联文档引用:
coord-final-decisions.mdL7:[ai-allocation.md](./architecture/ai-allocation.md)→[ai-allocation.md](./ai-allocation.md)ai-work-orchestration.mdL7:[ai-allocation.md](./architecture/ai-allocation.md)→[ai-allocation.md](./ai-allocation.md)
理由:两份文档自身位于 docs/architecture/ 目录下,引用 ./architecture/ai-allocation.md 会多一层路径。
执行者:coord 完成期限:本裁决发布后立即
1.7 issues.md §0.5 添加总裁裁决索引指针
裁决:在 issues.md §0.4 之后新增 §0.5:
### 0.5 总裁最终裁决索引
> 所有 ISSUE-001 ~ ISSUE-066 的"coord 裁决"字段已由总裁最终裁决覆盖。
> 查询裁决结果请先查阅 [president-final-rulings.md](./architecture/president-final-rulings.md)。
> 本文件保留所有 issues 原始内容作为问题追溯,编号冲突通过 `ISSUE-XXX-<提请AI>` 格式唯一定位(见 president-final-rulings.md §10)。
执行者:coord 完成期限:本裁决发布后立即
2. P1 批次 0 启动前完成:设计契约明确
2.1 shared-ts Outbox 工具包设计(ISSUE-018/050)
裁决:coord 在批次 0.4 完成 packages/shared-ts/src/outbox/ 设计草案,包含:
- 包名:
@edu/shared-ts/outbox - 导出 API:
// 1. OutboxModule(NestJS Module 注入)
export class OutboxModule {
static forRoot(config: OutboxConfig): DynamicModule;
}
// 2. OutboxService(发布接口)
export class OutboxService {
publish(
eventType: string,
payload: unknown,
options?: PublishOptions,
): Promise<string>;
// 返回 outbox record id
}
// 3. OutboxRelayWorker(内置 Relay Worker,可注入)
export class OutboxRelayWorker {
start(): void;
stop(): Promise<void>;
}
- 配置项:
interface OutboxConfig {
tableName: string; // 各服务可配,默认 'outbox_events'
kafkaTopic: string; // 各服务可配
pollIntervalMs: number; // 默认 1000
batchSize: number; // 默认 100
maxRetryCount: number; // 默认 5
retryBackoffMs: number; // 默认 1000,指数退避
}
- 表 schema(Drizzle migration,各服务执行):
CREATE TABLE outbox_events (
id VARCHAR(32) PRIMARY KEY, -- cuid2
event_type VARCHAR(64) NOT NULL,
payload JSON NOT NULL,
status VARCHAR(16) DEFAULT 'pending', -- pending / published / failed
retry_count INT DEFAULT 0,
last_error TEXT,
created_at TIMESTAMP DEFAULT NOW(),
published_at TIMESTAMP
);
CREATE INDEX idx_outbox_status_created ON outbox_events(status, created_at);
- 集成方式:NestJS Module 注入(
@Module({ imports: [OutboxModule.forRoot(config)] })) - 是否含 Kafka producer:内置(iam 仅配置 topic)
- ORM 支持:仅支持 Drizzle ORM(对齐黄金模板)
- 事务边界:业务表 + outbox 表同事务(Drizzle 事务 API),示例:
await db.transaction(async (tx) => {
await tx.insert(users).values(newUser);
await outboxService.publish("user.created", { userId: newUser.id }, { tx });
});
理由:iam 首次接入方需求迫切(I2 裁决),core-edu / content / msg 后续接入保持一致。
执行者:coord 完成期限:批次 0.4(批次 1 启动前)
2.2 GraphQL schema 仲裁机制(ISSUE-019/030/037)
裁决:建立 GraphQL schema 仲裁规范:
-
存放位置:
packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql(ai03 定义,coord 仲裁)student-bff.schema.graphql(ai04 定义,coord 仲裁)parent-bff.schema.graphql(ai05 定义,coord 仲裁)admin.schema.graphql(admin 命名空间,复用 teacher-bff schema,见 §5.1)
-
起草方:各 BFF 负责 AI 起草,coord 仲裁
- teacher-bff:ai03 起草,coord 在批次 1 启动前仲裁第一版
- student-bff:ai04 起草(批次 1 等待期),coord 在批次 2 启动前仲裁第一版
- parent-bff:ai05 起草(批次 2 等待期),coord 在批次 3 启动前仲裁第一版
-
覆盖范围:
- Query/Mutation 清单(含字段定义 + 类型 + 分页规范)
- 权限点标注(F7 规范,注释形式
# @permission: DASHBOARD_VIEW) - DataScope 标注(注释形式
# @dataScope: OWN/CHILD/CLASS) - 错误响应格式(GraphQL errors 数组扩展 ActionState 字段,
extensions.code = BFF_*)
-
版本管理:SDL-first(schema.graphql 文件),配合 graphql-codegen 生成 TS 类型
-
命名规范:
- Query/Mutation:camelCase(如
teacherDashboard/listClassesByTeacher) - 分页:Relay Cursor Connections 规范(
{ edges, pageInfo, totalCount }) - 错误:GraphQL errors 数组 +
extensions.code+extensions.traceId
- Query/Mutation:camelCase(如
-
协调流程:
- BFF AI 起草 schema 草案 → coord 仲裁第一版 → 前端 AI 消费
- schema 变更需 PR + BFF AI + 前端 AI 双方 review
- 重大变更(删除字段 / 修改类型)需 coord 仲裁
理由:ai03 / ai04 / ai05 / ai13 / ai14 / ai15 均依赖 schema 仲裁,需统一机制。
执行者:coord(仲裁)+ 各 BFF AI(起草)+ 各前端 AI(消费) 完成期限:
- teacher-bff schema 第一版:批次 1 启动前
- student-bff schema 第一版:批次 2 启动前
- parent-bff schema 第一版:批次 3 启动前
2.3 BFF 跨阶段扩展例外验收标准(ISSUE-020)
裁决:明确"跨阶段扩展例外"的允许范围:
允许扩展:
- 新增下游 gRPC 调用(新增 RPC 方法到 DownstreamClient)
- 新增下游配置(gRPC endpoint 配置)
- 新增 /readyz 探针(按阶段启用,见 §2.4)
- Dashboard Query Resolver 内部数据源扩展(null 字段 → 真实数据)
- AuthorizationGuard 内部实现替换(DEV_MODE 放行 → 真实 gRPC 校验)
禁止变更:
- 修改已有 RPC 调用的签名或返回类型
- 删除已实现的 RPC 调用(除非下游服务下线)
- 修改 GraphQL schema 已有字段的类型(新增字段允许)
- 修改 /readyz 已有探针的检查项(只能新增,不能修改)
验收标准:
- 扩展时必须更新 BFF 的 02-architecture-design.md 下游调用矩阵
- 扩展时必须更新 packages/shared-ts/contracts/graphql/ 下对应 schema 文件
- 扩展时必须运行
pnpm run arch:scan更新 arch.db - coord 在批次验收时检查上述 3 项
理由:ai03 / ai04 / ai05 跨阶段扩展时需统一标准。
执行者:各 BFF AI 执行,coord 验收
2.4 /readyz 探针按阶段扩展规则(ISSUE-023/034/042/055)
裁决:G2 裁决"首次实现即检查全部下游依赖"按以下规则执行:
-
探针列表按阶段扩展(属"跨阶段扩展例外"):
- P2 teacher-bff /readyz:DB + Redis + iam gRPC 50052(3 项)
- P3 teacher-bff:+ core-edu gRPC 50053(4 项)
- P4 teacher-bff:+ content gRPC 50054 + data-ana gRPC 50055(6 项)
- P5 teacher-bff:+ ai gRPC 50058 + msg gRPC 50056(8 项)
-
实现方式:
DownstreamHealthCheck注册表模式,每个下游注册独立探针,按阶段启用 -
可选依赖软失败规则(针对 ISSUE-042/055):
- 必需依赖(DB / Redis / 已启用 gRPC 下游):失败返回 503,触发 Pod 重启
- 可选依赖(Kafka 消费 / PushGateway / 未启用 gRPC 下游):失败仅告警,返回 200 + body
degraded: true - msg /readyz 对 PushGateway:软失败(ISSUE-042 采纳方案 A)
- push-gateway /readyz 对 Kafka:软失败(ISSUE-055)
-
未引入依赖跳过(ISSUE-023):
- content P4 /readyz:检查 MySQL + Neo4j + Kafka(3 项,ES 未配置则跳过)
- content P5 /readyz:扩展 ES 检查(4 项,ES_URL 存在时才检查)
- 实现方式:检查项数组通过 ENV 过滤(
if (env.ES_URL) checks.push(checkES))
-
分级检查(ISSUE-029):
- data-ana /readyz 对 iam gRPC:
- L1 ping iam 50052 端口可达(基础就绪,失败 ready=false)
- L2 调用 GetEffectiveDataScope 返回有效(深度就绪,失败 degraded=true)
- data-ana /readyz 对 iam gRPC:
理由:G2 原裁决"全部下游依赖"在 P2 不可行,需按阶段扩展 + 软失败策略。
执行者:各 AI 按规则实现
2.5 AttendanceService proto 责任方(ISSUE-022)
裁决:
- coord 负责 proto 契约定义:core_edu.proto 补 AttendanceService + GetClassesByTeacher + BatchGetClasses 的 message + RPC 签名
- ai08 负责 proto 实现:基于 coord 定义的 proto 生成 TS 代码 + 实现 AttendanceService 业务逻辑
- 修正 coord-cross-review.md §6 #14:责任方从 ai03 改为 coord(proto)+ ai08(实现)
- 修正 004 §16.7.3:保留 ai08 实现,但补注"proto 契约由 coord 定义"
理由:proto 契约是跨服务协作的接口,应由 coord 统一维护;业务实现由服务负责 AI 完成。
执行者:coord(proto)+ ai08(实现) 完成期限:proto 在批次 0.8 完成,实现 ai08 P3 完成
2.6 降级模式 ActionState 表达(ISSUE-030-ai11)
裁决:采纳方案 B(success=true + error=null + data 内 degraded 字段):
// 降级响应
{
success: true,
data: {
...actualData,
degraded: true, // 降级标记
degradedReason: "redis_unavailable" // 降级原因
},
error: null
}
规则:
- 降级时
success=true,HTTP 200 data内统一加degraded: boolean+degradedReason: string字段- BFF 消费端检查
data.degraded判断降级 - Python 服务(data-ana / ai)的 data 类型需统一加 degraded 字段
- 修正 data-ana 02-architecture-design.md §4.3 ActionState.ok() 实现
理由:方案 B 最符合"成功返回数据但质量降级"的语义,避免"success=true 但 error 有值"的语义矛盾。
执行者:ai11(data-ana)+ ai12(ai)实现,coord 验收
2.7 BFF 错误码语义区分(ISSUE-059)
裁决:采纳 ai03 建议方案,明确 3 类 BFF 越权防御错误码:
| 错误码 | HTTP | 场景 | i18n key |
|---|---|---|---|
BFF_TEACHER_UNAUTHORIZED |
401 | x-user-id 缺失或无效 | error.bffTeacher.unauthorized |
BFF_TEACHER_FORBIDDEN_RESOURCE |
403 | teacherId 与资源无归属关系(场景 A) | error.bffTeacher.forbidden_resource |
BFF_TEACHER_IDENTITY_MISMATCH |
403 | JWT teacherId 与请求 body teacherId 不一致(场景 B) | error.bffTeacher.identity_mismatch |
B3 裁决澄清:BFF 豁免 @RequirePermission 指不做"功能权限决策"(如"能否查看仪表盘"),但必须做"数据权限防御"(如"只能看自己的班级")。
student-bff / parent-bff 同规则:BFF_STUDENT_* / BFF_PARENT_* 前缀对应。
执行者:ai03 / ai04 / ai05 实现
2.8 Dashboard Query Resolver P2 实现方式(ISSUE-032)
裁决:采纳 ai03 建议方案:
- GraphQL schema 设计完整(含全部 Query/Mutation 字段定义),P2 即定型,后续不重构
- Resolver 实现:P2 阶段 Dashboard Query Resolver 内部仅调 iam gRPC(返回用户基础信息 + 角色),未启用的下游字段(班级数 / 作业数等)返回
null+extensions.warning = "field_unavailable_in_p2" - P3-P5 扩展:按"跨阶段扩展例外"原则,在 Resolver 内逐步补 gRPC 调用,将 null 字段替换为真实数据
- ai13 前端:P2 联调时对 null 字段做 UI 降级展示(如"数据加载中"或隐藏模块)
- 此方案不违反"不分阶段":schema 即最终方案,Resolver 内部数据源扩展属"跨阶段扩展例外"
执行者:ai03 实现 + ai13 前端配合
2.9 越权防御 P2 实现方式(ISSUE-033)
裁决:采纳 ai03 建议方案 D:
- P2 抽象
AuthorizationGuard接口(canAccessClass(userId, classId): Promise<boolean>) - P2 内部实现为"DEV_MODE 放行 + 生产拒绝"(保守策略)
- Redis 缓存:P3 接入 core-edu gRPC 后,
GetClassesByTeacher结果缓存到 Redis(key:authz:teacher:{teacherId}:classes,TTL 5min),AuthorizationGuard 优先查缓存 - 此方案不违反"不分阶段":Guard 接口即最终方案,P2→P3 仅替换内部实现(属"跨阶段扩展例外")
P2 阶段生产环境:Guard 全部拒绝时,teacher-bff P2 端到端验证仅限 DEV_MODE。生产环境 P2 不接入流量(仅 dev 测试),P3 接入真实校验后正式上线。
执行者:ai03 实现
2.10 analytics.proto 补全时间(ISSUE-027)
裁决:
- coord 在批次 0.11 完成 analytics.proto 扩展(4 端 Dashboard + Warning + MasteryDistribution + SubscribeMasteryUpdate Stream RPC)
- ai11 在批次 3(P4)启动前确认 proto 已就绪
- ai11 等待期间可先实现 HTTP 端点 + CDC 消费者 + ClickHouse DDL 等不依赖 proto 的工作
执行者:coord 完成期限:批次 0.11(批次 3 启动前)
2.11 warning.triggered topic 处理(ISSUE-028-ai11)
裁决:采纳方案 B(复用 topic):
- 维持现状,
warning.triggered复用edu.insight.mastery.updatedtopic - events.proto MasteryEvent 用
action字段区分mastery.updated/warning.triggered - consumer 按 action 字段路由
- D5 描述修正为"复用 mastery.updated topic,非独立登记"
- 004 §7.2 表格补充注释:"warning.triggered 复用 edu.insight.mastery.updated topic,通过 action 字段区分"
理由:避免拆分为两个 message 增加复杂度,复用 topic + action 字段路由是 Kafka 常见模式。
执行者:coord 修订 004 §7.2 + D5 描述
2.12 ClickHouse DDL 归属(ISSUE-026)
裁决:
- ai11 提供 DDL 内容(已在 02 文档 §3 设计完毕)
- coord 授权 ai11 在
infra/clickhouse/ddl/下创建纯 DDL .sql 文件(不涉及部署脚本) - SRE AI 负责部署执行脚本(如
init-clickhouse.sh) - 修正 project_rules §14.2 解释:业务 AI 可创建纯 DDL 文件(不涉及部署脚本),SRE AI 负责部署执行
理由:DDL 内容是业务特定的(5 张宽表设计),由 ai11 提供最合适;部署脚本属 infra 范畴。
执行者:ai11(DDL)+ SRE AI(部署)
2.13 Neo4j 知识图谱派生数据裁决(ISSUE-025-ai09)
裁决:Neo4j 知识图谱属于"派生数据读模型":
- Neo4j 节点数据完全从 MySQL 的 knowledge_points / kp_prerequisites 表派生
- Neo4j 是读模型(图查询优化),MySQL 是写模型(权威源)
- 符合 CQRS 读写分离原则
- 实现方式:content 主领域事件走 Outbox → Kafka,Neo4j Sync Worker 作为 Kafka consumer 消费这些事件并同步图谱(无需独立 Outbox)
理由:采纳 ai09 建议方案,符合 004 §12.2 派生数据事件豁免 Outbox 模式。
执行者:ai09 实现
2.14 ES Projector 实现位置(ISSUE-024-ai09)
裁决:采纳方案 A(content 内部实现):
- ES Projector 在 content 服务内部实现(
shared/sync/es-sync.worker.ts) - 与 Neo4j Sync Worker 同构(一对 Sync Worker 模式)
- shared-ts 仅承载通用的 Outbox Publisher(Kafka producer 通用能力),特定 Projector 由各服务自实现
- ES mapping 是 content 特有的(questions/knowledge_points 索引结构、ik_max_word 分词、dense_vector embedding),通用 Projector 难以抽象
执行者:ai09 实现(P5 阶段)
2.15 API 版本化 /iam/v1/* 规则(ISSUE-048)
裁决:
- 全服务统一加
/v1前缀(不只是 iam),各服务按自身节奏推进(iam P2 / core-edu P3 / content P4 / msg P5) - 前缀位置:Controller 内加
v1前缀(NestJS@Controller('v1/iam/auth')) - Gateway 透传:Gateway 路由
/iam/v1/*→ iam 服务/v1/iam/*(Gateway 不改路径,直接透传) - 避免双 v1:Controller 加
/v1,Gateway 转发路径不含/v1(Gateway 仅做路径匹配 + 代理) - 现有端点立即迁移:不保留旧路径(遵循"不分阶段"原则,P1 链路由 ai01 + ai06 同步修复)
- gateway 路由配置同步更新(ai01 P2 工作项)
理由:采纳 ai06 建议方案,统一规则避免各 AI 自行理解。
执行者:各服务 AI 实现 + ai01 Gateway 配置
2.16 gRPC 与 REST 双入口策略(ISSUE-049)
裁决:
- 双入口策略:REST 供 gateway 透传 + 前端直连(admin-portal),gRPC 供 BFF 聚合调用
- NestJS 复用:同一 Application Service 同时被 REST Controller + gRPC Controller 调用,业务逻辑不重复
- gateway 保持 HTTP 透传:gateway 不改为 gRPC 客户端(降低 P2 工作量),gateway → iam REST 路径不变
- BFF gRPC 调 iam:teacher-bff / student-bff / parent-bff 用 gRPC 调 iam(B2 裁决)
- 写入 coord-final-decisions.md I1 补充条款
理由:采纳 ai06 建议方案,避免 gateway 改为 gRPC 客户端的额外工作量。
执行者:ai06 实现 + ai01 Gateway
2.17 MF AppShell GraphQL client 单例(ISSUE-038/047)
裁决:采纳方案 A(Shell 暴露 GraphQL client 单例):
- Shell 暴露 GraphQLProvider:ai13 P2 teacher-portal MF shell 的 AppShell 包含
<GraphQLProvider client={sharedClient}> - 统一缓存:避免跨 Remote 数据不一致
- 统一鉴权 header 注入:Authorization: Bearer token
- 统一错误处理:401 跳转登录、5xx 降级
- MF shared 配置:react / urql / apollo 设为 singleton,避免多实例
- admin-portal 复用(ISSUE-047):ai16 admin-portal 作为 MF Remote 接入 teacher-portal Shell,复用 Shell 暴露的 GraphQL client 单例
- ai16 回写 02 文档 §4.1:将"复用 ApiClient (REST)"改为"复用 Shell 暴露的 GraphQL client 单例"
- coord 在批次 1 启动前仲裁 MF shell 暴露清单(增加 GraphQL client 项)
理由:统一缓存 + 鉴权 + 错误处理,避免各 Remote 自行初始化导致数据不一致。
执行者:ai13 实现 + ai14/ai15/ai16 消费
2.18 ai13 packages 建立时机(ISSUE-039)
裁决:
- ai13 在 P2 启动前(批次 0 末或批次 1 初)建立 3 个 packages 骨架:
packages/ui-tokens(设计令牌,无依赖)packages/ui-components(依赖 ui-tokens)packages/hooks(依赖 ui-components)
- 4 个 portal 统一消费,版本通过 pnpm workspace 协议(
"workspace:*") - ai13 完成后通知 ai14/ai15/ai16 消费
- coord 在批次 1 验收 ai13 时检查 packages 已建立
- 批次 0 增加 0.15 任务:"ai13 建立 packages/ui-tokens + ui-components + hooks 骨架"
执行者:ai13 完成期限:批次 0.15(批次 1 启动前)
2.19 shared-go 包建立(ISSUE-054)
裁决:
- coord 在批次 0 增加 0.14 任务:"建立
packages/shared-go包骨架(含 tracer/logger/jwks/env 4 个模块的接口定义 + 默认实现)" - ai01 / ai02 在 P2/P5 启动时直接 import
packages/shared-go,禁止各自维护副本 - shared-go 包版本管理:通过 go.workspace 引用,对齐 project_rules §11
- 后续提取候选:circuit-breaker.go / rate-limiter.go(若 ai01 P2 实现后 ai02 P5 复用)
执行者:coord 完成期限:批次 0.14(批次 1 启动前)
3. P2 各批次启动前完成:文档回写与工作量分级
3.1 ai03 P2 工作量分级(ISSUE-036)
裁决:采纳 ai03 建议方案,明确 P2 最小交付范围:
Must Have(P2 必须完成):
- GraphQL endpoint + schema 第一版(阻塞 ai13)
- DownstreamClient 抽象 + iam gRPC(阻塞 ai04/ai05)
- AuthMiddleware 越权防御抽象(B4 + ISSUE-033)
- /readyz 探针注册表 + iam 探针(G2 + ISSUE-034)
- /healthz liveness(G3)
- pino 结构化日志(G4)
- GlobalErrorFilter + ActionState 信封(G8)
- BFF_TEACHER_ 错误码前缀(B5 + G14 + ISSUE-059)
- 回写 02 文档(§7.2 + ISSUE-035)
- ESM import .js 后缀(G12)
- import type(G13)
- getDb() 统一(G10)
- cuid2 ID(G11)
Should Have(P2 末期或 P3 初期补):14. OTel tracer(G6,P2 可降级为 logger-only)15. /metrics 业务指标(G5,P2 仅暴露 process metrics)16. DataLoader 集成(B1,P2 可先用普通 resolver)17. Redis 5-30s 短缓存(B6)
Nice to Have(P3 持续补):18. Zod 全量验证(G7,P2 先校验核心 Query)19. 优雅关闭 SIGTERM(G9,P2 可简化为 HTTP close)
理由:批次 1 时间线 5-7 天内完成 19 项工作风险高,按 Must/Should/Nice 分级保证关键路径。
执行者:ai03 完成期限:Must Have 在批次 1 完成,Should Have 在 P3 初期补,Nice to Have 在 P3 持续补
3.2 ai06 iam P2 工作量分级(ISSUE-052)
裁决:采纳方案 A(拆分 P2 为 P2.1 核心 + P2.2 扩展):
P2.1(批次 1,5-7 天,阻塞批次 2):
- gRPC server 50052 + 8 RPC 实现(GetViewports / GetEffectivePermissions / GetEffectiveAccess / Logout / GetPublicKey / BatchGetUsers / GetEffectiveDataScope / GetChildrenByParent)
- AuthMiddleware 注册 + Controller 改用 @Req() 注入(I4 裁决)
- JWT RS256 本地文件 + refresh token 轮换(I5 裁决)
- iam_student_guardians 表 + GetChildrenByParent RPC + GET /iam/children REST(I6 裁决)
- shared-ts Outbox 接入(I2 裁决)
- /iam/v1/* 前缀迁移(I7 裁决)+ 端点路径统一(I8 裁决)
- DB 驱动 PermissionGuard 基础(I3 裁决,废弃硬编码 ROLE_PERMISSIONS map)
- 回写 02 文档(ISSUE-051)
P2.2(P3 期间持续补,不阻塞批次 2/3):9. 三层角色模型(school_admin / teacher / student + 自定义角色)10. DataScope 6 级实现(ALL / SCHOOL / GRADE / CLASS / SUBJECT / SELF)11. 视口 4 层(admin / teacher / student / parent)+ getEffectivePermissions 12. 审计日志(user_audit_log 表 + 记录关键操作)13. 密码策略(强度 / 过期 / 重用限制)14. 单元测试 + 集成测试 15. Redis 缓存(I3 裁决完整实现)
批次 2 启动条件:仅依赖 P2.1 完成(gRPC 50052 + 8 RPC + GetChildrenByParent 已就绪),不依赖 P2.2。
理由:iam 实际工作量 26-27 天,批次 1 时间线 5-7 天严重不匹配。拆分 P2.1 / P2.2 保证关键路径不阻塞。
执行者:ai06 完成期限:P2.1 在批次 1 完成,P2.2 在 P3 期间持续补
3.3 ai10 P5 工作量分级(关联 ISSUE-052)
裁决:ai10 msg P5 实际工作量 14-15 天,批次 4 预估 7-10 天差距约 50%。采纳分级交付:
P5 Must Have(批次 4,10-12 天):
- proto 生成代码 + gRPC server 50056 框架搭建
- DB schema 建立(6 表扩展/新增)+ ES mapping + Redis bitmap schema
- 6 层架构骨架(Entry/Guard/App/Strategy/Domain/Data)+ getDb() + cuid2
- 8 gRPC RPC 实现 + 16 REST 端点实现
- 7 Kafka 消费方实现 + 3 发布事件 Outbox
- 4 ChannelStrategy 基础实现(InApp/Email/SMS/Push)
- /readyz + /healthz + /metrics + 优雅关闭 + OTel
P5 Should Have(批次 4 末期或 P6 初期补):8. 模板渲染完整实现 9. 静默时段 10. DLQ 完整实现 11. 三层幂等完整实现 12. 集成测试 + 端到端验证(含 push-gateway 联调)
理由:与 ai06 iam P2 同类问题,分级交付保证关键路径。
执行者:ai10 完成期限:Must Have 在批次 4 完成,Should Have 在 P6 初期补
3.4 各 AI 文档回写义务(ISSUE-028/032-ai15/034-ai15/036-ai13/051-ai06/053-ai02/063-ai14)
裁决:各 AI 在 coord 仲裁后 3 个工作日内(或对应批次启动前)完成回写:
| AI | 文档 | 回写内容 | 完成期限 |
|---|---|---|---|
| ai03 | teacher-bff 02 | 4 处 GetTeacherDashboardStats → GetTeacherDashboard(ISSUE-035) | 批次 1 启动前 |
| ai04 | student-bff 02 | B1 GraphQL + B2 gRPC + B8 DownstreamClient 回写(ISSUE-028) | 批次 2 启动前 |
| ai05 | parent-bff 02 | B1 GraphQL + B2 gRPC 回写 | 批次 3 启动前 |
| ai06 | iam 02 | I1-I8 裁决对齐 4 处 + §9 标注前移(ISSUE-051) | 批次 1 启动前 |
| ai09 | content 02 | 移除已裁决项 + ES 启用时机标注 | 批次 3 启动前 |
| ai10 | msg 02 | M2 软失败 + ISSUE-043 验证 + ISSUE-012 契约更新 | 批次 4 启动前 |
| ai02 | push-gateway 02 | ISSUE-053 topic + ISSUE-055 /readyz + ISSUE-056 设计决策记录 + ISSUE-058 Redis SET | 批次 4 启动前 |
| ai13 | teacher-portal 03 | 删除 §6 REST→GraphQL 演进策略(ISSUE-036) | 批次 1 启动前 |
| ai14 | student-portal 02 | F9 GraphQL + F7 权限点命名回写(ISSUE-063/064) | 批次 2 启动前 |
| ai15 | parent-portal 02 | F9 GraphQL + 删除"P4 用 REST 后续切 GraphQL"(ISSUE-032/034) | 批次 3 启动前 |
| ai16 | admin-portal 02 | ISSUE-044~048 仲裁结果回写 | 批次 5 启动前 |
回写验收:
- 回写完成后在 known-issues.md 工作经验日志追加记录
- coord 在批次验收时检查 02 文档与裁决一致性
- 不回写视为违反 coord-final-decisions §0.1 回写义务,coord 验收不通过
执行者:各 AI
3.5 ai03 P2 功能范围(关联 ISSUE-040)
裁决:明确 ai13 teacher-portal P2 功能范围:
P2 实现(依赖 iam + teacher-bff GraphQL schema):
- 登录 + 权限上下文
- Dashboard 框架(null 字段降级展示)
- 个人设置
- 班级列表(iam 数据)
- 学生列表(iam 数据)
P3 扩展(跟随 teacher-bff 调 core-edu):
- 课表 / 考勤 / 考试 / 作业
P4 扩展(跟随 teacher-bff 调 content/data-ana):
- 教材 / 题库 / 分析仪表盘
P5 扩展(跟随 teacher-bff 调 ai/msg):
- AI 助教 / 消息通知
规则:前端路由骨架 P2 一次性建立,但页面内容随 BFF 能力分阶段填充(属"跨阶段扩展例外")。
执行者:ai13
3.6 ai14 student-portal P3 功能范围(ISSUE-065)
裁决:明确 ai14 student-portal P3 功能范围:
P3 实现(7 页,依赖 iam + core-edu):
- dashboard / homework / exams / take / result / grades / my-schedule
P4 扩展(4 页,依赖 content + data-ana):
- textbooks / questions / diagnostic / weakness
P5 扩展(2 页,依赖 msg + ai):
- notifications / ai-chat
P4/P5 页面:设 <FeatureFlag> 占位(显示"功能开发中"提示页),避免用户访问 404。
coord 验收 ai14 P3 时检查:P3 范围 7 页全部可用 + P4/P5 页面有占位。
执行者:ai14
3.7 BFF 通知功能阶段归属(ISSUE-013/033/066)
裁决:BFF 通知功能统一推迟到 P5:
- P2-P4 阶段:BFF 不订阅 Kafka(B7 裁决),通知功能不实现
- P5 阶段:msg + push-gateway 就绪后,BFF 订阅 Kafka + 前端接入 push-gateway WebSocket/SSE
- parent-portal 通知偏好(ISSUE-033):
- P4 阶段:通知偏好设置页面 UI + 表单校验,偏好暂存前端 localStorage(降级方案),不调后端 API
- P5 阶段:parent-bff 接入 msg 服务 GraphQL mutation
updateNotificationPreferences,偏好持久化到 msg DB
- student-portal 通知中心(ISSUE-066):
- P3-P4:notifications route 设
<FeatureFlag>占位 - P5:实现通知中心页面 + WebSocket/SSE 接入 push-gateway
- P3-P4:notifications route 设
- P3-P4 降级方案:学生端可提供"手动刷新"(轮询 core-edu 查询最近作业/考试),但不作为正式通知功能
理由:B7 裁决 P2-P4 BFF 不订阅 Kafka 简化实现,通知功能推迟到 P5 统一启用。
执行者:ai03/ai04/ai05(BFF)+ ai13/ai14/ai15(前端)
4. P2 各批次启动前完成:服务依赖与时序
4.1 批次 0 完成信号机制(ISSUE-047)
裁决:
- coord 在 ai-work-orchestration.md §3.1 标注每项任务完成状态(✅ 已完成 / ⏳ 待办 / 🔄 进行中)
- 批次 0 全部 15 项任务完成后,coord 发布批次 1 启动公告(在 ai-work-orchestration.md §9 时间线末尾追加"批次 0 已完成,批次 1 启动")
- 建立"前置依赖就绪检查清单",coord 在批次 1/2/3/4/5 启动前逐项确认
- 批次 0 任务清单(最终 15 项):
- 0.1 arch:scan 更新
- 0.2 修订 coord-cross-review.md
- 0.3 补全 iam.proto 8 RPC
- 0.4 建立 shared-ts Outbox 工具包(含设计草案 + 实现)
- 0.5 补全 content.proto(QuestionService 等)
- 0.6 补全 msg.proto
- 0.7 补全 analytics.proto 扩展
- 0.8 补全 core_edu.proto(AttendanceService / GetClassesByTeacher / BatchGetClasses)
- 0.9 buf.gen.yaml 补 gRPC 插件
- 0.10 补全 events.proto(7 message 已完成)
- 0.11 analytics.proto 扩展(4 端 Dashboard + Warning + MasteryDistribution + SubscribeMasteryUpdate)
- 0.12 补全 push-gateway 相关 proto(如有)
- 0.13 补全 msg.proto(5 RPC + NotificationPreferenceService + NotificationTemplateService + 3 message)
- 0.14 建立 shared-go 包骨架(tracer/logger/jwks/env 4 模块)
- 0.15 ai13 建立 packages/ui-tokens + ui-components + hooks 骨架
执行者:coord(0.1-0.14)+ ai13(0.15) 完成期限:批次 0 全部完成后再启动批次 1
4.2 /internal/push 契约采纳(ISSUE-057/012)
裁决:
- coord 直接采纳 ai02 02 §4.2 作为第一版 /internal/push 契约("as-is"采纳)
- 仅在 ai10 提出异议时(如 msg 调用方需要 batch 接口 / 异步回调机制),coord 才调整契约
- coord 在批次 4 启动前公布"采纳 ai02 02 §4.2 作为第一版契约"的决定,避免重复仲裁
- 若 coord 决定调整,必须给出具体差异点(如新增字段、修改响应格式),ai02/ai10 按差异点调整
执行者:coord 完成期限:批次 4 启动前
4.3 Redis SET 心跳重建机制(ISSUE-058)
裁决:采纳 ai02 建议方案:
- ai02 02 §3.1 补充"Hub 启动时重建 Redis SET"机制:
- Hub 启动时遍历内存连接(userID),SADD 自己 instanceID 到
edu:push:online:<userID>+ EXPIRE 60s - 启动时清空 Redis 中本 instanceID 的旧成员(避免幽灵成员)
- Hub 启动时遍历内存连接(userID),SADD 自己 instanceID 到
- /readyz Redis 检查失败时仅告警不阻塞(与 ISSUE-055 协调),避免雪崩
- metrics 暴露
push_gateway_redis_set_rebuild_total监控重建次数 - 文档化"Redis 故障恢复后 60s 内在线状态可能短暂不一致",msg 服务调用方需容忍
online: false误判(msg 应继续尝试 HTTP /internal/push,由 push-gateway 返回真实在线状态)
执行者:ai02 完成期限:P5 启动前回写 02 文档
4.4 设计决策记录章节保留规则(ISSUE-056)
裁决:
- coord-final-decisions.md §7.2 回写义务表补充澄清:"设计决策记录章节(已被 coord 采纳的仲裁请求)保留,但正文需标注'coord 已采纳,见 coord-final-decisions P1/P5/P6',标题改为'设计决策记录:xxx'"
- ai02 02 §5.4 改名为"设计决策记录:gRPC vs HTTP 协议选型(coord 已采纳 P1)"
- ai02 02 §14.2 改名为"设计决策记录:SSE/断线重连范围(coord 已采纳 P5/P6)"
- 章节内容保留作为决策追溯依据,但删除"中间过渡方案"字样
- 其他 AI 的同类"过渡方案描述"(如 ai13 ISSUE-036、ai15 ISSUE-034)按此原则处理:删除过渡方案本身,保留设计决策记录
执行者:coord(§7.2 补充)+ ai02(02 文档回写)+ 其他 AI 同规则
4.5 iam /readyz 检查深度(ISSUE-029-ai11)
裁决:采纳 ai11 建议方案:
- coord 验收 iam P2 时强制检查 GetEffectiveDataScope RPC 已落地(不仅仅是 gRPC server 启用)
- data-ana /readyz 分两级检查:
- L1 ping iam 50052 端口可达(基础就绪,失败 ready=false)
- L2 调用 GetEffectiveDataScope 返回有效(深度就绪,失败 degraded=true)
执行者:ai11 实现 + coord 验收
5. P2 各批次启动前完成:工作归属裁决
5.1 admin-portal BFF 归属(ISSUE-044)
裁决:采纳方案 2(复用 teacher-bff):
- admin-portal 复用 teacher-bff 的 GraphQL endpoint,不新建 admin-bff 服务
- ai03 P2 预留 admin schema 命名空间(如
admin.*Query/Mutation) - coord 在批次 1 启动前仲裁 schema 第一版时纳入 admin 命名空间
- 004 §1.2 服务清单保持不变(无 admin-bff)
- ai16 回写 02 文档 §4.1:数据获取路径改为"复用 teacher-bff GraphQL endpoint"
理由:admin 操作低 QPS,无需独立 BFF 实例;减少 ai16 工作量。
执行者:ai03(预留 admin 命名空间)+ ai16(回写 02 文档)
5.2 admin-portal 错误码前缀(ISSUE-045)
裁决:
- G14 清单补充
ADMIN_前缀(合并 SCHOOL_ 入 ADMIN_,因学校设置属 admin 业务子域) - ORG 管理也归入 ADMIN_ 前缀(统一 admin 域)
- 错误码命名:
ADMIN_<RESOURCE>_<ERROR>(如ADMIN_SCHOOL_NOT_FOUND、ADMIN_ORG_DUPLICATE_NAME) - i18n key:
error.admin.*(对齐 F4 规范) - 写入 coord-final-decisions.md G14 补充条款
执行者:coord(G14 补充)+ ai16(实现)
5.3 admin-portal 权限点命名(ISSUE-046)
裁决:
- F7 允许服务前缀作为命名空间(避免不同域同名资源冲突,如
CONTENT_QUESTION_READvsCORE_EDU_QUESTION_READ) - 命名规则:
[<SERVICE>_]<RESOURCE>_<ACTION>[_<SCOPE>],SERVICE 可选 - admin-portal 权限点统一加
ADMIN_前缀(与错误码前缀对齐) - 跨服务资源(如调 iam 用户管理)保留 iam 前缀(
IAM_USER_READ),admin 自身资源用ADMIN_前缀 - admin-portal 调下游服务的权限点校验由下游服务负责(B3 裁决 BFF 豁免 @RequirePermission,admin-portal 作为 client 不做权限决策)
- 写入 coord-final-decisions.md F7 补充条款
执行者:coord(F7 补充)+ ai16(实现)
5.4 admin-portal GraphQL 客户端(ISSUE-047)
裁决:已在 §2.17 裁决,admin-portal 复用 Shell 暴露的 GraphQL client 单例。
执行者:ai13(Shell 暴露)+ ai16(消费)
5.5 admin-portal 审计日志归属(ISSUE-048)
裁决:X3 审计日志归属前置到 P6 启动前裁决:
- 审计日志归 iam(iam 已掌握用户/角色数据,审计事件天然属 iam 域)
- events.proto 补
AuditEventmessage:
message AuditEvent {
string event_id = 1;
string aggregate_id = 2;
string event_type = 3;
int64 occurred_at = 4;
string actor_user_id = 5;
string action = 6; // create / update / delete / login / logout
string resource_type = 7; // user / role / class / exam ...
string resource_id = 8;
string before_state = 9; // JSON string
string after_state = 10; // JSON string
string ip = 11;
string user_agent = 12;
string trace_id = 13;
map<string, string> metadata = 14;
}
- 新增 topic
edu.iam.audit.created(统一审计事件 topic,不按操作类型分) - admin-portal 作为 consumer 订阅
edu.iam.audit.created,写入 ClickHouse 审计表(或 MySQL 审计表) - admin-portal 8 个新 Kafka topic 重新评估:若审计归 iam,admin-portal 仅需 1 个 audit consumer topic,无需 8 个
- iam P2.2 扩展阶段补 AuditEvent 发布(user_audit_log 表 + 事件发布)
- events.proto 补 AuditEvent 在批次 0.10 完成
执行者:coord(proto + topic)+ ai06(iam 发布)+ ai16(admin-portal 消费)
6. 时间统筹总表(批次时间线最终调整)
6.1 批次时间线(最终版)
基于工作量分级裁决(§3.1-3.3),批次时间线最终调整如下:
| 批次 | 阶段 | AI 并行 | 时间线 | 关键交付 | 启动条件 |
|---|---|---|---|---|---|
| 批次 0 | coord 前置 | coord(0.1-0.14)+ ai13(0.15) | 3-5 天 | proto 契约 + shared-ts Outbox + shared-go + packages 骨架 | 本裁决发布后立即 |
| 批次 1 | P2 | ai01 + ai06 + ai03⟷ai13 | 7-10 天 | iam P2.1 + teacher-bff Must Have + teacher-portal P2 + Gateway 路由 | 批次 0 全部完成 |
| 批次 2 | P3 | ai08 + ai07 交接 + ai04⟷ai14 + ai03 扩展 | 7-10 天 | core-edu gRPC 50053 + student-bff + student-portal P3(7 页)+ teacher-bff P3 扩展 | 批次 1 P2.1 完成 + ai03 DownstreamClient 抽象就绪 |
| 批次 3 | P4 | ai09 + ai11 + ai05⟷ai15 + ai03/ai04 扩展 | 10-12 天 | content gRPC 50054 + data-ana gRPC 50055 + parent-bff + parent-portal P4 + teacher/student-bff P4 扩展 | 批次 2 完成 |
| 批次 4 | P5 | ai10⟷ai02 + ai12 + ai03 扩展 | 12-15 天 | msg gRPC 50056 + push-gateway + ai 服务 + teacher-bff P5 扩展 + 通知功能启用 | 批次 3 完成 |
| 批次 5 | P6 | ai16 + 持续优化 | 10-12 天 | admin-portal + 审计日志 + iam P2.2 补全 + 持续优化 | 批次 4 完成 |
总时间线:49-64 天(约 10-13 周)
6.2 批次 0 详细任务清单
| 任务 | 责任方 | 内容 | 完成信号 |
|---|---|---|---|
| 0.1 | coord | arch:scan 更新 | arch.db 已更新 |
| 0.2 | coord | 修订 coord-cross-review.md | 文档已更新 |
| 0.3 | coord | 补全 iam.proto 8 RPC | proto 文件已提交 |
| 0.4 | coord | 建立 shared-ts Outbox 工具包(含设计草案 + 实现) | packages/shared-ts/src/outbox/ 已建立 |
| 0.5 | coord | 补全 content.proto(QuestionService 等) | proto 文件已提交 |
| 0.6 | coord | 补全 msg.proto 基础 | proto 文件已提交 |
| 0.7 | coord | 补全 analytics.proto 基础 | proto 文件已提交 |
| 0.8 | coord | 补全 core_edu.proto(AttendanceService / GetClassesByTeacher / BatchGetClasses) | proto 文件已提交 |
| 0.9 | coord | buf.gen.yaml 补 gRPC 插件 | buf generate 可运行 |
| 0.10 | coord | 补全 events.proto(含 AuditEvent) | proto 文件已提交 |
| 0.11 | coord | analytics.proto 扩展(4 端 Dashboard + Warning + MasteryDistribution + SubscribeMasteryUpdate Stream RPC) | proto 文件已提交 |
| 0.12 | coord | 补全 push-gateway 相关 proto(如有) | proto 文件已提交 |
| 0.13 | coord | 补全 msg.proto(5 RPC + NotificationPreferenceService + NotificationTemplateService + 3 message) | proto 文件已提交 |
| 0.14 | coord | 建立 shared-go 包骨架(tracer/logger/jwks/env 4 模块) | packages/shared-go/ 已建立 |
| 0.15 | ai13 | 建立 packages/ui-tokens + ui-components + hooks 骨架 | 3 个 packages 已建立 |
6.3 批次 1 详细任务清单(P2)
| AI | 任务 | 时间线 | 关键交付 |
|---|---|---|---|
| ai01 | Gateway 路由配置(/iam/v1/* + /teacher/* + /parent/* 前缀) | 3-5 天 | Gateway 路由就绪 |
| ai06 | iam P2.1(gRPC + 8 RPC + AuthMiddleware + JWT RS256 + iam_student_guardians + shared-ts Outbox + /iam/v1/* 前缀 + DB 驱动 PermissionGuard 基础) | 7-10 天 | iam gRPC 50052 + 8 RPC 就绪 |
| ai03 | teacher-bff P2 Must Have(GraphQL + DownstreamClient + AuthMiddleware + /readyz + /healthz + pino + GlobalErrorFilter + 错误码 + ESM + cuid2) | 7-10 天 | teacher-bff GraphQL schema 第一版 + DownstreamClient 抽象 |
| ai13 | teacher-portal P2(client 改造 + MF shell + 共享组件抽取 + GraphQL Provider + packages 完善) | 7-10 天 | teacher-portal P2 可联调 |
批次 1 启动前 coord 仲裁:
- teacher-bff GraphQL schema 第一版(含 admin 命名空间)
- MF shell 暴露清单(含 GraphQL client 单例)
- /internal/push 契约(如批次 4 提前需要,可延后)
6.4 批次 2-5 启动前 coord 仲裁
| 批次 | 仲裁内容 | 完成期限 |
|---|---|---|
| 批次 2 | student-bff GraphQL schema 第一版 | 批次 2 启动前 |
| 批次 3 | parent-bff GraphQL schema 第一版 | 批次 3 启动前 |
| 批次 4 | /internal/push 契约(采纳 ai02 02 §4.2) | 批次 4 启动前 |
| 批次 5 | admin-portal schema 命名空间(复用 teacher-bff) | 批次 5 启动前 |
7. 各 AI 工作内容最终清单
7.1 ai01(api-gateway)
- 批次 1(P2):Gateway 路由配置(/iam/v1/* + /teacher/* + /parent/* 前缀)+ 接入 shared-go 包
- 批次 2-5:路由扩展(core-edu / content / data-ana / msg / ai 路由)+ 持续优化
7.2 ai02(push-gateway)
- 批次 0 等待期:复审 02 文档 + 回写 ISSUE-053/055/056/058
- 批次 4(P5):/internal/push + WebSocket + Redis Pub/Sub + Kafka 消费(可选)+ /readyz + /metrics + OTel + 多阶段 Dockerfile + slog + X-Internal-Token 重命名 + 集成测试
7.3 ai03(teacher-bff)
- 批次 1(P2):Must Have 13 项(见 §3.1)+ DownstreamClient 抽象 + admin schema 命名空间预留
- 批次 2-5:跨阶段扩展(core-edu / content / data-ana / msg / ai gRPC 调用)+ Should Have + Nice to Have 持续补
7.4 ai04(student-bff)
- 批次 0/1 等待期:回写 02 文档(B1/B2/B8)+ 起草 student-bff GraphQL schema 草案
- 批次 2(P3):student-bff P3(GraphQL + DownstreamClient 复用 + iam + core-edu gRPC)
- 批次 3-4:跨阶段扩展(content / data-ana gRPC)
- 批次 4:跨阶段扩展(msg / ai gRPC)+ 通知功能启用
7.5 ai05(parent-bff)
- 批次 0-2 等待期:回写 02 文档 + 起草 parent-bff GraphQL schema 草案
- 批次 3(P4):parent-bff P4(GraphQL + DownstreamClient 复用 + iam + core-edu gRPC)
- 批次 4:跨阶段扩展(data-ana gRPC)+ 通知功能启用
7.6 ai06(iam)
- 批次 0 等待期:回写 02 文档(I1-I8)+ 监控批次 0.3/0.4 完成
- 批次 1(P2.1):gRPC + 8 RPC + AuthMiddleware + JWT RS256 + iam_student_guardians + shared-ts Outbox + /iam/v1/* 前缀 + DB 驱动 PermissionGuard 基础
- 批次 2-5(P2.2 持续补):三层角色 + DataScope + 视口 + 审计日志 + 密码策略 + 测试
7.7 ai07(classes 交接)
- 批次 0:classes 黄金模板代码交接给 ai08
- 后续:无(ai07 已完成黄金模板工作)
7.8 ai08(core-edu)
- 批次 0 等待期:复审 02 文档 + 监控批次 0.8 完成
- 批次 2(P3):core-edu gRPC 50053 + AttendanceService 实现 + classes 代码交接 + Outbox + TOPIC_MAP 修订(edu.teaching.*)
- 批次 3-5:跨阶段扩展(如需)
7.9 ai09(content)
- 批次 0-2 等待期:复审 02 文档 + 移除已裁决项
- 批次 3(P4):content gRPC 50054 + QuestionService 完整实现 + Outbox + Neo4j Sync Worker + /readyz(MySQL + Neo4j + Kafka)
- 批次 4(P5):ES Projector 实现 + /readyz 扩展 ES 检查
7.10 ai10(msg)
- 批次 0-3 等待期:复审 02 文档 + 回写 ISSUE-042/043
- 批次 4(P5):msg gRPC 50056 + Must Have(gRPC + REST + Outbox + 基础 channel)+ Should Have(模板 + 静默 + DLQ + 完整幂等)
- 批次 5:Should Have 补全 + 集成测试
7.11 ai11(data-ana)
- 批次 0-2 等待期:复审 02 文档 + ClickHouse DDL 文件创建
- 批次 3(P4):data-ana gRPC 50055 + CDC 消费者 + ClickHouse 宽表 + /readyz(分两级检查 iam gRPC)
- 批次 4-5:跨阶段扩展(如需)
7.12 ai12(ai)
- 批次 0-3 等待期:复审 02 文档
- 批次 4(P5):ai 服务(ES 检索 + AI 备课 + 出题 + StreamChat)+ 接入 content/data-ana gRPC
7.13 ai13(teacher-portal)
- 批次 0(0.15):建立 packages/ui-tokens + ui-components + hooks 骨架
- 批次 1(P2):teacher-portal P2(client 改造 + MF shell + GraphQL Provider + 共享组件抽取)+ 03 文档回写
- 批次 2-5:跟随 teacher-bff 扩展页面
7.14 ai14(student-portal)
- 批次 0/1 等待期:回写 02 文档(F9 GraphQL + F7 权限点命名)+ 起草 client query 清单
- 批次 2(P3):student-portal P3(7 页:dashboard/homework/exams/take/result/grades/my-schedule)
- 批次 3:P4 扩展(4 页:textbooks/questions/diagnostic/weakness)
- 批次 4:P5 扩展(2 页:notifications/ai-chat)
7.15 ai15(parent-portal)
- 批次 0-2 等待期:回写 02 文档(F9 GraphQL + 删除"P4 用 REST 后续切 GraphQL")+ 起草 client query 清单
- 批次 3(P4):parent-portal P4(Dashboard + 孩子列表 + 考试/作业/成绩 + 通知偏好 UI 占位)
- 批次 4:P5 扩展(通知偏好持久化 + 通知中心)
7.16 ai16(admin-portal)
- 批次 0-4 等待期:回写 02 文档(ISSUE-044~048 仲裁结果)
- 批次 5(P6):admin-portal(用户/角色管理 + 学校设置 + 组织管理 + 审计日志消费)+ 复用 teacher-bff GraphQL endpoint
8. 总裁裁决执行检查清单
8.1 P0 立即执行(coord)
- 修正 port-allocation.md §5 iam 行(§1.1)
- 修正 004 §4.2 gRPC 启用矩阵(§1.2)
- 修正 004 §16.7.4 P4 清单补 QuestionService(§1.3)
- 修正 004 §16.7.5 P5 清单删 QuestionService(§1.4)
- 修订 004 §7.2 Kafka topic 表格(§1.5)
- 修正 coord-final-decisions.md + ai-work-orchestration.md 相对路径(§1.6)
- 在 issues.md §0.5 添加总裁裁决索引指针(§1.7)
8.2 P1 批次 0 启动前完成(coord + ai13)
- coord 完成 shared-ts Outbox 工具包设计 + 实现(§2.1,0.4)
- coord 建立 GraphQL schema 仲裁规范(§2.2)
- coord 补全 core_edu.proto AttendanceService(§2.5,0.8)
- coord 补全 analytics.proto 扩展(§2.10,0.11)
- coord 补全 events.proto AuditEvent(§5.5,0.10)
- coord 建立 shared-go 包骨架(§2.19,0.14)
- ai13 建立 packages 骨架(§2.18,0.15)
- coord 修订 004 §7.2 warning.triggered 注释(§2.11)
- coord 修正 coord-cross-review.md §6 #14 责任方(§2.5)
- coord 在 coord-final-decisions.md 补充 I1 双入口策略(§2.16)
- coord 在 coord-final-decisions.md 补充 F7 服务前缀规则(§5.3)
- coord 在 coord-final-decisions.md 补充 G14 ADMIN_ 前缀(§5.2)
- coord 在 coord-final-decisions.md §7.2 补充设计决策记录保留规则(§4.4)
8.3 P2 各批次启动前完成(各 AI)
- ai03 回写 teacher-bff 02(GetTeacherDashboard 命名,§3.4)
- ai04 回写 student-bff 02(B1/B2/B8,§3.4)
- ai06 回写 iam 02(I1-I8,§3.4)
- ai13 回写 teacher-portal 03(删除 REST→GraphQL,§3.4)
- ai14 回写 student-portal 02(F9/F7,§3.4)
- ai15 回写 parent-portal 02(F9/删除过渡方案,§3.4)
- ai02 回写 push-gateway 02(ISSUE-053/055/056/058,§3.4)
- ai10 回写 msg 02(ISSUE-042/043/012,§3.4)
- ai16 回写 admin-portal 02(ISSUE-044~048,§3.4)
8.4 P3 各阶段执行中持续(各 AI)
- 各 AI 按工作量分级执行(§3.1-3.3)
- 各 AI 按跨阶段扩展例外执行(§2.3)
- 各 AI 按回写义务执行(§3.4)
- coord 按批次验收检查(§8.1-8.3)
9. 未解决问题后续处理
9.1 待 P6 评估的问题(保留)
以下问题待 P6 阶段评估,不阻塞当前批次:
- ISSUE-014:admin-portal 8 个新 Kafka topic(若审计归 iam,仅需 1 个 audit consumer topic,见 §5.5)
- X3 审计日志归属:已前置裁决(§5.5),归 iam
- X6 httpOnly Cookie 迁移:P6 评估
- X7 其他 P6+ 事项:P6 评估
9.2 不再追溯的问题
以下问题已被本裁决覆盖,不再单独追溯:
- ISSUE-001 ~ ISSUE-014(coord 初始识别,已被 coord-final-decisions + 本裁决覆盖)
- ISSUE-015 ~ ISSUE-022(ai08 提请,已在 §1/§2 裁决)
- ISSUE-023 ~ ISSUE-025-ai09(ai09 提请,已在 §2.4/2.13/2.14 裁决)
- ISSUE-026 ~ ISSUE-030-ai11(ai11 提请,已在 §2.6/2.10/2.11/4.5 裁决)
- ISSUE-028 ~ ISSUE-031-ai04(ai04 提请,已在 §3.4 裁决)
- ISSUE-032 ~ ISSUE-036+059-ai03(ai03 提请,已在 §2.7/2.8/2.9/3.1 裁决)
- ISSUE-036 ~ ISSUE-041-ai13(ai13 提请,已在 §2.2/2.17/2.18/3.5 裁决)
- ISSUE-031 ~ ISSUE-035-ai15(ai15 提请,已在 §0.3/0.4/3.4 裁决)
- ISSUE-042 ~ ISSUE-043-ai10(ai10 提请,已在 §1.5/2.4 裁决)
- ISSUE-044 ~ ISSUE-048-ai16(ai16 提请,已在 §5.1-5.5 裁决)
- ISSUE-047 ~ ISSUE-052-ai06(ai06 提请,已在 §2.15/2.16/3.2/4.1 裁决)
- ISSUE-053 ~ ISSUE-058-ai02(ai02 提请,已在 §1.5/2.4/4.2/4.3/4.4 裁决)
- ISSUE-063 ~ ISSUE-066-ai14(ai14 提请,已在 §3.4/3.6/4.7 裁决)
10. 问题索引表(编号冲突映射)
由于 issues.md 存在严重编号冲突(见 §0.4),本表提供
ISSUE-XXX-<提请AI>格式的唯一定位。
| ISSUE 编号 | 提请 AI | 主题 | 裁决章节 |
|---|---|---|---|
| ISSUE-001 | coord | iam gRPC server 启用时机三处文档冲突 | §1.1/1.2 |
| ISSUE-002 | coord | shared-ts Outbox 工具包未列入 P2 整改清单 | §2.1 |
| ISSUE-003 | coord | 004 §4.2 gRPC 启用阶段矩阵与 B2 裁决冲突 | §1.2 |
| ISSUE-004 | coord | teacher-bff P2 "首次实现即 gRPC 调下游"与下游服务分阶段启用矛盾 | §2.3/2.8 |
| ISSUE-005 | coord | teacher-bff 跨阶段持续改造与"不分阶段"裁决原则矛盾 | §0.3/2.3 |
| ISSUE-006 | coord | student-bff P3 同样存在跨度过大问题 | §2.3 |
| ISSUE-007 | coord | BFF DownstreamClient 抽象回写 teacher-bff 的时间点 | §3.4 |
| ISSUE-008 | coord | teacher-portal P2 改造为 urql/apollo 的工作量 | §2.17/3.5 |
| ISSUE-009 | coord | parent-bff P4 依赖 iam.GetChildrenByParent | §3.2 |
| ISSUE-010 | coord | ai12 ai P5 调 content.QuestionService 的 proto 补全时机冲突 | §1.3/1.4 |
| ISSUE-011 | coord | ai12 ai P5 调 core-edu.ExamService.GetExam 的方向修正 | §7.12 |
| ISSUE-012 | coord | msg P5 调 push-gateway HTTP /internal/push 的时序协调 | §4.2 |
| ISSUE-013 | coord | BFF P2-P4 不订阅 Kafka,家长通知实时性如何保证 | §3.7 |
| ISSUE-014 | coord | admin-portal P6 + 8 个新 Kafka topic 时序 | §5.5/9.1 |
| ISSUE-015 | ai08 | port-allocation.md §3 与 §5 关于 iam gRPC 启用阶段冲突 | §1.1 |
| ISSUE-016 | ai08 | 004 §16.7.4 P4 清单未列 content QuestionService | §1.3/1.4 |
| ISSUE-017 | ai08 | 14 个 issues 状态字段未回填 coord 裁决 | §0.4/9.2 |
| ISSUE-018 | ai08 | shared-ts Outbox 工具包设计未明确 | §2.1 |
| ISSUE-019 | ai08 | GraphQL schema 第一版仲裁机制未明确 | §2.2 |
| ISSUE-020 | ai08 | BFF 跨阶段扩展例外的验收标准未明确 | §2.3 |
| ISSUE-021 | ai08 | "不分阶段"原则与"批次时间线"表述易混淆 | §0.3 |
| ISSUE-022 | ai08 | core-edu AttendanceService proto 补全责任方不明 | §2.5 |
| ISSUE-023-ai09 | ai09 | content /readyz 检查项与 P5 ES 引入的时序冲突 | §2.4 |
| ISSUE-024-ai09 | ai09 | content ES Projector 实现位置未明确 | §2.14 |
| ISSUE-025-ai09 | ai09 | Neo4j 知识图谱同步是否属于"派生数据事件"豁免 Outbox | §2.13 |
| ISSUE-026-ai11 | ai11 | ClickHouse DDL 目录归属不明 | §2.12 |
| ISSUE-027-ai11 | ai11 | analytics.proto 扩展交付时间不明确 | §2.10 |
| ISSUE-028-ai11 | ai11 | warning.triggered topic 登记状态不明确 | §2.11 |
| ISSUE-029-ai11 | ai11 | data-ana /readyz 检查 iam gRPC 依赖落地验证 | §4.5 |
| ISSUE-030-ai11 | ai11 | 降级模式在 ActionState 信封中的表达方式 | §2.6 |
| ISSUE-028-ai04 | ai04 | ai04 02 文档与 coord B1+B2 裁决冲突需回写 | §3.4 |
| ISSUE-029-ai04 | ai04 | ai04 P3 启动前置依赖确认 | §4.1/6.1 |
| ISSUE-030-ai04 | ai04 | ai04⟷ai14 student-bff GraphQL schema 第一版仲裁时机 | §2.2 |
| ISSUE-031-ai04 | ai04 | issues.md ISSUE-024/025 编号冲突 | §0.4 |
| ISSUE-031-ai15 | ai15 | coord-final-decisions.md + ai-work-orchestration.md 相对路径错误 | §1.6 |
| ISSUE-032-ai03 | ai03 | B2 裁决 P2 阶段 teacher-bff Dashboard Query Resolver 实现方式 | §2.8 |
| ISSUE-033-ai03 | ai03 | B4 越权防御校验 teacherId 与班级关系在 P2 阶段实现方式 | §2.9 |
| ISSUE-034-ai03 | ai03 | G2 /readyz 检查全部下游依赖在 P2 阶段不可行 | §2.4 |
| ISSUE-035-ai03 | ai03 | §5.2 接口命名 GetTeacherDashboard 需 ai03 回写 02 文档 | §3.4 |
| ISSUE-036-ai03 | ai03 | ai03 P2 工作量激增 | §3.1 |
| ISSUE-059 | ai03 | BFF_TEACHER_FORBIDDEN_RESOURCE vs BFF_TEACHER_PERMISSION_DENIED 错误码语义区分 | §2.7 |
| ISSUE-032-ai15 | ai15 | ai15 parent-portal API 契约 REST 假设与 F9 GraphQL 裁决冲突 | §3.4 |
| ISSUE-033-ai15 | ai15 | ai15 parent-portal 通知偏好 P4 落地与 B7 裁决冲突 | §3.7 |
| ISSUE-034-ai15 | ai15 | ai15 parent-portal §476 "P4 用 REST 后续切 GraphQL"违反"不分阶段"原则 | §3.4 |
| ISSUE-035-ai15 | ai15 | issues.md 文件结构严重混乱 | §0.4 |
| ISSUE-036-ai13 | ai13 | ai13 03-long-term-architecture.md §6 "REST→GraphQL 演进策略"与 F9 裁决冲突 | §3.4 |
| ISSUE-037-ai13 | ai13 | ai13 与 ai03 的 GraphQL schema 契约协调机制未明确 | §2.2 |
| ISSUE-038-ai13 | ai13 | MF 暴露 AppShell 整体是否包含 GraphQL client 单例未明确 | §2.17 |
| ISSUE-039-ai13 | ai13 | F8 ai13 维护 packages 的建立时机与依赖未明确 | §2.18 |
| ISSUE-040-ai13 | ai13 | ai13 teacher-portal P2 功能范围与下游服务启用阶段的关系未明确 | §3.5 |
| ISSUE-041-ai13 | ai13 | 仲裁评估总结 | §9.2 |
| ISSUE-042-ai10 | ai10 | M2 msg /readyz 强依赖 PushGateway 与 P5 同批次启动时序冲突 | §2.4 |
| ISSUE-043-ai10 | ai10 | 004 §7.2 表格 edu.notification.events 与 §16.3.2 + G16 裁决不同步 | §1.5 |
| ISSUE-044-ai16 | ai16 | admin-portal BFF 归属不明 | §5.1 |
| ISSUE-045-ai16 | ai16 | admin-portal 错误码前缀缺失 | §5.2 |
| ISSUE-046-ai16 | ai16 | admin-portal 权限点命名与 F7 规范的契合度 | §5.3 |
| ISSUE-047-ai16 | ai16 | admin-portal GraphQL 客户端复用 Shell 还是独立引入 | §2.17/5.4 |
| ISSUE-048-ai16 | ai16 | admin-portal 审计日志与 iam 审计事件归属耦合 | §5.5 |
| ISSUE-047-ai06 | ai06 | 批次 0 强阻塞 ai06 iam P2 启动 | §4.1 |
| ISSUE-048-ai06 | ai06 | I7 API 版本化 /iam/v1/* 破坏性变更跨服务协调 | §2.15 |
| ISSUE-049-ai06 | ai06 | gRPC 与 REST 双入口实现策略未明确 | §2.16 |
| ISSUE-050-ai06 | ai06 | shared-ts Outbox 工具包 API 契约未明确 | §2.1 |
| ISSUE-051-ai06 | ai06 | 02-architecture-design.md 与 I1-I8 裁决对齐回写义务 | §3.4 |
| ISSUE-052-ai06 | ai06 | iam P2 工作量评估与批次时间线不匹配 | §3.2 |
| ISSUE-053-ai02 | ai02 | G16 Kafka topic 命名规则与 push-gateway 02 §5.1 消费 topic 不一致 | §1.5 |
| ISSUE-054-ai02 | ai02 | shared-go 共享包建立时机与责任方未在批次规划中明确 | §2.19 |
| ISSUE-055-ai02 | ai02 | G2 /readyz "全部下游依赖"对 push-gateway Kafka 可选消费的适用性 | §2.4 |
| ISSUE-056-ai02 | ai02 | 02 文档 §5.4/§14.2 仲裁请求章节删除会丢失设计决策追溯 | §4.4 |
| ISSUE-057-ai02 | ai02 | ISSUE-012 /internal/push 契约仲裁前置与 02 §4.2 已有定义重复 | §4.2 |
| ISSUE-058-ai02 | ai02 | push-gateway 在线状态 Redis SET 心跳续期与 G2 /readyz 检查的耦合 | §4.3 |
| ISSUE-063-ai14 | ai14 | ai14 student-portal 02 REST 假设与 F9/B1 GraphQL 裁决冲突 | §3.4 |
| ISSUE-064-ai14 | ai14 | F7 权限点命名风格 ai14 文档与裁决不一致 | §3.4 |
| ISSUE-065-ai14 | ai14 | student-portal P3 功能范围受限 | §3.6 |
| ISSUE-066-ai14 | ai14 | student-portal 通知功能推迟到 P5 | §3.7 |
11. 裁决效力
11.1 裁决生效
本文件自发布之日起生效,覆盖以下文档的冲突条款:
coord-final-decisions.md(80+ 项裁决保持有效,本文件为其补充 + 澄清)ai-work-orchestration.md(批次时间线以本文件 §6 为准)issues.md(所有问题状态转为"总裁已裁决")
11.2 裁决变更
本文件的裁决变更需总裁(用户)再次确认。coord 无权单方面变更。
11.3 裁决执行
- coord:负责 P0 立即执行项(§8.1)+ P1 批次 0 启动前完成项(§8.2)+ 批次验收
- 各 AI:负责 P2 各批次启动前完成项(§8.3)+ P3 各阶段执行中持续项(§8.4)
本文件为总裁最终裁决,所有 AI 必须遵守。