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.设计规格文档
134 lines
12 KiB
Markdown
134 lines
12 KiB
Markdown
# 模块理解确认书 — teacher-bff
|
||
|
||
> AI 标识:ai03
|
||
> 负责模块:teacher-bff(P2)
|
||
> 阶段:架构设计外包 · 阶段 1(全局理解)
|
||
> 日期:2026-07-09(v1)/ 2026-07-09(v2 审计修订)
|
||
> 关联文档:[ai-allocation.md](../../../docs/architecture/ai-allocation.md)、[004 架构影响地图](../../../docs/architecture/004_architecture_impact_map.md)、[pending-features.md](../../../docs/architecture/roadmap/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 缓存失效消费者
|
||
- **端口**:3003 HTTP(见 [teacher-bff env.ts](../src/config/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](./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)
|
||
- **暴露的 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](../src/shared/observability/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` 存在)
|
||
- [x] 错误处理:[GlobalErrorFilter](../src/shared/errors/global-error.filter.ts) + ApplicationError 层次(**错误码前缀需迁移 `TEACHER_BFF_*` → `BFF_TEACHER_*`**)
|
||
- [x] logger / metrics / tracer 三支柱(已具备)
|
||
- [x] `/healthz` 健康检查(HealthModule 已注册)
|
||
- [ ] `/readyz`(端点已存在,但**未做下游就绪探针**,需在 P2 补全:并行 ping iam + classes + core-edu 的 /healthz)
|
||
- [x] 优雅关闭 SIGTERM(main.ts 已处理)
|
||
- [ ] 测试覆盖率 ≥ 80%(**当前 0%**,无测试文件,P2 引入 Vitest)
|
||
- [x] Dockerfile 多阶段构建(builder + runtime,已具备,见 [Dockerfile](../Dockerfile))
|
||
- [ ] Zod 输入验证(当前 Controller 直接透传 unknown,**未做 Zod 校验**,P2 补全)
|
||
- [x] GlobalErrorFilter 统一兜底
|
||
|
||
---
|
||
|
||
## 服务审计表 — ai03(teacher-bff 部分)
|
||
|
||
> 对照 [黄金模板 classes 服务](../../classes/src/),审计已实现的 teacher-bff 服务。状态:✅ 达标 / ⚠️ 部分 / ❌ 缺失
|
||
|
||
| 服务 | 权限装饰器 | 错误码前缀 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile |
|
||
| ----------- | --------------------------------------- | ---------------------------------------------- | ------- | -------------- | ------- | -------- | ----------------------- | -------- | ---------- | ---------- |
|
||
| teacher-bff | ⚠️ 无(BFF 不做权限决策,依赖 Gateway) | ⚠️ `TEACHER_BFF_*`(需迁移为 `BFF_TEACHER_*`) | ✅ pino | ✅ prom-client | ✅ OTel | ✅ | ⚠️ 端点存在,无下游探针 | ✅ | 0% ❌ | ✅ 多阶段 |
|
||
|
||
### 审计发现的关键差距(P2 阶段 2 设计需解决)
|
||
|
||
1. ⚠️ 通信方式:当前 REST `fetch`,需引入 client 抽象层为 P3 gRPC 切换铺路;GraphQL Yoga + DataLoader 按 coord 仲裁决定 P2 还是 P4 引入(见 02 文档 §4.1)
|
||
2. ❌ 无 Redis 聚合缓存(004 §6.3 要求 5-30s 短缓存)
|
||
3. ❌ 无 DataLoader(防 N+1,pending-features P2 明确要求,目标态必备)
|
||
4. ⚠️ `/readyz` 端点存在但无下游就绪探针
|
||
5. ⚠️ env 配置用 `IamServiceUrl`/`ClassesServiceUrl`(REST URL),需抽象为 service target,支持 P3+ gRPC target
|
||
6. ⚠️ 无 Zod 输入验证
|
||
7. ⚠️ 无测试
|
||
8. ⚠️ 错误码前缀违反 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 设计重点](../../../docs/architecture/ai-allocation.md#ai03--教学场景域) 产出模块架构设计文档 [02-architecture-design.md](./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)
|