docs: ai 协作文档体系重构与多 ai 仲裁结果落地

1.AI 协作文档体系重构(objections/worklines/contracts+matrix.md)

2.coord 仲裁文档(final-decisions/cross-review/final-rulings/orchestration)

3.各服务 01/02 文档补全

4.共享包初始化(shared-ts/shared-go/hooks/ui-components/ui-tokens)

5.Proto 契约补全

6.004 架构影响地图更新

7.端口分配表

8.设计规格文档
This commit is contained in:
SpecialX
2026-07-10 12:58:22 +08:00
parent 2a2a56f541
commit faaaf29f67
120 changed files with 23201 additions and 2 deletions

View File

@@ -0,0 +1,287 @@
# Coord 最终方案强制裁决
> 版本1.0
> 日期2026-07-09
> 决策者coord经用户确认
> 适用范围Edu 项目全部 16 份 AI 设计文档ai01-ai16
> 关联文档:[004 架构影响地图 §16](./004_architecture_impact_map.md)、[ai-allocation.md](./ai-allocation.md)、[project_rules.md](../../.trae/rules/project_rules.md)
---
## 0. 裁决原则
用户反馈:**"前面简略实现后面要重写,完全没必要,直接使用最好的方式工作"**。
各 AI 设计文档中存在大量"P2 简化 → P3 重构 → P4 再重构"的渐进式过渡方案导致前期代码后期必废弃。coord 裁决如下:
### 0.1 强制覆盖声明
- **本文档 > 各 AI 设计文档**:凡本文档列出的裁决项,各 AI 设计文档中与之冲突的"中间过渡方案"一律作废,**直接采用最终方案**
- **不分阶段**:最终方案在服务首次落地时即采用,不得以"阶段未到"为由先实现简化版
- **回写义务**:各 AI 收到本文档后,必须在 3 个工作日内回写自己的 02-architecture-design.md删除所有"中间过渡方案"描述,对齐最终方案
### 0.2 裁决依据
- 用户明确指示"直接使用最好的方式"
- project_rules.md §3.1 已规定企业级规范(如 Dockerfile 多阶段、Zod 验证、GlobalErrorFilter无理由分阶段
- 黄金模板 services/classes/ 已实现全部最终方案,其他服务对齐即可
---
## 1. 通用裁决(适用全部服务)
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 | 影响服务 |
| --- | --------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| G1 | **Dockerfile** | "P3 重构"、"P5 重构"、"待落地" | **首次实现即多阶段构建**builder + runtime | 全部 |
| G2 | **/readyz 探针** | "P2 仅返回 ok"、"P3+ 补下游探针" | **首次实现即检查全部下游依赖**DB SELECT 1 / Redis PING / Kafka 连接 / gRPC 下游可达) | 全部 |
| G3 | **/healthz** | "P2 改造" | **首次实现即 liveness 探针** | 全部 |
| G4 | **Logger** | "待引入 slog"、"console.log → P3 修复" | **首次实现即结构化日志**TS pino / Go slog / Python structlog禁止 console.log | 全部 |
| G5 | **Metrics** | "自定义业务指标待实现" | **首次实现即 /metrics 端点 + 基础业务指标** | 全部 |
| G6 | **Tracer** | "资源属性待补"、"span 待补" | **首次实现即 OTel SDK + OTLP exporter + 完整资源属性 + 全链路 span** | 全部 |
| G7 | **Zod 验证** | "P2 补全"、"P3 实施中"、"部分 → P4 全 parse" | **Controller 层首次实现即全量 schema.parse(body/query/params)** | 全部 TS |
| G8 | **GlobalErrorFilter** | "待落地"、"P4+ 对齐 ActionState" | **首次实现即注册 GlobalErrorFilter + 响应信封严格对齐 ActionState 结构** | 全部 |
| G9 | **优雅关闭** | "P2 补全" | **首次实现即 SIGTERM → app.close() → shutdownTracer(),按序关闭 HTTP→DB→Redis→Kafka** | 全部 |
| G10 | **DB 连接模式** | "const db vs getDb()" | **统一 getDb() 函数**(对齐 classes 黄金模板) | 全部 TS 持 DB 服务 |
| G11 | **ID 策略** | "cuid2 vs randomUUID" | **统一 cuid2**(对齐 classes 黄金模板) | 全部 TS 持 DB 服务 |
| G12 | **ESM import** | 缺 .js 后缀 | **所有相对 import 带 .js 后缀**NestJS ESM 模式) | 全部 TS |
| G13 | **import type** | 混用 | **仅用于类型的导入必须 import type** | 全部 TS |
| G14 | **错误码前缀** | api-gateway 无前缀 | **每个服务错误码必须用服务名大写前缀**GW_/IAM_/CORE_EDU_/CONTENT_/MSG_/DATA_ANA_/AI_/PUSH_/BFF_TEACHER_/BFF_STUDENT_/BFF_PARENT_/CLASSES_ | 全部 |
| G15 | **错误码子前缀** | 保留 EXAMS_/HOMEWORK_/GRADES_ | **统一用聚合域前缀 CORE_EDU_***,禁止子前缀 | 前端 + core-edu |
| G16 | **Kafka topic 命名** | edu.notification.events 抽象名 | **edu.\<domain>.\<aggregate>.\<action>** 具体动作(如 edu.notification.sent | 全部 |
| G17 | **proto 包名** | 不一致 | **next_edu_cloud.\<domain>.v1** | 全部 |
---
## 2. BFF 层专项裁决teacher-bff / student-bff / parent-bff
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| B1 | **API 风格** | "P2 REST → P4 GraphQL"、"P3 REST → P4+ GraphQL" | **P2 起直接 GraphQL**GraphQL Yoga + DataLoader |
| B2 | **对下游通信** | "P2 HTTP fetch → P3+ gRPC"、"P3 HTTP → P3+ gRPC" | **首次实现即 gRPC 调用下游**iam/core-edu/content/data-ana/msg/ai 全部 gRPC |
| B3 | **权限装饰器** | "BFF 加 @RequirePermission"、"待仲裁" | **BFF 豁免 @RequirePermission**(权限由 Gateway JWT + 下游服务负责BFF 仅校验 x-user-id 存在 |
| B4 | **越权防御** | "仅 teacher-bff 透传"、"student-bff 待仲裁" | **全部 BFF 强制自我越权防御**student-bff 比对 userId、parent-bff 校验 childId 绑定列表、teacher-bff 校验 teacherId 与班级关系 |
| B5 | **错误码前缀** | "STUDENT_BFF_ vs BFF_STUDENT_" | **BFF_TEACHER\_ / BFF_STUDENT\_ / BFF_PARENT_**(统一 BFF_ 前缀) |
| B6 | **缓存策略** | "不缓存 vs Redis 短缓存" | **Redis 5-30s 短缓存**(对齐 004 §6.2 BFF 混合读策略) |
| B7 | **Kafka 订阅** | "P3 评估"、"P5 评估" | **P2-P4 不订阅 Kafka**仅同步聚合P5 push-gateway 落地后再订阅 |
| B8 | **DownstreamClient 抽象** | "是否回写 teacher-bff" | **回写 teacher-bff**,作为 BFF 模式 v2 标准抽象3 个 BFF 统一使用 |
---
## 3. 业务服务专项裁决
### 3.1 iamai06
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| I1 | **gRPC server** | "P2 仅 REST → P3 启用 gRPC" | **P2 即启用 gRPC server 50052**,同时暴露 REST + gRPC |
| I2 | **Outbox** | "iam 自建 → core-edu 落地后回写 shared-ts" | **直接建 shared-ts Outbox 工具包**iam 首次实现即用 |
| I3 | **PermissionGuard** | "本地 ROLE_PERMISSIONS map → DB 驱动" | **首次实现即 DB 驱动 + Redis 缓存**,废弃本地 map |
| I4 | **AuthMiddleware** | "P2 不注册 → Controller 直读 header" | **首次实现即注册 AuthMiddleware**Controller 通过 @Req() 获取用户上下文 |
| I5 | **JWT 密钥** | "P2 本地文件 → P6 Vault" | **P2 本地文件**IAM_PRIVATE_KEY_PATH / IAM_PUBLIC_KEY_PATHP6 迁 Vault 单列后续 |
| I6 | **家长-学生关联** | "接口缺失 → P3 补" | **P2 即补全**iam_student_guardians 表 + GetChildrenByParent RPC + GET /iam/children RESTP0 阻塞 parent-bff |
| I7 | **API 版本化** | "待 coord 审查" | _*采用 /iam/v1/* 前缀_*Gateway 同步调整 |
| I8 | **iam 端点路径** | /iam/permissions/effective vs /iam/effective-permissions | **统一 GET /iam/permissions/effective**RESTful 资源路径风格) |
### 3.2 core-eduai08
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ----------------------------------------- | -------------------------------------- | -------------------------------------------------------------------- |
| C1 | **classes 合并** | "P3 初期 vs P3 末期" | **P3 开始前直接合并**classes 代码迁移到 core-educlasses 服务下线 |
| C2 | **gRPC server** | "P3 启用" | **P3 首次实现即启用 gRPC server 50053** |
| C3 | **Kafka console.log** | "P3 修复" | **首次实现即用 logger.info**,禁止 console.log |
| C4 | **AttendanceService** | "待 coord 补 proto" | **P3 首次实现即补全 proto + 实现** |
| C5 | **GetClassesByTeacher / BatchGetClasses** | "待新增" | **P3 首次实现即补全** |
| C6 | **排课 room_id** | "P3 实现 vs 预留 vs P6+" | **P3 预留字段**(不实现逻辑,但 schema 含字段) |
| C7 | **成绩计算公式** | "scope 优先级待定" | **class > subject > school**(越细粒度优先) |
| C8 | **作业 grace_period** | "0 秒 vs 300 秒" | **默认 300 秒**5 分钟宽限) |
| C9 | **schema 强制校验** | "P3 JSON Schema vs 文档约束" | **P3 仅文档约束**P6+ 引入 schema registry |
| C10 | **exam.submitted 事件** | "包含完整 answers vs 仅 submission_id" | **仅含 submission_id**(避免事件过大) |
| C11 | **archived 考试** | "物理迁移 vs 软删除 vs P6+" | **仅软删除**is_archived 字段) |
### 3.3 contentai09
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------- | -------------------- | ------------------------------------------------ |
| N1 | **gRPC server** | "gRPC 待实现" | **P4 首次实现即启用 gRPC server 50054** |
| N2 | **/readyz** | "仅 DB → P4 多依赖" | **首次实现即检查 DB/Neo4j/Kafka** |
| N3 | **QuestionService** | "P5 阻塞待补 proto" | **P4 即补全 QuestionService proto**(不等到 P5 |
| N4 | **ErrorFilter** | "错误响应结构待对齐" | **首次实现即对齐 ActionState** |
| N5 | **ChapterService** | "缺 GetChapter" | **P4 首次实现即补全** |
### 3.4 msgai10
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | --------------------- | --------------------------- | ----------------------------------------------------- |
| M1 | **gRPC server** | "gRPC 待实现" | **P5 首次实现即启用 gRPC server 50056** |
| M2 | **/readyz** | "仅 DB → P5 多依赖" | **首次实现即检查 DB/ES/Redis/Kafka/PushGateway** |
| M3 | **ZodError** | "未处理 → P5 处理" | **首次实现即处理 ZodError 分支** |
| M4 | **调用 push-gateway** | "gRPC PushService.Push" | **HTTP POST /internal/push**coord 仲裁豁免 gRPC |
| M5 | **事件 topic** | "edu.teaching.assignment.*" | **edu.teaching.homework.***(与 core-edu 发布方一致) |
### 3.5 data-anaai11
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------- |
| D1 | **ErrorFilter** | "v2 对齐 ActionState" | **首次实现即对齐 ActionState** |
| D2 | **Dockerfile** | "v2 设计多阶段" | **首次实现即多阶段** |
| D3 | **ClickHouse DDL** | "待 coord 建目录" | **直接建 infra/clickhouse/ddl/** |
| D4 | **analytics.proto 扩展** | "待 coord 审议" | **P4 即补全**4 端 Dashboard + Warning + MasteryDistribution + SubscribeMasteryUpdate Stream RPC |
| D5 | **warning.triggered topic** | "待 coord 登记" | **已登记**004 §7.2 + events.proto MasteryEvent |
### 3.6 aiai12
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ---------------------- | ------------------------- | ------------------------------------------------------------------------------ |
| A1 | **ErrorFilter** | "待对齐" | **首次实现即对齐 ActionState** |
| A2 | **Dockerfile** | "实现阶段需新增" | **首次实现即多阶段** |
| A3 | **gRPC 端口** | "待 coord 补登" | **已补登 50058**(见 infra/port-allocation.md |
| A4 | **ai.proto 补全** | "待 coord" | **P5 首次实现即补全** GenerateLessonPlan / StreamGenerateQuestion |
| A5 | **AIUsageEvent proto** | "待 coord" | **已补全** events.proto |
| A6 | **Prompt 模板存储** | "P5 YAML / P6+ DB" | **P5 直接用 DB 存储**(避免后期迁移) |
| A7 | **备课工作流** | "P5 Redis / P6+ Temporal" | **P5 用 FastAPI BackgroundTasks + Redis**Temporal 引入成本高P6+ 单独评估) |
| A8 | **多模态** | "P5 文本 / P6+ 多模态" | **P5 仅文本**proto v2 预留字段 |
### 3.7 push-gatewayai02
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------ | ---------------------------- | ----------------------------------------------------------------- |
| P1 | **gRPC** | "备选 gRPC PushService" | **彻底删除 gRPC 设计**,纯 HTTP + WebSocketcoord 仲裁豁免) |
| P2 | **X-Internal-Key** | "→ X-Internal-Token P5 立即" | **首次实现即 X-Internal-Token**(环境变量 INTERNAL_API_TOKEN |
| P3 | **Dockerfile** | "P5 重构" | **首次实现即多阶段** |
| P4 | **slog** | "待引入" | **首次实现即用 slog** |
| P5 | **SSE 降级** | "P7+ 考虑" | **本期仅 HTTP 长轮询预留**SSE 不实现 |
| P6 | **断线重连** | "本期仅协议预留" | **本期仅协议预留**session_id + last_seq 字段P6 实现补推逻辑 |
### 3.8 api-gatewayai01
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | -------------------- | ------------------------------------------- | ----------------------------------------------------- |
| W1 | **错误码前缀** | "无前缀" | **GW_***GW_UNAUTHORIZED 等) |
| W2 | **错误信封** | "recovery/ratelimit/circuit-breaker 待整改" | **首次实现即对齐 ActionState** |
| W3 | **slog** | "待引入" | **首次实现即用 slog** |
| W4 | **/readyz** | "待重构" | **首次实现即真实健康检查**(轮询下游 /healthz |
| W5 | **业务 metrics** | "待实现" | **首次实现即基础业务指标**(请求量/延迟/错误率/熔断) |
| W6 | **tracer 资源属性** | "待补" | **首次实现即完整**version/env/host |
| W7 | **DevMode 防护** | "P1 待办" | **首次实现即生产防护**DEV_MODE 仅非生产环境生效) |
| W8 | **per-服务实例熔断** | "P6 待办" | **保持共享 downstream 熔断**per-实例 P6 单独评估 |
---
## 4. 前端 4 portal 专项裁决
| # | 过渡项 | 禁止的中间方案 | 强制最终方案 |
| --- | ------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| F1 | **admin-portal 端口** | 3003 / 3000 / 4003 三处矛盾 | **统一 4003** |
| F2 | **admin-portal MF 配置** | teacher_app@localhost:3000 | **teacher_app@localhost:4000** |
| F3 | **Web Vitals** | FID vs INP 混用 | **统一 INP**CWV 2024 标准) |
| F4 | **i18n key 命名** | bff.error / bffTeacher.error / bffStudent.error 混用 | **统一 error.\<service>.\<code_snake>**(如 error.iam.invalid_credentials、error.bffTeacher.validation_error |
| F5 | **错误码子前缀** | parent-portal 保留 GRADES_/HOMEWORK_ | **统一删除子前缀**,用 CORE_EDU_* |
| F6 | **iam 权限端点** | /iam/permissions/effective vs /iam/effective-permissions | **统一 /iam/permissions/effective** |
| F7 | **权限点命名风格** | TEACHER_DASHBOARD_VIEW / STUDENT_DASHBOARD_READ / GRADES_READ_CHILD 混用 | **统一 \<RESOURCE>\_\<ACTION>**(如 DASHBOARD_VIEW、EXAM_READ、GRADE_READ数据范围用后缀 _OWN/_CHILD如 GRADE_READ_CHILD |
| F8 | **packages 归属** | "ai07/ai13 维护 vs coord 维护" | **ai13 维护 ui-tokens/ui-components/hookscoord 仅维护 shared-ts/contracts** |
| F9 | **GraphQL vs REST** | "P2-P6 REST未来切 GraphQL" | **P2 起 BFF 用 GraphQL前端用 urql/apollo** |
| F10 | **MF 暴露粒度** | "AppShell 整体 vs 细粒度" | **暴露 AppShell 整体**,各 Remote 自行决定内部布局 |
| F11 | **teacher-portal 归属** | "004 §15.1 写 ai07ai-allocation §3.2 写 ai13" | **ai13 负责 teacher-portal**ai07 负责 classes 黄金模板) |
| F12 | **localStorage token** | "P6 评估迁移 httpOnly Cookie" | **P2 用 localStorage**httpOnly Cookie + CSRF Token P6 单独评估) |
---
## 5. 跨服务契约裁决(一次性补全,不分阶段)
### 5.1 proto 契约补全coord 负责P2 启动前全部就位)
| proto 文件 | 待补内容 | 阻塞阶段 | 完成期限 |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| events.proto | ✅ 已补全UserEvent/RoleEvent/NotificationEvent/MasteryEvent/AIUsageEvent/KnowledgePointEvent/QuestionEvent | — | 已完成 |
| iam.proto | GetViewports / GetEffectivePermissions / GetEffectiveAccess / Logout / GetPublicKey / BatchGetUsers / GetEffectiveDataScope / GetChildrenByParent | P2 | P2 启动前 |
| core_edu.proto | AttendanceService.* / GetClassesByTeacher / BatchGetClasses | P3 | P3 启动前 |
| content.proto | ChapterService.GetChapter / QuestionService.* / TextbookService.ListTextbooks 补全 | P4 | P4 启动前 |
| analytics.proto | GetTeacherDashboard / GetStudentDashboard / GetParentDashboard / GetAdminDashboard / GetWarnings / GetMasteryDistribution / SubscribeMasteryUpdate (stream) | P4 | P4 启动前 |
| ai.proto | GenerateLessonPlan / StreamGenerateQuestion / 字段扩展 | P5 | P5 启动前 |
| msg.proto | BatchSendNotification / GetUnreadCount / BatchMarkAsRead / MarkAllAsRead / RecallNotification + NotificationPreferenceService + NotificationTemplateService + 3 个 message | P5 | P5 启动前 |
### 5.2 接口命名统一
| 调用方 | 被调方 | 统一命名 | 说明 |
| ----------------- | ------------ | ------------------------------------------------------------ | ---------------------------- |
| core-edu | content | **KnowledgeGraphService.GetPrerequisites / GetLearningPath** | 禁用 ContentService 命名 |
| teacher-bff | data-ana | **GetTeacherDashboard**(无 Stats 后缀) | 统一命名 |
| msg / student-bff | push-gateway | **HTTP POST /internal/push**body 含 user_id | 豁免 gRPC |
| ai | core-edu | **ExamService.GetExam** | 方向ai 调 core-edu非反向 |
### 5.3 gRPC server 启用时机
| 服务 | gRPC 端口 | 启用时机 | 说明 |
| ------------ | --------- | --------------- | ---------------------------------- |
| iam | 50052 | **P2** | 首次实现即启用(覆盖"P2 仅 REST" |
| core-edu | 50053 | **P3** | 首次实现即启用 |
| content | 50054 | **P4** | 首次实现即启用 |
| data-ana | 50055 | **P4** | 首次实现即启用 |
| msg | 50056 | **P5** | 首次实现即启用 |
| ai | 50058 | **P5** | 首次实现即启用 |
| push-gateway | — | **不启用** | 豁免 gRPC |
| BFF3 个) | — | **不暴露 gRPC** | 仅对下游走 gRPC |
---
## 6. 待 P6+ 单独评估事项(不阻塞当前阶段)
以下事项不属于"中间过渡方案",属于"未来扩展",保持原状:
| # | 事项 | 评估时机 |
| --- | ------------------------------------------------------------------- | --------- |
| X1 | ai 发布 edu.insight.ai.generated / feedback / workflow 3 个新 topic | P6+ |
| X2 | admin-portal 8 个新 Kafka topic + events.proto message | P6 实施时 |
| X3 | admin-portal 审计日志/安全事件归属iam vs audit-service | P6 |
| X4 | ai 备课工作流迁移 Temporal | P6+ |
| X5 | ai Prompt 模板 DB 存储迁移(已在 A6 裁决 P5 直接用 DB | — |
| X6 | admin-portal Grafana/Jaeger iframe 嵌入 | P6 |
| X7 | teacher-portal localStorage → httpOnly Cookie 迁移 | P6 |
| X8 | iam JWT 密钥迁移 Vault | P6 |
| X9 | api-gateway per-服务实例熔断 | P6 |
| X10 | schema registry 引入events.proto 强制校验) | P6+ |
---
## 7. 各 AI 回写义务
各 AI 收到本文档后,必须执行以下回写:
### 7.1 回写内容
1. 删除自己 02-architecture-design.md 中所有"中间过渡方案"描述
2. 对齐本文档的最终方案
3. 更新 §8 风险与假设(移除已裁决项)
### 7.2 回写期限
| AI | 服务 | 回写期限 | 阻塞阶段 |
| ---- | -------------- | ---------------------- | -------- |
| ai01 | api-gateway | P2 启动前 | — |
| ai02 | push-gateway | P5 启动前 | — |
| ai03 | teacher-bff | **P2 启动前** | P2 |
| ai04 | student-bff | P3 启动前 | — |
| ai05 | parent-bff | P4 启动前 | — |
| ai06 | iam | **P2 启动前** | P2 |
| ai07 | classes | 已是黄金模板,无需回写 | — |
| ai08 | core-edu | P3 启动前 | — |
| ai09 | content | P4 启动前 | — |
| ai10 | msg | P5 启动前 | — |
| ai11 | data-ana | P4 启动前 | — |
| ai12 | ai | P5 启动前 | — |
| ai13 | teacher-portal | **P2 启动前** | P2 |
| ai14 | student-portal | P3 启动前 | — |
| ai15 | parent-portal | P4 启动前 | — |
| ai16 | admin-portal | P6 启动前 | — |
### 7.3 coord 验收
各 AI 回写完成后coord 将重新运行 §8 交叉审查,确认无"中间过渡方案"残留。
---
## 8. 变更记录
| 日期 | 变更 | 决策者 |
| ---------- | --------------------------------------------------------------------------------------------------------------------- | ----------------- |
| 2026-07-09 | 初始创建,覆盖 G1-G17 / B1-B8 / I1-I8 / C1-C11 / N1-N5 / M1-M5 / D1-D5 / A1-A8 / P1-P6 / W1-W8 / F1-F12 共 80+ 项裁决 | coord用户确认 |