# 模块理解确认书 — 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）
