fix: code compliance audit and fix across all services
Some checks failed
CI / quality-ts (push) Failing after 48s
CI / quality-go (push) Failing after 4s
CI / quality-proto (push) Failing after 2s
CI / deploy (push) Has been skipped

NestJS (6 services): implement @RequirePermission decorator with
SetMetadata+Reflector, register APP_GUARD globally, fix as assertions
to type guards, add explicit return types, fix import type for express,
fix /metrics implicit any, replace native Error with ApplicationError,
remove typeorm remnants, register LifecycleService.

teacher-bff: add logger, ApplicationError, GlobalErrorFilter, forward
real userId to downstream, log downstream failures, migrate health
controller to shared/health.

Go (2 services): interface to any, doc comments, CORS dev whitelist,
JWT secret fail-fast, push-gateway internal API auth, metrics and
readyz endpoints, remove dead code.

Python (2 services): lifespan return type, dev_mode to bool, data-ana
APIRouter, ai POST body model, ClickHouse async wrapping.
This commit is contained in:
SpecialX
2026-07-09 17:28:27 +08:00
parent b53a486c6e
commit 0a71b02e04
93 changed files with 5775 additions and 608 deletions

View File

@@ -0,0 +1,297 @@
# 模块理解确认书 — student-bff
> AI 标识ai04
> 阶段:阶段 1全局理解
> 日期2026-07-09
> 状态:待 coord 审核
> 关联文档:[ai-allocation §6 模板](../../docs/architecture/ai-allocation.md)、[004 架构影响地图](../../docs/architecture/004_architecture_impact_map.md)、[pending-features P3](../../docs/architecture/roadmap/pending-features.md)
---
## 1. 我在架构中的位置
| 维度 | 内容 |
| -------------- | ----------------------------------------------------------------------------- |
| 层级 | **L4 BFF 聚合层**004 §3.1 六层架构) |
| 上游调用方 | api-gatewayGo Gin反向代理 `/api/v1/student/*` → student-bff:3009 |
| 下游被调用方 | iam、core-edu、content、data-ana按 004 §4 服务依赖图) |
| 通信方式(入) | HTTP RESTapi-gateway → student-bff当前阶段设计意图为 gRPC004 §4.1 |
| 通信方式(出) | HTTP fetch当前阶段对齐 teacher-bff 模式);设计意图为 gRPC004 §4.1 |
| 微前端对接 | student-portalai07 负责P3 阶段)通过 api-gateway 调用 student-bff |
| 推送通道 | push-gatewayP5 阶段WebSocket/SSE 推送考试通知、成绩发布等) |
**架构定位**004 §1.1a + §5.4
- 按"使用场景域"分 BFFstudent-bff 服务于**学习场景域**,复用角色:学生
- 不按角色分 BFF新角色复用现有 BFF 通过视口差异化
- DataScope = **SELFL0**学生只能看自己的数据004 §5.3
---
## 2. 我的限界上下文
### 2.1 我负责什么
student-bff 是**纯聚合层**,不持有业务状态、不直接访问 DB对齐 teacher-bff 模式)。职责:
1. **聚合**:并行调用多个下游业务服务,组装学生视角的复合数据
2. **裁剪**:将下游返回的领域数据裁剪为学生端所需的最小字段集
3. **协议转换**:对外暴露场景化 HTTP/GraphQL 端点,对内调用下游 REST/gRPC
4. **缓存**:聚合结果 Redis 短缓存 5-30s004 §6.2 BFF 混合读策略)
### 2.2 我的聚合场景(学生视角)
| 场景 | 聚合的下游服务 | 用途 |
| ------------------ | --------------------------------------------------------------------------- | ------------------------------ |
| 学生首页 Dashboard | iam `/iam/me` + core-edu `/homework/class/:classId` + msg `/notifications` | 个人信息 + 待办作业 + 未读消息 |
| 即将到来的考试 | core-edu `/exams/class/:classId` | 考试日程提醒 |
| 我的作业列表 | core-edu `/homework/class/:classId` | 查看待完成作业 |
| 提交作业 | core-edu `/homework/:id/submit` | 学生提交作业答案 |
| 我的成绩 | core-edu `/grades/student/:studentId` | 查询历史成绩 |
| 消息中心 | msg `/notifications` + `/notifications/:id/read` | 通知列表 + 已读 |
| 教材浏览 | content `/textbooks` + `/chapters` | 按章节学习 |
| 题库练习 | content `/questions` | 按知识点刷题 |
| 学情诊断 | data-ana `/analytics/student/:id/weakness` + `/analytics/student/:id/trend` | 自我掌握度分析 |
| AI 答疑 | ai `/ai/chat` + `/ai/stream-chat`SSE 流式) | 智能答疑辅助 |
| 个性化学习路径 | content `/knowledge-points/:id/learning-path` | 基于学情推荐学习路径 |
### 2.3 我不负责什么(明确边界外)
| 不负责项 | 归属服务 | 说明 |
| -------------- | ------------------------------ | ----------------------------------------------------------------- |
| 业务数据持久化 | core-edu / content / msg / iam | BFF 不写 DB |
| 权限校验 | 下游业务服务 + iam | BFF 不做权限校验(对齐 teacher-bff透传 `x-user-id` 让下游校验 |
| 用户认证 | iam + api-gateway | JWT 校验在 GatewayBFF 只读 `x-user-id` 头 |
| 领域事件发布 | core-edu / content | BFF 不发布事件,仅可选订阅事件用于实时推送 |
| 数据范围过滤 | 下游业务服务 Repository 层 | BFF 透传 userId下游按 DataScope=SELF 过滤 |
| 班级管理 | core-educlasses 模块) | 学生只读自己所在班级 |
| 考试批改 | core-edu | 学生不能批改,只能查看成绩 |
---
## 3. 我与外部的契约
### 3.1 我消费的 proto message / 下游接口
> ⚠️ **重要差距**:当前阶段 BFF→Service 走 HTTP fetch对齐 teacher-bff 现状proto 仅作"契约文档"。gRPC 落地需 coord 在 buf.gen.yaml 补 gRPC 插件。
| 下游服务 | proto service设计意图 | 当前 REST 端点(实际可用) | 用途 |
| ------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------ |
| iam | `IamService.GetUserInfo` | `GET /iam/me` | 获取学生个人信息 + roles + dataScope |
| iam | `IamService.GetViewports`proto 缺失) | `GET /iam/viewports` | 获取学生端导航视口 |
| iam | `IamService.GetEffectivePermissions`proto 缺失) | `GET /iam/permissions/effective` | 获取有效权限列表 |
| classescore-edu | `ClassService.GetClass` / `ListClasses` | `GET /classes` / `GET /classes/:id` | 查自己所在班级 |
| core-edu | `ExamService.GetExam` / `ListExamsByClass` | `GET /exams/class/:classId` | 查班级考试 |
| core-edu | `HomeworkService.GetHomework` / `ListHomeworkByClass` / `SubmitHomework` | `GET /homework/class/:classId` / `POST /homework/:id/submit` | 查作业 + 提交 |
| core-edu | `GradeService.GetGrade` / `ListGradesByStudent` | `GET /grades/student/:studentId` | 查自己成绩 |
| content | `TextbookService.GetTextbook` / `ListTextbooks` | `GET /textbooks` | 查教材 |
| content | `ChapterService`proto 缺失) | `GET /chapters` / `GET /chapters/:id` | 查章节 |
| content | `QuestionService`proto 缺失) | `GET /questions` | 查题库 |
| content | `KnowledgeGraphService.GetLearningPath` | `GET /knowledge-points/:id/learning-path` | 学习路径 |
| msg | `NotificationService.ListNotifications` / `MarkAsRead` / `SearchNotifications` | `GET /notifications` / `POST /notifications/:id/read` | 消息中心 |
| data-ana | `AnalyticsService.GetStudentWeakness` / `GetLearningTrend` | **REST 未实现** | 学情分析 |
| ai | `AiService.Chat` / `StreamChat` / `GenerateQuestion` | **REST 未实现** | AI 答疑 |
### 3.2 我暴露的 API 端点student-bff 对外)
> 路由前缀:`/student`(对齐 teacher-bff 用 `/teacher` 的命名规律BFF 用角色单数无 `-bff` 后缀)
> 网关路径:`/api/v1/student/*` → api-gateway 剥离 `/api/v1` 后代理到 student-bff:3009
| method | path | 聚合下游 | 权限(透传给下游校验) | 说明 |
| ------ | --------------------------------- | -------------------- | ------------------------- | -------------------- |
| GET | `/student/dashboard` | iam + core-edu + msg | STUDENT_DASHBOARD_READ | 学生首页聚合 |
| GET | `/student/exams` | core-edu | STUDENT_EXAM_READ | 即将到来的考试 |
| GET | `/student/homework` | core-edu | STUDENT_HOMEWORK_READ | 我的作业列表 |
| POST | `/student/homework/:id/submit` | core-edu | STUDENT_HOMEWORK_SUBMIT | 提交作业 |
| GET | `/student/grades` | core-edu | STUDENT_GRADE_READ | 我的成绩 |
| GET | `/student/notifications` | msg | STUDENT_NOTIFICATION_READ | 消息列表 |
| POST | `/student/notifications/:id/read` | msg | STUDENT_NOTIFICATION_READ | 标记已读 |
| GET | `/student/textbooks` | content | STUDENT_CONTENT_READ | 教材列表 |
| GET | `/student/chapters/:textbookId` | content | STUDENT_CONTENT_READ | 章节树 |
| GET | `/student/questions` | content | STUDENT_CONTENT_READ | 题库(按知识点过滤) |
| GET | `/student/analytics/weakness` | data-ana | STUDENT_ANALYTICS_READ | 学情诊断 |
| GET | `/student/analytics/trend` | data-ana | STUDENT_ANALYTICS_READ | 学习趋势 |
| POST | `/student/ai/chat` | ai | STUDENT_AI_CHAT | AI 答疑(同步) |
| POST | `/student/ai/stream-chat` | ai | STUDENT_AI_CHAT | AI 答疑SSE 流式) |
### 3.3 错误码前缀
| 前缀 | 用途 | 示例 |
| -------------- | ---------------------- | ----------------------------------------------------- |
| `STUDENT_BFF_` | student-bff 自身错误 | `STUDENT_BFF_UNAUTHORIZED``STUDENT_BFF_BAD_GATEWAY` |
| 下游错误透传 | 下游服务错误码原样返回 | `CLASSES_NOT_FOUND``IAM_USER_NOT_FOUND` |
错误类清单(对齐 teacher-bff application-error.ts
- `UnauthorizedError(401)` — 缺失 `x-user-id`
- `BadGatewayError(502)` — 下游服务返回非 ok 或 fetch rejected
- `ValidationError(400)` — 入参校验失败BFF 层 Zod 校验)
- `InternalError(500)` — 未捕获异常
### 3.4 我订阅的 Kafka 事件(可选,用于实时推送)
| Topic | 事件 | 消费动作 |
| --------------------- | --------------------------------------- | -------------------------- |
| `edu.homework.events` | `homework.assigned` / `homework.graded` | 推送给学生push-gateway |
| `edu.exam.events` | `exam.published` / `exam.updated` | 考试提醒推送 |
| `edu.grade.events` | `grade.recorded` | 成绩发布推送 |
> ⚠️ Kafka 订阅在 P5 阶段 push-gateway 落地后才有意义P3 阶段 student-bff 可不消费事件,仅做同步聚合。
---
## 4. 我的技术栈
| 维度 | 选型 | 依据 |
| ------------ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| 语言 | TypeScript 5.5+ | 004 §2.1 |
| 框架 | NestJS 10 | 004 §2.1,对齐 teacher-bff 模板 |
| ORM | **无**BFF 不访问 DB | 对齐 teacher-bff无 repository/schema/dto |
| 缓存 | Redis 7短缓存 5-30s | 004 §6.2 BFF 混合读策略 |
| 可观测性日志 | pino | 对齐 classes/teacher-bff |
| 可观测性指标 | prom-client`/metrics` 端点) | 对齐 teacher-bff main.ts |
| 可观测性链路 | OpenTelemetry SDK + OTLP exporter | 对齐 teacher-bff tracer.ts |
| API 风格 | **HTTP REST**(当前阶段) | 对齐 teacher-bff 现状pending-features P2 设计意图为 GraphQL但 teacher-bff 实际未落地 GraphQL需 coord 仲裁是否在 student-bff 引入 |
| 输入校验 | Zod | 对齐 classes/teacher-bff |
| 错误处理 | GlobalErrorFilter + ApplicationError | 对齐 classes/teacher-bff |
| ESM 模式 | NodeNext + `.js` 后缀 import | 对齐 teacher-bff tsconfig |
| 测试框架 | Jest待定对齐 classes | 黄金模板要求测试覆盖率 ≥ 80% |
### 4.1 关于 GraphQL 的设计决策(待 coord 仲裁)
**现状矛盾**
- 004 §11.3 BFF 聚合模式图示为 GraphQL Resolver + DataLoader + Redis 缓存
- pending-features P2 明确"Teacher BFFTS/GraphQL"用 GraphQL Yoga + DataLoader
- **实际**teacher-bff 当前是纯 REST + fetch无 GraphQL、无 DataLoader
- ai-allocation.md §5 ai04 设计重点提到"DataLoader 复用 teacher-bff 模式"
**ai04 倾向方案**P3 阶段 student-bff **先对齐 teacher-bff 现状REST + fetch + Promise.allSettled**,避免技术栈分裂;若 coord 决策统一升级到 GraphQL则在 P3 后期或 P4 阶段同步升级 teacher-bff + student-bff + parent-bff 三端。此决策需 coord 仲裁。
---
## 5. 我的阶段归属
| 维度 | 内容 |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| 阶段 | **P3 核心教学阶段**M7-M10 |
| 退出标准pending-features P3 | 教师创建考试 → 发布 → 学生作答提交 → 教师批改 → 事件发到 Kafka → 成绩统计更新 → 全链路可观测 |
| student-bff 在 P3 的最小交付 | 学生作答作业页面所需 API`/student/homework` 列表 + `/student/homework/:id/submit` 提交 + `/student/grades` 成绩查看 |
| 依赖上游阶段产出 | P1api-gateway 路由骨架 + classes 黄金模板 + shared-proto、P2iam 认证 + teacher-bff BFF 模板 + teacher-portal 微前端骨架) |
| P3 同阶段依赖 | core-edu考试/作业/成绩域 CRUD + Outbox 事件) |
| P4 阶段扩展 | 学情诊断查询(双轨读:实时查 core-edu 主库 + 聚合查 data-ana ClickHouse 宽表) |
| P5 阶段扩展 | AI 答疑流式响应 + Kafka 事件订阅推送 |
### 5.1 P3 阶段最小可行集合MVP
student-bff 在 P3 阶段不一定要实现全部 14 个端点,优先级:
| 优先级 | 端点 | P3 必需 | 说明 |
| ------ | ----------------------------------------------------------------- | ------- | ------------------------- |
| P0 | `/student/homework` GET | ✅ | 学生作答作业页面核心 |
| P0 | `/student/homework/:id/submit` POST | ✅ | 学生作答提交 |
| P0 | `/student/grades` GET | ✅ | 成绩查看 |
| P0 | `/student/dashboard` GET | ✅ | 学生首页 |
| P1 | `/student/exams` GET | ✅ | 考试日程 |
| P1 | `/student/notifications` GET | ⚠️ 可选 | P5 msg 服务落地后才有意义 |
| P2 | `/student/textbooks` / `/student/chapters` / `/student/questions` | ❌ P4 | content 服务 P4 才落地 |
| P2 | `/student/analytics/*` | ❌ P4 | data-ana 学情诊断 P4 |
| P2 | `/student/ai/*` | ❌ P5 | ai 服务 P5 |
---
## 6. 我需要对齐的黄金模板项(对照 classes 服务)
> 对照 ai-allocation.md §6 模板第 6 节 + §10 审计模板
| 对齐项 | classes 黄金模板 | student-bff 计划 | 备注 |
| ------------------------------- | ---------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------- |
| 权限装饰器 `@RequirePermission` | ✅ 全部 Controller 方法 | ⚠️ **不对齐** | BFF 不做权限校验(对齐 teacher-bff透传 `x-user-id` 给下游校验 |
| 错误码前缀统一 | ✅ `CLASSES_` | ✅ `STUDENT_BFF_` | 对齐 teacher-bff 的 `TEACHER_BFF_` 模式 |
| loggerpino | ✅ `shared/observability/logger.ts` | ✅ 复制 teacher-bff 实现 | service 名改 `student-bff` |
| metricsprom-client | ✅ `/metrics` 端点 | ✅ 复制 teacher-bff main.ts 注册方式 | 指标名前缀 `student_bff_` |
| tracerOpenTelemetry | ✅ OTLP exporter + auto-instrumentations | ✅ 复制 teacher-bff tracer.ts | serviceName 改 `student-bff` |
| `/healthz` 健康检查 | ✅ liveness | ✅ 复制 teacher-bff | BFF 不查 DB直接返回 ok |
| `/readyz` 健康检查 | ✅ Drizzle `SELECT 1` | ✅ 复制 teacher-bff | BFF 不查 DB直接返回 ok可选检查下游服务可达性 |
| 优雅关闭SIGTERM | ✅ LifecycleService 关闭 DB 连接池 | ✅ main.ts 注册 SIGTERM → `app.close()` + `shutdownTracer()` | BFF 无 DB 连接,仅需关闭 HTTP server + tracer |
| 测试覆盖率 ≥ 80% | ✅ Jest | ⚠️ **待补** | BFF 测试重点是 Service 层聚合逻辑 mock 下游 fetch |
| Dockerfile 多阶段构建 | ✅ builder + runtime | ✅ 复制 teacher-bff Dockerfile | EXPOSE 改 3009 |
| Zod 输入验证 | ✅ Controller 层 `schema.parse(body)` | ✅ Controller 层校验 | 提交作业 body 需 Zod 校验 |
| GlobalErrorFilter | ✅ `@Catch()` 全局过滤器 | ✅ 复制 teacher-bff | 注册到 main.ts |
| ESM `.js` 后缀 import | ✅ tsconfig NodeNext | ✅ 复制 teacher-bff tsconfig | 所有相对 import 带 `.js` |
| `import type` 纯类型导入 | ✅ | ✅ | 对齐 classes 规范 |
| 环境变量 Zod 校验 | ✅ `config/env.ts` | ✅ 复制 teacher-bff env.ts | 下游 URL 配置项扩展 |
### 6.1 与 teacher-bff 模板的差异点(克隆时必须改)
| 文件 | teacher-bff 现值 | student-bff 应改为 |
| ------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `package.json` name | `@edu/teacher-bff` | `@edu/student-bff` |
| `src/config/env.ts` `PORT` default | `"3003"` | `"3009"` |
| `src/config/env.ts` 下游 URL | IamServiceUrl / ClassesServiceUrl / CoreEduServiceUrl | + ContentServiceUrl / DataAnaServiceUrl / MsgServiceUrl / AiServiceUrl按聚合需求 |
| `src/teacher/` 目录名 | `teacher/` | `student/` |
| `@Controller("teacher")` | `"teacher"` | `"student"` |
| `health.controller.ts` `SERVICE_NAME` | `"teacher-bff"` | `"student-bff"` |
| `application-error.ts` 错误码前缀 | `TEACHER_BFF_` | `STUDENT_BFF_` |
| `metrics.ts` 指标名前缀 | `teacher_bff_` | `student_bff_` |
| `tracer.ts` serviceName | `"teacher-bff"` | `"student-bff"` |
| `logger.ts` service | `"teacher-bff"` | `"student-bff"` |
| `main.ts` 启动日志 | `"Teacher BFF started"` | `"Student BFF started"` |
| `Dockerfile` `EXPOSE` | `3003` | `3009` |
---
## 7. 风险与依赖(待 coord 仲裁)
### 7.1 上游依赖缺口
| 风险 | 影响 | 缓解措施 |
| -------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------- |
| data-ana 服务未实现查询 APIanalytics.proto 3 个 method 无 REST 端点) | P4 学情诊断端点无法实现 | P3 阶段先不实现 `/student/analytics/*`,等 ai06 在 P4 实现 data-ana 查询 API 后再补 |
| ai 服务未实现 REST/gRPC 端点 | P5 AI 答疑端点无法实现 | P3/P4 阶段先不实现 `/student/ai/*`,等 ai06 在 P5 实现 ai 服务后再补 |
| content.proto 缺 Chapter/Question 域 | P4 教材/题库端点 proto 契约不全 | 推动 coord 在 shared-proto 补全 content.proto |
| iam.proto 缺 Viewport/EffectivePermissions | 学生端导航视口 proto 契约不全 | 当前走 REST `/iam/viewports`proto 补全后切换 |
| 出勤attendance全局缺失 | 学生端无法查出勤 | 推动 coord 在 core_edu.proto 补 Attendance 域P3 后期或 P4 |
| 学生-家长关联表缺失pending-features P2 提到 `parent_student_relations` | 影响 parent-bff不影响 student-bff | 报告给 coord由 ai02 在 iam 或 ai03 在 core-edu 补表 |
### 7.2 设计决策待仲裁
| 决策点 | 选项 | ai04 建议 |
| ------------------ | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------- |
| BFF API 风格 | A. REST对齐 teacher-bff 现状)<br/>B. GraphQL对齐 004 §11.3 设计意图 + pending-features P2 | **A**P3 阶段先 REST避免技术栈分裂后续统一升级 |
| BFF 是否做权限校验 | A. 不校验(对齐 teacher-bff透传 x-user-id<br/>B. 加 `@RequirePermission` 装饰器 | **A**BFF 是聚合层,权限由下游服务校验) |
| `/readyz` 检查逻辑 | A. 直接返回 ok对齐 teacher-bff<br/>B. 检查下游服务可达性 | **A**P3 阶段,下游可达性由 Prometheus 监控) |
| Kafka 事件订阅 | A. P3 不订阅(仅同步聚合)<br/>B. P3 订阅事件推送 | **A**push-gateway P5 才落地P3 无推送通道) |
| 端口分配 | 3009 | 对齐 full-stack-runbook 端口矩阵3001-3008 已用) |
### 7.3 跨模块协作需求(需提交 coord 协调)
| 需求 | 涉及 AI | 协调内容 |
| ------------------------------------------------------------ | -------------- | --------------------------------------------------------- |
| api-gateway 新增 `/student` 路由 | ai01 | 在 main.go + config.go 新增 `StudentBffURL` 字段 + 路由块 |
| docker-compose.deploy.yml 新增 student-bff 服务定义 | coordinfra | 端口 3009加入 edu-net + edu-shared 网络 |
| full-stack-runbook 端口矩阵更新 | coorddocs | 追加 3009 行 |
| 004 架构图状态更新 | coorddocs | student-bff 状态从"📐 需设计"改为"✅ 已实现" |
| shared-proto 补全 content.protoChapter/Question | coord | P4 阶段 content 服务落地前补全 |
| shared-proto 补全 iam.protoViewport/EffectivePermissions | coord | 推动 ai02 补 proto |
| buf.gen.yaml 补 gRPC 插件 | coord | 决定是否在 P3 升级到 gRPC 通信 |
---
## 8. 阶段 1 自检结论
| 检查项 | 状态 |
| ------------------------------------ | --------------------------- |
| 已读必读文档清单ai-allocation §4 | ✅ |
| 已运行 arch:scan 更新 arch.db | ✅ |
| 已查 arch:query modules / stats | ✅ |
| 已读 classes 黄金模板源码 | ✅ |
| 已读 teacher-bff BFF 模板源码 | ✅ |
| 已读 iam 认证服务源码 | ✅ |
| 已读 shared-proto 全部 .proto | ✅ |
| 已识别 proto 契约缺口 | ✅(见 §7.1 |
| 已识别端口/路由预留情况 | ✅3009 可用,路由未预留) |
| 已识别设计决策待仲裁项 | ✅(见 §7.2 |
| 已识别跨模块协作需求 | ✅(见 §7.3 |
**ai04 阶段 1 交付完成,请 coord 审核。审核通过后进入阶段 2模块架构设计文档**

View File

@@ -0,0 +1,176 @@
# 服务审计表 — ai04
> AI 标识ai04
> 阶段:阶段 1自检
> 日期2026-07-09
> 审计对象student-bffP3 待实现、parent-bffP4 待实现)
> 对照基准classes 黄金模板(已实现)+ teacher-bff BFF 模板(已实现)
> 模板来源:[ai-allocation.md §10](../../docs/architecture/ai-allocation.md)
---
## 1. 审计状态说明
| 标记 | 含义 |
| ---- | --------------------------------------------------- |
| ✅ | 已对齐黄金模板(实施时复制 + 改名即可) |
| ⚠️ | 有差异但已识别缓解方案(需 coord 仲裁或实施时调整) |
| ❌ | 未对齐,需补齐 |
| 🆕 | 全新服务,尚未实现,审计结果为"设计目标" |
由于 student-bff 和 parent-bff 均为**全新服务(未实现)**,本审计表为**设计目标审计**,列出实施时需对齐的各项。
---
## 2. ai04 服务审计表
| 服务 | 权限装饰器 | 错误码前缀 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile |
| ---------------------------- | ---------- | ----------------- | ------- | -------------- | ------- | -------- | ------- | ---------- | ------------ | ---------- |
| **student-bff**P3 待实现) | ⚠️ 不对齐 | ✅ `STUDENT_BFF_` | ✅ pino | ✅ prom-client | ✅ OTel | ✅ | ✅ | ✅ SIGTERM | 🆕 目标 ≥80% | ✅ 多阶段 |
| **parent-bff**P4 待实现) | ⚠️ 不对齐 | ✅ `PARENT_BFF_` | ✅ pino | ✅ prom-client | ✅ OTel | ✅ | ✅ | ✅ SIGTERM | 🆕 目标 ≥80% | ✅ 多阶段 |
---
## 3. 审计项详解
### 3.1 权限装饰器 `@RequirePermission` — ⚠️ 不对齐
**classes 黄金模板**:全部 Controller 方法用 `@RequirePermission(Permissions.XXX)` 装饰,全局 `PermissionGuard` 校验。
**ai04 服务决策****不对齐**。理由:
- BFF 是纯聚合层,权限由下游业务服务校验(对齐 teacher-bff 现状)
- BFF 透传 `x-user-id` 头给下游,下游 Repository 按 DataScope 过滤
- parent-bff 在 BFF 层做"DataScope=CHILDREN 越权校验"(家长查询的 childId 必须在绑定列表内),但用普通 Service 层校验,不用装饰器
**风险**:若 coord 要求 BFF 也加权限装饰器(双重校验),需在 student-bff/parent-bff 引入 `middleware/permission.guard.ts`(复制 classes 实现)。
### 3.2 错误码前缀 — ✅ 对齐
| 服务 | 前缀 | 示例 |
| ----------- | -------------- | --------------------------------------------------------------------------------- |
| student-bff | `STUDENT_BFF_` | `STUDENT_BFF_UNAUTHORIZED``STUDENT_BFF_BAD_GATEWAY` |
| parent-bff | `PARENT_BFF_` | `PARENT_BFF_UNAUTHORIZED``PARENT_BFF_BAD_GATEWAY``PARENT_BFF_CHILD_NOT_BOUND` |
对齐 teacher-bff 的 `TEACHER_BFF_` 模式。
### 3.3 logger — ✅ 对齐
复制 teacher-bff `shared/observability/logger.ts`,仅改 `service` 字段:
- student-bff: `service: 'student-bff'`
- parent-bff: `service: 'parent-bff'`
### 3.4 metrics — ✅ 对齐
复制 teacher-bff `shared/observability/metrics.ts` + `main.ts``/metrics` 端点注册,仅改指标名前缀:
- student-bff: `student_bff_requests_total``student_bff_request_duration_seconds`
- parent-bff: `parent_bff_requests_total``parent_bff_request_duration_seconds`
### 3.5 tracer — ✅ 对齐
复制 teacher-bff `shared/observability/tracer.ts`,仅改 `serviceName`
- student-bff: `serviceName: 'student-bff'`
- parent-bff: `serviceName: 'parent-bff'`
### 3.6 /healthz — ✅ 对齐
复制 teacher-bff `shared/health/health.controller.ts`,仅改 `SERVICE_NAME`
- student-bff: `service: 'student-bff'`
- parent-bff: `service: 'parent-bff'`
### 3.7 /readyz — ✅ 对齐
BFF 不查 DB`/readyz` 直接返回 ok对齐 teacher-bff
**可选增强**P3 后期检查下游服务可达性HEAD 请求 iam/core-edu 的 `/healthz`),但 P3 阶段建议先简单返回 ok下游可达性由 Prometheus 监控。
### 3.8 优雅关闭 — ✅ 对齐
复制 teacher-bff `main.ts` 中 SIGTERM 处理:
```ts
process.on("SIGTERM", async () => {
await app.close();
await shutdownTracer();
});
```
BFF 无 DB 连接需关闭(无 LifecycleService仅需关闭 HTTP server + tracer。
### 3.9 测试覆盖率 — 🆕 目标 ≥ 80%
**测试重点**
- Service 层聚合逻辑mock 下游 fetch验证 Promise.allSettled 容错)
- Controller 层入参校验Zod schema
- 错误处理BadGatewayError、UnauthorizedError、ValidationError
- parent-bff 特有DataScope=CHILDREN 越权校验
**测试框架**Jest对齐 classes待确认 classes 是否已配置 Jest
### 3.10 Dockerfile — ✅ 对齐
复制 teacher-bff `Dockerfile`多阶段构建builder + runtime仅改 `EXPOSE`
- student-bff: `EXPOSE 3009`
- parent-bff: `EXPOSE 3010`
---
## 4. 与 teacher-bff 模板对比(克隆基线)
teacher-bff 是已实现的最小 BFF 模板student-bff/parent-bff 应 1:1 克隆后改造。
### 4.1 完全复制的部分(无需改动)
| 文件/目录 | 说明 |
| -------------------------------------- | ----------------------------------- |
| `shared/errors/global-error.filter.ts` | 全局错误过滤器(仅错误码前缀不同) |
| `shared/health/health.module.ts` | 健康检查模块 |
| `shared/observability/logger.ts` | pino logger仅 service 名不同) |
| `shared/observability/metrics.ts` | prom-client仅指标名前缀不同 |
| `shared/observability/tracer.ts` | OTel tracer仅 serviceName 不同) |
| `app.module.ts` | 根模块(仅 imports 的业务模块不同) |
| `main.ts` | 启动流程(仅端口和日志不同) |
| `tsconfig.json` | ESM 配置 |
| `nest-cli.json` | NestJS CLI 配置 |
### 4.2 需要改造的部分
| 文件 | 改造点 |
| --------------------------------------- | ---------------------------------------------------------- |
| `package.json` | name 字段、dependencies按下游服务需求扩展 |
| `src/config/env.ts` | PORT default、下游服务 URL 配置项 |
| `src/<context>/` 目录名 | teacher → student / parent |
| `src/<context>/<context>.controller.ts` | @Controller 装饰器前缀、端点路由 |
| `src/<context>/<context>.service.ts` | 聚合逻辑(按场景域不同) |
| `src/<context>/<context>.module.ts` | 模块注册 |
| `shared/errors/application-error.ts` | 错误码前缀、新增错误类parent-bff 加 ChildNotBoundError |
| `shared/health/health.controller.ts` | SERVICE_NAME |
| `Dockerfile` | EXPOSE 端口 |
### 4.3 teacher-bff 模板的可改进点ai04 实施时可优化)
| 改进点 | teacher-bff 现状 | ai04 建议改进 |
| ------------ | ----------------------------- | ------------------------------------------------------------ |
| 聚合响应类型 | 大量用 `unknown` | 用 Zod schema 推导强类型响应 |
| 下游调用封装 | 原生 `fetch()` 散落在 Service | 抽取 `DownstreamClient` 工具类带超时、重试、traceId 透传) |
| 错误信封 | 下游错误直接吞掉返回 null | 下游错误结构化记录service/endpoint/status透传 traceId |
| 缓存 | 无缓存 | 引入 NestJS CacheInterceptor + Redis5-30s 短缓存) |
> ⚠️ 这些改进点需 coord 仲裁是否回写到 teacher-bff避免技术栈分裂还是仅用于 student-bff/parent-bff。
---
## 5. 审计结论
| 服务 | 总体对齐度 | 阻塞项 | 备注 |
| ----------- | ------------ | -------------------------------------- | ---------------------------------------------------------------- |
| student-bff | 🟢 高90% | 无 P0 阻塞 | P3 阶段可直接克隆 teacher-bff 实施data-ana/ai 端点延后到 P4/P5 |
| parent-bff | 🟡 中70% | **P0 阻塞iam 家长-学生关联接口缺失** | 需 coord 协调 ai02 在 P3 阶段补全 iam 接口,否则 P4 无法启动实施 |
**ai04 阶段 1 审计完成。两份理解确认书 + 本审计表已交付,请 coord 审核。**

View File

@@ -0,0 +1,77 @@
# ai04 工作经验日志
> AI 标识ai04student-bff + parent-bff
> 阶段:阶段 1全局理解
> 日期2026-07-09
> 待 coord 合并到 `docs/troubleshooting/known-issues.md` "工作经验日志"区
---
## 2026-07-09 阶段 1 上下文加载
**模块**student-bffP3 待实现、parent-bffP4 待实现)
**做了什么**
1. 运行 `pnpm run arch:scan` 更新 arch.db10 TS / 2 Go / 2 Python / 138 proto 契约12 模块 342 符号)
2. 通过 3 个 search subagent 并行探索classes/teacher-bff/iam 三个 TS NestJS 模板服务结构、shared-proto 全部 8 个 .proto 契约、student-bff/parent-bff 现状与端口/路由预留
3. 阅读 README、MIGRATION_GUIDE、004 架构影响地图、pending-features 路线图
4. 产出两份模块理解确认书 + 一份服务审计表
**学到什么**
1. **teacher-bff 实际实现与设计意图存在差距**
- 004 §11.3 设计意图为 GraphQL + DataLoaderpending-features P2 明确"Teacher BFFTS/GraphQL"
- 实际 teacher-bff 是纯 REST + 原生 fetch + Promise.allSettled无 GraphQL、无 DataLoader
- ai04 建议 student-bff/parent-bff 先对齐 teacher-bff 现状REST避免技术栈分裂待 coord 仲裁是否统一升级
2. **shared-proto 契约与实际 REST 实现存在显著缺口**
- proto 包名用 `next_edu_cloud.*` 而非项目规则要求的 `edu.*`8 个文件全不合规)
- buf.gen.yaml 只配置了 protocolbuffers 序列化插件,**无 gRPC 插件**proto 目前仅作"契约文档"
- iam REST 已暴露 viewports/permissions/effective/roles 端点,但 proto 完全缺失
- content REST 已实现 chapters/questions CRUD但 proto 完全缺失
- data-ana/ai 服务的 proto 已定义但 REST 端点未实现
3. **parent-bff 存在 P0 阻塞项**
- iam 缺失"家长-学生关联查询"接口proto + REST + schema 三缺失)
- pending-features P2 提到 `parent_student_relations` 表,但 iam.schema.ts 未实现
- 需 coord 协调 ai02 在 P3 阶段补全,否则 P4 parent-bff 无法启动
4. **004 §4 服务依赖图与实际场景存在偏差**
- 004 列 parent-bff 仅依赖 iam + core-edu
- 但家长通知、学情诊断场景需要 msg + data-ana
- 需 coord 仲裁是否扩展 parent-bff 依赖
5. **端口/路由预留情况**
- student-bff=3009、parent-bff=3010 可用3001-3008 已用)
- api-gateway 未预留 `/student``/parent` 路由(需 ai01 协调)
- pnpm-workspace.yaml glob `services/*` 自动覆盖新目录
- commitlint scope-enum + CODEOWNERS 已预留 student-bff/parent-bff
6. **BFF 克隆模板策略**
- teacher-bff 是最小 BFF 模板shared/ 目录结构与 classes 完全一致
- BFF 特征:无 DB、无 repository/schema/dto、无 PermissionGuard、无 LifecycleService
- student-bff/parent-bff 可 1:1 克隆 teacher-bff 后改造11 处需改名)
**下次注意**
1. 阶段 2 设计文档需等 coord 审核阶段 1 后再产出
2. 实施前需推动 coord 协调 ai02 补全 iam 家长-学生关联接口P0 阻塞)
3. 实施前需推动 coord 协调 ai01 在 api-gateway 预留 `/student``/parent` 路由
4. proto 包名合规性(`next_edu_cloud.*``edu.*`)需 coord 仲裁是否迁移
5. buf.gen.yaml 是否补 gRPC 插件需 coord 决策
---
## 待 coord 合并到 known-issues.md "场景→技术"映射
| 场景 | 技术/规则 |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| BFF 服务克隆 teacher-bff 模板 | 复制 shared/ + 改 11 处命名package.json/env.ts/Controller/SERVICE_NAME/错误码前缀/指标名前缀/tracer serviceName/logger service/Dockerfile EXPOSE |
| BFF 不做权限校验 | 透传 `x-user-id` 给下游服务校验(对齐 teacher-bffBFF 无 PermissionGuard |
| BFF 聚合用 Promise.allSettled | Dashboard 类聚合容错(部分失败返回 null单依赖查询用 throw BadGatewayError 快速失败 |
| BFF 无 DB 依赖 | /readyz 直接返回 ok无 LifecycleService无 closeDb() |
| 新服务端口分配 | NestJS 服务按 3001-3008 顺序分配student-bff=3009、parent-bff=3010 |
| api-gateway 路由前缀命名 | BFF 用角色单数无 `-bff` 后缀teacher-bff → `/teacher`student-bff → `/student` |
| proto 包名不合规 | 当前用 `next_edu_cloud.*`,规则要求 `edu.*`8 个文件全不合规,待 coord 仲裁迁移 |
| buf.gen.yaml 缺 gRPC 插件 | 当前只配置 protocolbuffers 序列化proto 仅作"契约文档"gRPC 通信未落地 |