Files
Edu/services/student-bff/docs/01-understanding.md
SpecialX 0a71b02e04
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
fix: code compliance audit and fix across all services
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.
2026-07-09 17:28:27 +08:00

32 KiB
Raw Blame History

模块理解确认书 — student-bff

AI 标识ai04 阶段:阶段 1全局理解 日期2026-07-09 状态:待 coord 审核 关联文档:ai-allocation §6 模板004 架构影响地图pending-features P3


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-chatSSE 流式) 智能答疑辅助
个性化学习路径 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.GetViewportsproto 缺失) GET /iam/viewports 获取学生端导航视口
iam IamService.GetEffectivePermissionsproto 缺失) 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 ChapterServiceproto 缺失) GET /chapters / GET /chapters/:id 查章节
content QuestionServiceproto 缺失) 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_UNAUTHORIZEDSTUDENT_BFF_BAD_GATEWAY
下游错误透传 下游服务错误码原样返回 CLASSES_NOT_FOUNDIAM_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/viewportsproto 补全后切换
出勤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
AP3 阶段先 REST避免技术栈分裂后续统一升级
BFF 是否做权限校验 A. 不校验(对齐 teacher-bff透传 x-user-id
B. 加 @RequirePermission 装饰器
ABFF 是聚合层,权限由下游服务校验)
/readyz 检查逻辑 A. 直接返回 ok对齐 teacher-bff
B. 检查下游服务可达性
AP3 阶段,下游可达性由 Prometheus 监控)
Kafka 事件订阅 A. P3 不订阅(仅同步聚合)
B. P3 订阅事件推送
Apush-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模块架构设计文档