Files
Edu/services/parent-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

38 KiB
Raw Blame History

模块理解确认书 — parent-bff

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


1. 我在架构中的位置

维度 内容
层级 L4 BFF 聚合层004 §3.1 六层架构)
上游调用方 api-gatewayGo Gin反向代理 /api/v1/parent/* → parent-bff:3010
下游被调用方 iam、core-edu按 004 §4 服务依赖图parent-bff 依赖最少)
通信方式(入) HTTP RESTapi-gateway → parent-bff当前阶段设计意图为 gRPC004 §4.1
通信方式(出) HTTP fetch当前阶段对齐 teacher-bff 模式);设计意图为 gRPC004 §4.1
微前端对接 parent-portalai07 负责P4 阶段)通过 api-gateway 调用 parent-bff
推送通道 push-gatewayP5 阶段WebSocket/SSE 推送孩子成绩发布、作业批改等通知)

架构定位004 §1.1a + §5.4

  • 按"使用场景域"分 BFFparent-bff 服务于家长场景域,复用角色:家长
  • 不按角色分 BFF新角色复用现有 BFF 通过视口差异化
  • DataScope = CHILDREN自定义级家长只能看自己绑定孩子的数据004 §5.3 的 L0 SELF 变体dataScope 枚举值含 children,见 004 §5.4 iam 服务职责)

004 §4 服务依赖图明确

PBFF --> IAM
PBFF --> CoreEdu

parent-bff 仅依赖 iam + core-edu不直接依赖 content / data-ana / msg / ai。这是设计意图:家长场景的核心是"查看孩子的教学数据",教学数据由 core-edu 提供。但 ai-allocation.md §5 ai04 设计重点提到"家长通知偏好配置",意味着 parent-bff 可能需要调用 msg 服务。此差异需 coord 仲裁(见 §7.2)。


2. 我的限界上下文

2.1 我负责什么

parent-bff 是纯聚合层,不持有业务状态、不直接访问 DB对齐 teacher-bff 模式)。职责:

  1. 多子女账户切换家长账号可绑定多个孩子parent-bff 维护"当前选中孩子"上下文
  2. 聚合:并行调用 iam查家长信息 + 孩子列表)+ core-edu查孩子的教学数据
  3. 裁剪:将下游返回的领域数据裁剪为家长端所需的最小字段集
  4. 协议转换:对外暴露场景化 HTTP/GraphQL 端点,对内调用下游 REST/gRPC
  5. 缓存:聚合结果 Redis 短缓存 5-30s004 §6.2 BFF 混合读策略)
  6. 通知偏好:家长可配置通知偏好(哪些事件推送、哪些不推送),存于 msg 服务或 iam 服务

2.2 我的聚合场景(家长视角)

场景 聚合的下游服务 用途
家长首页 Dashboard iam /iam/me + iam /iam/children(缺失) + core-edu /grades/student/:childId 个人信息 + 孩子列表 + 孩子近期成绩
切换当前孩子 iam /iam/children(缺失) + core-edu /homework/class/:classId 切换上下文后加载孩子数据
孩子的考试成绩 core-edu /exams/class/:classId + /grades/student/:childId 孩子所在班级考试 + 孩子成绩
孩子的作业情况 core-edu /homework/class/:classId 孩子作业列表 + 提交状态
孩子的成绩趋势 data-ana /analytics/student/:childId/trend004 未列入依赖,待仲裁) 历史成绩曲线
孩子的学情诊断 data-ana /analytics/student/:childId/weakness(待仲裁) 薄弱知识点
班级学情对比 data-ana /analytics/class/:classId/performance(待仲裁) 孩子相对班级的位置
消息中心 msg /notifications004 未列入依赖,待仲裁) 家长通知列表
通知偏好配置 msg 或 iam缺失 配置哪些事件推送
孩子的出勤 core-edu /attendance/student/:childId(缺失) 出勤记录

2.3 我不负责什么(明确边界外)

不负责项 归属服务 说明
业务数据持久化 core-edu / iam BFF 不写 DB
权限校验 下游业务服务 + iam BFF 不做权限校验(对齐 teacher-bff透传 x-user-id 让下游校验
用户认证 iam + api-gateway JWT 校验在 GatewayBFF 只读 x-user-id
学生-家长关系维护 iam 或 core-edu缺失 parent-bff 只读取关系,不维护
领域事件发布 core-edu BFF 不发布事件,仅可选订阅事件用于实时推送
数据范围过滤 下游业务服务 Repository 层 BFF 透传 userId + childId下游按 DataScope=CHILDREN 过滤
考试批改 core-edu 家长不能批改,只能查看孩子成绩
孩子的作业提交 core-edu学生端职责 家长不能代孩子提交作业

3. 我与外部的契约

3.1 我消费的 proto message / 下游接口

⚠️ 重要差距:当前阶段 BFF→Service 走 HTTP fetch对齐 teacher-bff 现状proto 仅作"契约文档"。gRPC 落地需 coord 在 buf.gen.yaml 补 gRPC 插件。 ⚠️ 核心依赖缺失iam 没有"家长-学生关联查询"接口parent-bff 无法实现核心场景。

下游服务 proto service设计意图 当前 REST 端点(实际可用) 用途
iam IamService.GetUserInfo GET /iam/me 获取家长个人信息
iam IamService.GetViewportsproto 缺失) GET /iam/viewports 获取家长端导航视口
iam IamService.GetEffectivePermissionsproto 缺失) GET /iam/permissions/effective 获取有效权限列表
iam GetChildrenByParentproto + REST 双缺失) 查询家长绑定的孩子列表(核心缺失)
iam GetParentsByStudentproto + REST 双缺失) 反向查询(可选)
classescore-edu ClassService.GetClass GET /classes/:id 查孩子所在班级信息
core-edu ExamService.GetExam / ListExamsByClass GET /exams/class/:classId 查孩子班级考试
core-edu HomeworkService.ListHomeworkByClass GET /homework/class/:classId 查孩子作业
core-edu GradeService.GetGrade / ListGradesByStudent / ListGradesByExam GET /grades/student/:childId / GET /grades/exam/:examId 查孩子成绩
core-edu AttendanceServiceproto + REST 双缺失) 查孩子出勤(全局缺失)
data-ana AnalyticsService.GetClassPerformance / GetStudentWeakness / GetLearningTrend REST 未实现 学情分析004 未列入依赖,待仲裁)
msg NotificationService.ListNotifications / MarkAsRead GET /notificationsmsg 服务 P5 才落地) 家长通知004 未列入依赖,待仲裁)
msg 或 iam 通知偏好配置proto + REST 双缺失) 配置推送偏好

3.2 我暴露的 API 端点parent-bff 对外)

路由前缀:/parent(对齐 teacher-bff 用 /teacher 的命名规律) 网关路径:/api/v1/parent/* → api-gateway 剥离 /api/v1 后代理到 parent-bff:3010

method path 聚合下游 权限(透传给下游校验) 说明
GET /parent/dashboard iam + core-edu PARENT_DASHBOARD_READ 家长首页(含孩子列表 + 近期成绩)
GET /parent/children iam PARENT_CHILDREN_READ 我的孩子列表
POST /parent/children/:childId/select BFF 内部状态) PARENT_CHILDREN_READ 切换当前选中孩子sessionId 或 cookie
GET /parent/children/:childId/exams core-edu PARENT_EXAM_READ 孩子的考试列表
GET /parent/children/:childId/homework core-edu PARENT_HOMEWORK_READ 孩子的作业列表
GET /parent/children/:childId/grades core-edu PARENT_GRADE_READ 孩子的成绩列表
GET /parent/children/:childId/analytics/trend data-ana待仲裁 PARENT_ANALYTICS_READ 孩子成绩趋势
GET /parent/children/:childId/analytics/weakness data-ana待仲裁 PARENT_ANALYTICS_READ 孩子薄弱知识点
GET /parent/notifications msg待仲裁 PARENT_NOTIFICATION_READ 家长通知列表
POST /parent/notifications/:id/read msg待仲裁 PARENT_NOTIFICATION_READ 标记已读
GET /parent/notification-preferences msg 或 iam缺失 PARENT_PREFERENCE_READ 通知偏好配置
PUT /parent/notification-preferences msg 或 iam缺失 PARENT_PREFERENCE_UPDATE 更新通知偏好

3.3 错误码前缀

前缀 用途 示例
PARENT_BFF_ parent-bff 自身错误 PARENT_BFF_UNAUTHORIZEDPARENT_BFF_BAD_GATEWAYPARENT_BFF_CHILD_NOT_BOUND
下游错误透传 下游服务错误码原样返回 IAM_USER_NOT_FOUNDCORE_EDU_GRADE_NOT_FOUND

错误类清单(对齐 teacher-bff application-error.ts + 新增家长特有错误):

  • UnauthorizedError(401) — 缺失 x-user-id
  • BadGatewayError(502) — 下游服务返回非 ok 或 fetch rejected
  • ValidationError(400) — 入参校验失败BFF 层 Zod 校验)
  • BusinessError(422) — 业务校验失败(如家长查询的 childId 不在自己绑定列表内)
  • NotFoundError(404) — 资源不存在
  • InternalError(500) — 未捕获异常

家长特有错误

  • PARENT_BFF_CHILD_NOT_BOUND(403) — 家长查询的 childId 未在自己绑定的孩子列表内DataScope=CHILDREN 越权)

3.4 我订阅的 Kafka 事件(可选,用于实时推送)

Topic 事件 消费动作
edu.grade.events grade.recorded 推送给家长(孩子成绩发布)
edu.homework.events homework.graded 推送给家长(孩子作业批改完成)
edu.exam.events exam.published 推送给家长(考试提醒)

⚠️ Kafka 订阅在 P5 阶段 push-gateway 落地后才有意义P4 阶段 parent-bff 可不消费事件,仅做同步聚合。 ⚠️ 家长通知偏好配置生效后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 混合读策略
会话状态 Redis当前选中孩子 childId 多子女账户切换,不持久化在 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 现状;与 student-bff 一致,需 coord 仲裁是否统一升级 GraphQL
输入校验 Zod 对齐 classes/teacher-bff
错误处理 GlobalErrorFilter + ApplicationError 对齐 classes/teacher-bff
ESM 模式 NodeNext + .js 后缀 import 对齐 teacher-bff tsconfig
测试框架 Jest待定对齐 classes 黄金模板要求测试覆盖率 ≥ 80%

4.1 关于 GraphQL 的设计决策(待 coord 仲裁)

与 student-bff §4.1 相同的矛盾ai04 建议 P4 阶段 parent-bff 先对齐 teacher-bff 现状REST + fetch + Promise.allSettled,与 student-bff 保持一致。此决策需 coord 仲裁。

4.2 关于多子女账户切换的设计

问题:家长账号绑定多个孩子,前端需要知道"当前选中的孩子"。

方案对比

方案 实现 优点 缺点
A. 前端管理 前端在 URL query 或 localStorage 存 childId每次请求带上 BFF 无状态,简单 切换后页面状态丢失风险
B. BFF Session Redis 存 parent:userId:currentChildIdBFF 读取 切换全局生效 BFF 引入会话状态,违反"无状态服务"约束004 §12.1
C. JWT Claims iam 在 JWT 中注入 currentChildId claim 与认证一体化 切换孩子需重签 JWT成本高

ai04 建议方案 A(前端管理 childIdBFF 无状态),符合 004 §12.1"无状态服务"约束。POST /parent/children/:childId/select 端点可选,仅用于记录切换日志(审计),不持久化会话。


5. 我的阶段归属

维度 内容
阶段 P4 内容分析阶段M11-M13
退出标准pending-features P4 教师查看知识图谱前置依赖Neo4j 秒级返回)→ 学生查看学情诊断ClickHouse 宽表 5s 内返回)→ CDC 链路延迟 < 5s
parent-bff 在 P4 的最小交付 家长查看孩子成绩 + 学情诊断(双轨读:实时查 core-edu 主库 + 聚合查 data-ana ClickHouse 宽表)
依赖上游阶段产出 P1api-gateway + classes 黄金模板 + shared-proto、P2iam 认证 + teacher-bff BFF 模板、P3core-edu 考试/作业/成绩 + student-bff BFF 模式验证)
P4 同阶段依赖 contentP4 落地、data-anaP4 落地,学情诊断 API
P5 阶段扩展 msg 通知 + push-gateway 推送 + 通知偏好配置
前置阻塞 iam 必须先补"家长-学生关联查询"接口(见 §7.1

5.1 P4 阶段最小可行集合MVP

parent-bff 在 P4 阶段优先级:

优先级 端点 P4 必需 说明
P0 /parent/children GET 家长核心场景:查孩子列表(依赖 iam 补接口)
P0 /parent/children/:childId/grades GET 查孩子成绩
P0 /parent/dashboard GET 家长首页
P1 /parent/children/:childId/exams GET 孩子考试
P1 /parent/children/:childId/homework GET 孩子作业
P1 /parent/children/:childId/analytics/trend GET 学情趋势(依赖 data-ana P4 落地)
P1 /parent/children/:childId/analytics/weakness GET 薄弱知识点
P2 /parent/notifications GET ⚠️ 可选 P5 msg 服务落地后才有意义
P2 /parent/notification-preferences GET/PUT ⚠️ 可选 P5 落地

5.2 与 student-bff 的协同

parent-bff 与 student-bff 同属 ai04 负责,技术栈完全一致(同语言、同框架、同 BFF 模式)。两者共享:

  • teacher-bff 克隆模板shared/ 目录结构、main.ts、env.ts、health.controller.ts 等基础代码
  • 聚合模式Promise.allSettled 并行调用 + BadGatewayError 错误处理
  • 可观测性pino + prom-client + OTel 三支柱
  • 错误码前缀PARENT_BFF_ / STUDENT_BFF_ 仅前缀不同

差异点

  • parent-bff 多了"多子女账户切换"上下文
  • parent-bff 多了"DataScope=CHILDREN 越权校验"(家长查询的 childId 必须在自己绑定列表内)
  • parent-bff 不直接依赖 content / msg / ai按 004 §4但实际场景可能需要待 coord 仲裁)

6. 我需要对齐的黄金模板项(对照 classes 服务)

对照 ai-allocation.md §6 模板第 6 节 + §10 审计模板

对齐项 classes 黄金模板 parent-bff 计划 备注
权限装饰器 @RequirePermission 全部 Controller 方法 ⚠️ 不对齐 BFF 不做权限校验(对齐 teacher-bff透传 x-user-id 给下游校验
错误码前缀统一 CLASSES_ PARENT_BFF_ 对齐 teacher-bff 的 TEACHER_BFF_ 模式
loggerpino shared/observability/logger.ts 复制 teacher-bff 实现 service 名改 parent-bff
metricsprom-client /metrics 端点 复制 teacher-bff main.ts 注册方式 指标名前缀 parent_bff_
tracerOpenTelemetry OTLP exporter + auto-instrumentations 复制 teacher-bff tracer.ts serviceName 改 parent-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 连接
测试覆盖率 ≥ 80% Jest ⚠️ 待补 BFF 测试重点是 Service 层聚合逻辑 + DataScope 越权校验
Dockerfile 多阶段构建 builder + runtime 复制 teacher-bff Dockerfile EXPOSE 改 3010
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 现值 parent-bff 应改为
package.json name @edu/teacher-bff @edu/parent-bff
src/config/env.ts PORT default "3003" "3010"
src/config/env.ts 下游 URL IamServiceUrl / ClassesServiceUrl / CoreEduServiceUrl + DataAnaServiceUrl / MsgServiceUrl按仲裁结果
src/teacher/ 目录名 teacher/ parent/
@Controller("teacher") "teacher" "parent"
health.controller.ts SERVICE_NAME "teacher-bff" "parent-bff"
application-error.ts 错误码前缀 TEACHER_BFF_ PARENT_BFF_
application-error.ts 新增错误类 ChildNotBoundError(403)DataScope=CHILDREN 越权)
metrics.ts 指标名前缀 teacher_bff_ parent_bff_
tracer.ts serviceName "teacher-bff" "parent-bff"
logger.ts service "teacher-bff" "parent-bff"
main.ts 启动日志 "Teacher BFF started" "Parent BFF started"
Dockerfile EXPOSE 3003 3010

7. 风险与依赖(待 coord 仲裁)

7.1 上游依赖缺口(核心阻塞)

风险 影响 缓解措施
iam 缺失"家长-学生关联查询"接口proto + REST + schema 三缺失) P0 阻塞parent-bff 核心场景无法实现 推动 coord 协调 ai02 在 iam 补1) iam_student_guardians2) Repository 查询方法3) GET /iam/children REST 端点4) proto GetChildrenByParent RPC
pending-features P2 提到 parent_student_relations 表,但 iam.schema.ts 未实现 表缺失 同上,推动 ai02 补表
data-ana 服务未实现查询 APIanalytics.proto 3 个 method 无 REST 端点) P4 学情诊断端点无法实现 推动 ai06 在 P4 实现 data-ana 查询 API
content.proto 缺 Chapter/Question 域 parent-bff 不直接依赖 content影响较小 推动 coord 在 shared-proto 补全P4 content 服务落地前)
iam.proto 缺 Viewport/EffectivePermissions 家长端导航视口 proto 契约不全 当前走 REST /iam/viewportsproto 补全后切换
出勤attendance全局缺失 家长无法查孩子出勤 推动 coord 在 core_edu.proto 补 Attendance 域P4 或后续)
msg 通知偏好配置接口缺失 家长通知偏好无法配置 推动 ai05 在 msg 服务补接口P5 阶段)

7.2 设计决策待仲裁

决策点 选项 ai04 建议
BFF API 风格 A. REST对齐 teacher-bff 现状)
B. GraphQL对齐 004 §11.3 设计意图)
A(与 student-bff 保持一致)
BFF 是否做权限校验 A. 不校验(对齐 teacher-bff透传 x-user-id
B. 加 @RequirePermission 装饰器
ABFF 是聚合层,权限由下游服务校验)
DataScope=CHILDREN 越权校验位置 A. BFF 校验(家长查询的 childId 必须在绑定列表内)
B. 下游服务校验core-edu 接收 childId 时校验)
ABFF 层校验更早失败,减少下游调用;但需 iam 提供"查询家长绑定孩子列表"接口)
多子女账户切换方案 A. 前端管理 childIdBFF 无状态)
B. BFF SessionRedis 存当前 childId
C. JWT Claims
A(符合 004 §12.1 无状态约束)
004 §4 依赖图与实际场景的偏差 004 列 parent-bff 仅依赖 iam + core-edu但家长通知、学情诊断需要 msg + data-ana 建议扩展依赖parent-bff → iam + core-edu + data-ana + msg与 student-bff 对齐),需 coord 仲裁并更新 004 §4
Kafka 事件订阅 A. P4 不订阅(仅同步聚合)
B. P4 订阅事件推送
Apush-gateway P5 才落地)
通知偏好存储位置 A. msg 服务(通知域内)
B. iam 服务(用户偏好域内)
A(通知偏好与通知发送强相关,归 msg 服务)
端口分配 3010 对齐 full-stack-runbook 端口矩阵3001-3009 已用/将用)

7.3 跨模块协作需求(需提交 coord 协调)

需求 涉及 AI 协调内容
iam 新增家长-学生关联接口P0 阻塞) ai02 iam_student_guardians 表 + Repository + GET /iam/children 端点 + proto GetChildrenByParent RPC
api-gateway 新增 /parent 路由 ai01 在 main.go + config.go 新增 ParentBffURL 字段 + 路由块
docker-compose.deploy.yml 新增 parent-bff 服务定义 coordinfra 端口 3010加入 edu-net + edu-shared 网络
full-stack-runbook 端口矩阵更新 coorddocs 追加 3010 行
004 架构图状态更新 + 依赖图仲裁 coorddocs parent-bff 状态从"📐 需设计"改为" 已实现";仲裁是否扩展 parent-bff 依赖到 data-ana + msg
shared-proto 补全 iam.protoViewport/EffectivePermissions/StudentParentRelation coord 推动 ai02 补 proto
shared-proto 补全 core_edu.protoAttendance 域) coord 推动 ai03 补 proto
data-ana 实现 analytics.proto 查询 API ai06 P4 阶段落地
buf.gen.yaml 补 gRPC 插件 coord 决定是否在 P4 升级到 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
已识别端口/路由预留情况 3010 可用,路由未预留)
已识别设计决策待仲裁项 (见 §7.2
已识别跨模块协作需求 (见 §7.3
已识别 P0 阻塞项 iam 家长-学生关联接口缺失)

ai04 阶段 1 交付完成,请 coord 审核。审核通过后进入阶段 2模块架构设计文档

特别提示 coordparent-bff 存在 P0 阻塞项——iam 缺失"家长-学生关联查询"接口。建议 coord 优先协调 ai02 在 P3 阶段parent-bff P4 落地前)补全此接口,否则 P4 阶段 parent-bff 无法启动实施。