# 模块理解确认书 — 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-gateway(Go Gin,反向代理 `/api/v1/student/*` → student-bff:3009) | | 下游被调用方 | iam、core-edu、content、data-ana(按 004 §4 服务依赖图) | | 通信方式(入) | HTTP REST(api-gateway → student-bff,当前阶段);设计意图为 gRPC(004 §4.1) | | 通信方式(出) | HTTP fetch(当前阶段,对齐 teacher-bff 模式);设计意图为 gRPC(004 §4.1) | | 微前端对接 | student-portal(ai07 负责,P3 阶段)通过 api-gateway 调用 student-bff | | 推送通道 | push-gateway(P5 阶段,WebSocket/SSE 推送考试通知、成绩发布等) | **架构定位**(004 §1.1a + §5.4): - 按"使用场景域"分 BFF,student-bff 服务于**学习场景域**,复用角色:学生 - 不按角色分 BFF,新角色复用现有 BFF 通过视口差异化 - DataScope = **SELF(L0)**:学生只能看自己的数据(004 §5.3) --- ## 2. 我的限界上下文 ### 2.1 我负责什么 student-bff 是**纯聚合层**,不持有业务状态、不直接访问 DB(对齐 teacher-bff 模式)。职责: 1. **聚合**:并行调用多个下游业务服务,组装学生视角的复合数据 2. **裁剪**:将下游返回的领域数据裁剪为学生端所需的最小字段集 3. **协议转换**:对外暴露场景化 HTTP/GraphQL 端点,对内调用下游 REST/gRPC 4. **缓存**:聚合结果 Redis 短缓存 5-30s(004 §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 校验在 Gateway,BFF 只读 `x-user-id` 头 | | 领域事件发布 | core-edu / content | BFF 不发布事件,仅可选订阅事件用于实时推送 | | 数据范围过滤 | 下游业务服务 Repository 层 | BFF 透传 userId,下游按 DataScope=SELF 过滤 | | 班级管理 | core-edu(classes 模块) | 学生只读自己所在班级 | | 考试批改 | 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` | 获取有效权限列表 | | classes(core-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 BFF(TS/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` 成绩查看 | | 依赖上游阶段产出 | P1(api-gateway 路由骨架 + classes 黄金模板 + shared-proto)、P2(iam 认证 + 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_` 模式 | | logger(pino) | ✅ `shared/observability/logger.ts` | ✅ 复制 teacher-bff 实现 | service 名改 `student-bff` | | metrics(prom-client) | ✅ `/metrics` 端点 | ✅ 复制 teacher-bff main.ts 注册方式 | 指标名前缀 `student_bff_` | | tracer(OpenTelemetry) | ✅ 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 服务未实现查询 API(analytics.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 现状)
B. GraphQL(对齐 004 §11.3 设计意图 + pending-features P2) | **A**(P3 阶段先 REST,避免技术栈分裂;后续统一升级) | | BFF 是否做权限校验 | A. 不校验(对齐 teacher-bff,透传 x-user-id)
B. 加 `@RequirePermission` 装饰器 | **A**(BFF 是聚合层,权限由下游服务校验) | | `/readyz` 检查逻辑 | A. 直接返回 ok(对齐 teacher-bff)
B. 检查下游服务可达性 | **A**(P3 阶段,下游可达性由 Prometheus 监控) | | Kafka 事件订阅 | A. P3 不订阅(仅同步聚合)
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 服务定义 | coord(infra) | 端口 3009,加入 edu-net + edu-shared 网络 | | full-stack-runbook 端口矩阵更新 | coord(docs) | 追加 3009 行 | | 004 架构图状态更新 | coord(docs) | student-bff 状态从"📐 需设计"改为"✅ 已实现" | | shared-proto 补全 content.proto(Chapter/Question) | coord | P4 阶段 content 服务落地前补全 | | shared-proto 补全 iam.proto(Viewport/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(模块架构设计文档)。**