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.设计规格文档
12 KiB
12 KiB
模块理解确认书 — teacher-bff
AI 标识:ai03 负责模块:teacher-bff(P2) 阶段:架构设计外包 · 阶段 1(全局理解) 日期:2026-07-09(v1)/ 2026-07-09(v2 审计修订) 关联文档:ai-allocation.md、004 架构影响地图、pending-features.md
v2 修订说明:依据 ai-allocation.md §3.2 修正 ai03 责任范围(仅 teacher-bff,core-edu 由 ai08 负责);修正 /readyz 实际状态;修正错误码前缀描述;补充前瞻性内容(SSE 流式透传、Kafka 缓存失效、DataLoader 覆盖、DataScope 透传)。
1. 我在架构中的位置
- 层级:BFF 聚合层(L4)
- 上游:api-gateway(Go/Gin)通过 HTTP 转发请求,注入
x-user-id/x-user-roles头 - 下游:iam(3002 / gRPC 50052)、classes(3001 / P3 合并入 core-edu)、core-edu(3004 / gRPC 50053);P4 扩展 content(gRPC 50054)、data-ana(gRPC 50055);P5 扩展 msg(gRPC 50056)、ai(gRPC 50057,含 StreamChat 流式 RPC)
- 通信方式:
- 当前(P2):对前端 REST,对下游 REST
fetch(同步) - 目标态(004 §4.1 / pending-features P2):gRPC 调下游业务服务 + GraphQL Yoga 对前端暴露 + DataLoader 防 N+1
- 演进路径:P2 REST 内部封装为 client 抽象层 → P3 引入 gRPC client(iam + core-edu)→ P4 GraphQL Yoga 对前端 + DataLoader + content/data-ana gRPC → P5 SSE 流式透传(ai)+ msg gRPC + 可选 Kafka 缓存失效消费者
- 当前(P2):对前端 REST,对下游 REST
- 端口:3003 HTTP(见 teacher-bff env.ts);BFF 不暴露 gRPC 端口(只被 Gateway HTTP 调用)
2. 我的限界上下文
- 聚合职责:教学场景域(教师 / 教导主任 / 教研组长 共用)的数据聚合、裁剪、协议转换
- 业务领域:跨 D2 教学组织 + D3 教学核心 + D1 身份认证(只读拉取视口/权限)
- 我不负责:
- 不持有业务状态(无 DB 写入,无 Outbox)
- 不做权限决策(依赖 Gateway JWT 校验 + 下游服务
@RequirePermission) - 不直接访问任何业务服务数据库
- 复用策略(004 §5.4):教导主任 / 教研组长复用 Teacher BFF,通过视口差异化(L1 导航扩展管理菜单,L4 DataScope 扩大到年级)
3. 我与外部的契约
- 消费的 proto message(按阶段,详见 02-architecture-design.md §7):
- P2:
iam.v1.IamService(GetUserInfo;待补 RPC:GetViewports / GetEffectivePermissions / Logout / GetPublicKey)、classes.v1.ClassService(ListClasses / GetClass) - P3:
core_edu.v1.ExamService / HomeworkService / GradeService(全部 RPC);待补 RPC:AttendanceService、GetClassesByTeacher - P4:
content.v1.KnowledgeGraphService(GetPrerequisites / GetLearningPath);待补 RPC:ChapterService / QuestionService;analytics.v1.AnalyticsService(GetClassPerformance / GetStudentWeakness / GetLearningTrend);待补 RPC:GetTeacherDashboardStats - P5:
ai.v1.AiService(GenerateQuestion / StreamChat 流式 RPC / Chat / OptimizeExpression)、msg.v1.NotificationService(ListNotifications / SearchNotifications / MarkAsRead)
- P2:
- 暴露的 API(当前 REST,目标 GraphQL Yoga,详见 02 文档 §4):
GET /teacher/dashboard— 聚合 IAM 用户信息 + classes 列表GET /teacher/viewports— 拉取 IAM 视口配置(L1 导航)GET /teacher/classes/:classId/exams— 聚合 core-edu 考试列表GET /teacher/classes/:classId/homework— 聚合 core-edu 作业列表GET /teacher/exams/:examId/grades— 聚合 core-edu 成绩列表- P4+ 目标:GraphQL Query/Mutation(dashboard / viewports / classes / exams / homework / grades / knowledgePath / classPerformance / studentWeakness / notifications)+ Mutation(createExam / assignHomework / recordGrade / generateQuestion)
- P5:SSE 流式端点(AI 对话透传)
- 错误码前缀:当前代码用
TEACHER_BFF_*(违反 project_memory 规则 "BFF 错误码必须用BFF_XXX_前缀"),需迁移为BFF_TEACHER_*(coord P0 整改 #3);业务错误透传下游CORE_EDU_*/IAM_*/CLASSES_* - 缓存:聚合结果 Redis 短缓存 5-30s(004 §6.3,当前未实现);权限列表 5min 缓存 + 事件驱动失效(订阅
edu.identity.user.role_changed/edu.identity.role.updated,P3+ 引入 Kafka consumer,P2 用短 TTL 兜底) - DataScope 透传:BFF 不解析 dataScope 语义,从 IAM 获取后作为 gRPC metadata 透传给下游服务,下游 Repository 层注入 WHERE 条件(详见 02 文档 §9)
4. 我的技术栈
- 语言:TypeScript 5.5+(ESM 模式,相对 import 带
.js后缀) - 框架:NestJS 10
- 下游通信:当前
fetch(REST)→ P3 引入@grpc/grpc-js+@bufbuild/protobuf(经 client 抽象层,平滑切换) - 对前端:当前 REST → P4 目标 GraphQL Yoga + DataLoader(urql 客户端)
- 缓存:Redis(待引入;ioredis 客户端)
- 流式:P5 SSE 透传(ai.StreamChat streaming RPC → BFF → 前端 EventSource)
- 可观测:pino logger + prom-client metrics + OpenTelemetry tracer(已具备 tracer.ts)
- 弹性:P6 引入 circuit breaker(opossum)+ retry(gRPC interceptor)
- 测试:Vitest(待引入,目标覆盖率 ≥ 80%)
5. 我的阶段归属
- P2 身份:教师登录 → 获取 JWT → 访问 teacher-portal → 侧边栏按 viewports.L1 渲染 → 空白 Dashboard
- P3 扩展:考试/作业/成绩的查询与 mutation;iam + core-edu 切 gRPC;引入 Redis 聚合缓存
- P4 扩展:知识图谱查询(content)+ 学情诊断(data-ana);GraphQL Yoga 对前端 + DataLoader;content + data-ana 切 gRPC
- P5 扩展:AI 辅助出题(SSE 流式透传)+ 通知查询聚合(msg);ai + msg 切 gRPC;可选 Kafka 缓存失效消费者
- P6 硬化:circuit breaker + retry + HPA + mTLS;99.9% 可用性
- 依赖上游:P1 黄金模板 classes、P2 iam(getEffectivePermissions + 视口)
6. 我需要对齐的黄金模板项(对照 classes 服务)
- 权限装饰器
@RequirePermission(BFF 不做权限决策,当前无;目标态:BFF 不加 Guard,仅校验x-user-id存在) - 错误处理:GlobalErrorFilter + ApplicationError 层次(错误码前缀需迁移
TEACHER_BFF_*→BFF_TEACHER_*) - logger / metrics / tracer 三支柱(已具备)
/healthz健康检查(HealthModule 已注册)/readyz(端点已存在,但未做下游就绪探针,需在 P2 补全:并行 ping iam + classes + core-edu 的 /healthz)- 优雅关闭 SIGTERM(main.ts 已处理)
- 测试覆盖率 ≥ 80%(当前 0%,无测试文件,P2 引入 Vitest)
- Dockerfile 多阶段构建(builder + runtime,已具备,见 Dockerfile)
- Zod 输入验证(当前 Controller 直接透传 unknown,未做 Zod 校验,P2 补全)
- GlobalErrorFilter 统一兜底
服务审计表 — ai03(teacher-bff 部分)
对照 黄金模板 classes 服务,审计已实现的 teacher-bff 服务。状态:✅ 达标 / ⚠️ 部分 / ❌ 缺失
| 服务 | 权限装饰器 | 错误码前缀 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile |
|---|---|---|---|---|---|---|---|---|---|---|
| teacher-bff | ⚠️ 无(BFF 不做权限决策,依赖 Gateway) | ⚠️ TEACHER_BFF_*(需迁移为 BFF_TEACHER_*) |
✅ pino | ✅ prom-client | ✅ OTel | ✅ | ⚠️ 端点存在,无下游探针 | ✅ | 0% ❌ | ✅ 多阶段 |
审计发现的关键差距(P2 阶段 2 设计需解决)
- ⚠️ 通信方式:当前 REST
fetch,需引入 client 抽象层为 P3 gRPC 切换铺路;GraphQL Yoga + DataLoader 按 coord 仲裁决定 P2 还是 P4 引入(见 02 文档 §4.1) - ❌ 无 Redis 聚合缓存(004 §6.3 要求 5-30s 短缓存)
- ❌ 无 DataLoader(防 N+1,pending-features P2 明确要求,目标态必备)
- ⚠️
/readyz端点存在但无下游就绪探针 - ⚠️ env 配置用
IamServiceUrl/ClassesServiceUrl(REST URL),需抽象为 service target,支持 P3+ gRPC target - ⚠️ 无 Zod 输入验证
- ⚠️ 无测试
- ⚠️ 错误码前缀违反 project_memory 规则,需迁移
TEACHER_BFF_*→BFF_TEACHER_*
跨模块契约对齐待确认项(提请 coord 交叉审查)
| 待确认项 | 我方期望 | 对方模块 | 状态 |
|---|---|---|---|
iam getEffectivePermissions(userId) 返回结构 |
{permissions, viewports, dataScope} 聚合 API(建议 GetEffectiveAccess RPC) |
iam(ai06) | ⚠️ 当前 teacher-bff 调 /iam/viewports 与 /iam/me,未定义此聚合 API 的 proto |
| iam 补 RPC:GetViewports / GetEffectivePermissions / Logout / GetPublicKey | 4 个 RPC | iam(ai06) | ❌ proto 缺失,coord 裁决 P2 补全 |
| core-edu 补 AttendanceService + GetClassesByTeacher | 1 个 service + 1 个 RPC | core-edu(ai08) | ❌ proto 缺失,coord 裁决 P3 补全 |
| data-ana 补 GetTeacherDashboardStats | 1 个 RPC | data-ana(ai11) | ❌ proto 缺失,提请 coord 仲裁 |
| GraphQL vs REST 仲裁 | P2 即 GraphQL(pending-features)vs P2-P3 REST、P4+ GraphQL(coord 裁决) | coord | ⚠️ 表述冲突,需仲裁 |
| core-edu 端口 3004 / gRPC 50053 | 不冲突 | 全局端口矩阵 | 待 coord 核对 |
下一步(阶段 2 入口)
待 coord 审核本确认书通过后,ai03 进入阶段 2,按 ai-allocation.md §5 ai03 设计重点 产出模块架构设计文档 02-architecture-design.md:
- teacher-bff 模块架构设计:目标态架构(GraphQL Yoga + DataLoader + gRPC + Redis 缓存 + SSE 流式透传)+ 分阶段演进路线(P2-P6)+ 视口推导 + DataScope 透传 + 并行 gRPC 编排与降级策略
阶段 2 设计需先解决上述 8 项差距与跨模块契约对齐。
AI Agent: ai03 (teacher-bff) Coordinator: coord-ai Branch: 单仓库并行模式(直接 push main)