Files
Edu/docs/architecture/issues/worklines/parent-bff_workline.md

17 KiB
Raw Permalink Blame History

parent-bff 工作排期

负责人ai05 关联:workline.mdcoord.mdcontracts/parent-bff_contract.md02-architecture-design.md 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,开发期间用 mock最后统一集成测试


§1 总览

parent-bff 为家长端提供 GraphQL 聚合 API端口 3010覆盖 Dashboard、多子女切换、成绩趋势、学情诊断、通知偏好等场景。

全阶段目标

阶段 交付核心 依赖
P4 MVP GraphQL Yoga + DataLoader + 多子女切换 + ChildGuard + 并行 gRPC 聚合 + Redis 缓存 + /readyz 下游探针 iam.GetChildrenByParentI6 裁决)+ core-edu gRPC + data-ana gRPC
P5 通知接入 msg gRPC + push-gateway HTTP + Kafka consumer 缓存失效 + 通知偏好过滤 msg gRPC 50056 + push-gateway /internal/push
P6 硬化 熔断器 opossum + HPA + SLO 监控 + 灰度发布

关键路径:批次 0coord 补 proto→ 批次 1iam gRPC + GetChildrenByParent→ 批次 2core-edu gRPC批次 3parent-bff P4 MVP → 批次 4msg P5→ parent-bff P5 接入

P0 阻塞项(详见 objections/parent-bff_issue.md ISSUE-008/007

  • iam.GetChildrenByParent RPC + iam_student_guardians 表I6 裁决ai06 负责)
  • core-edu ClassService.GetClass proto 缺失ISSUE-008待 coord 仲裁归属)
  • msg.proto Notification 缺 child_id 字段ISSUE-007P5 阶段阻塞)

§2 全阶段甘特图P2-P6

gantt
    title ai05 parent-bff 全阶段排期(全并行 + mock
    dateFormat YYYY-MM-DD
    axisFormat %m-%d

    section P4 MVP 核心
    P4.1 骨架搭建(env+main+health) :crit, a5a, 2026-07-31, 2d
    P4.2 GraphQL Yoga+schema第一版 :crit, a5b, after a5a, 3d
    P4.3 DownstreamClient抽象+gRPC mock :crit, a5c, after a5a, 2d
    P4.4 ChildGuard+DataLoader实现 :crit, a5d, after a5b, 3d
    P4.5 Dashboard/children/grades Resolver :a5e, after a5d, 2d
    P4.6 Redis缓存层+ Orchestrator降级 :a5f, after a5e, 2d
    P4.7 /readyz下游探针+可观测三支柱 :a5g, after a5f, 1d
    P4.8 单元+集成测试(≥80%覆盖) :a5h, after a5g, 2d

    section P5 通知接入
    P5.1 msg gRPC client接入 :b5a, after a5h, 2d
    P5.2 Notification Resolver+偏好配置 :b5b, after b5a, 2d
    P5.3 push-gateway HTTP /internal/push :b5c, after b5a, 1d
    P5.4 Kafka consumer订阅+缓存失效 :b5d, after b5c, 3d
    P5.5 通知偏好过滤逻辑 :b5e, after b5d, 1d

    section P6 硬化
    P6.1 opossum熔断器per-service :c5a, after b5e, 2d
    P6.2 HPA+podAntiAffinity :c5b, after c5a, 1d
    P6.3 SLO告警规则+灰度发布 :c5c, after c5b, 2d

说明:以上日期为 coord 总排期推算(批次 3 P4 在批次 2 P3 完成后启动。全并行模式下P4/P5/P6 代码一口气完成,上游未就绪时用 mock最后统一集成测试。


§3 详细任务

P4.1骨架搭建env + main + health

  • 负责人ai05
  • 依赖:无(克隆 teacher-bff 骨架)
  • 交付物
    • services/parent-bff/package.jsonname=@edu/parent-bff
    • src/config/env.tsZod 校验,见 02 §12.1 完整配置项)
    • src/main.ts(启动 + /metrics + SIGTERM 优雅关闭)
    • src/app.module.ts
    • src/shared/health/health.controller.ts/healthz 直接 ok
    • src/shared/observability/{logger,metrics,tracer}.tsservice=parent-bff
    • src/shared/errors/{application-error,global-error.filter}.tsBFF_PARENT_ 前缀)
    • Dockerfile多阶段EXPOSE 3010
    • tsconfig.jsonNodeNext + ESM .js 后缀)
  • 验收标准pnpm run typecheck + pnpm run lint 零错误;docker build 通过;本地启动 /healthz 返回 200

P4.2GraphQL Yoga + schema 第一版

  • 负责人ai05
  • 依赖P4.1
  • 交付物
    • src/entry/graphql.controller.tsPOST /graphql + GET /graphql playground 仅 dev
    • src/entry/context.middleware.ts(解析 x-user-id/x-user-roles/x-request-id 注入 GraphQL context
    • src/graphql/schema.tstypeDefs + resolvers见 02 §4.2 GraphQL schema
    • src/graphql/types/parent/child/grade/homework/exam/analytics/notification.type.ts
    • GraphQL 复杂度限制depth ≤ 7cost ≤ 100002 §9 #5
    • packages/shared-ts/contracts/graphql/parent-bff.graphqlSDL-first 集中管理,对齐 coord ARB-001 模式)
  • 验收标准POST /graphql 可内省 schema深度超 7 的查询被拒cost 超 1000 被拒

P4.3DownstreamClient 抽象 + gRPC mock

  • 负责人ai05
  • 依赖P4.1 + ai03 DownstreamClient 抽象模式teacher-bff 参考)
  • 交付物
    • src/clients/grpc/grpc.factory.tsgRPC client 创建 + interceptortrace/metrics/retry
    • src/clients/iam.client.tsIamClient interface + gRPC impl + mock impl
    • src/clients/core-edu.client.tsCoreEduClient interface + gRPC impl + mock impl
    • src/clients/data-ana.client.tsDataAnaClient interface + gRPC impl + mock impl
    • mock 数据:固定 2 个孩子student-001 李同学 + student-002 李妹妹)+ 固定成绩/作业/考试/学情
  • 验收标准DEV_MODE=true 时走 mock impl返回固定数据mock 数据 student_id 与 core-edu mock 一致(见 contract.md §4.2

P4.4ChildGuard + DataLoader 实现

  • 负责人ai05
  • 依赖P4.2 + P4.3
  • 交付物
    • src/aggregation/child-guard.tsDataScope=CHILDREN 越权校验,见 02 §2.3
      • 30s TTL Redis 缓存绑定列表ISSUE-002 修正§3.1.1 同步为 30s
      • singleflight 模式防缓存击穿02 §14 #5
      • 越权时抛 BFF_PARENT_CHILD_NOT_BOUND(403)
    • src/dataloader/dataloader.module.tsper-request 实例注册器)
    • src/dataloader/{children,grade,homework,exam}.dataloader.ts(批量去重 N+1 防御)
  • 验收标准
    • childId ∉ 绑定列表时抛 403
    • 30s 内第二次查询不调 iam.GetChildrenByParent
    • 并发 100 请求只调 iam 1 次singleflight
    • DataLoader 同 parentId 多次调用合并为 1 次 gRPC

P4.5Dashboard / children / grades Resolver

  • 负责人ai05
  • 依赖P4.4
  • 交付物
    • src/graphql/resolvers/dashboard.resolver.ts(聚合 iam.GetUserInfo + iam.GetChildrenByParent + core-edu.ListGradesByStudent 并行)
    • src/graphql/resolvers/child.resolver.tschildQuery + ChildGuard 校验 + 延迟加载 grades/homework/exams/analytics
    • src/graphql/resolvers/select-child.resolver.tsmutation仅审计日志不持久化
    • src/graphql/resolvers/grade.resolver.tschildGrades query含分页
  • 验收标准
    • dashboard Query 返回 parent + children + unreadNotifications
    • child(childId) 对未绑定 childId 返回 403
    • selectChild mutation 记录审计日志traceId + parentId + childId + timestamp

P4.6Redis 缓存层 + Orchestrator 降级

  • 负责人ai05
  • 依赖P4.5
  • 交付物
    • src/shared/cache/redis.client.tsioredis 连接)
    • src/shared/cache/cache-key.builder.tsbff:parent:* 前缀,见 02 §3.1.1
    • src/aggregation/orchestrator.tsPromise.allSettled 并行 + 降级标记 partial
    • src/aggregation/response-mapper.tsproto → GraphQL type含 Grade.score string→Float 转换ISSUE-008
    • src/aggregation/fallback-strategy.ts(下游失败时返回缓存陈旧数据或 null 字段)
  • 验收标准
    • dashboard 聚合结果缓存 15s第二次命中不调下游
    • data-ana 失败时返回 dashboard.degraded=true其他字段正常
    • Redis 不可用时降级为内存 LRU

P4.7/readyz 下游探针 + 可观测三支柱

  • 负责人ai05
  • 依赖P4.6
  • 交付物
    • src/shared/health/health.controller.ts 补 /readyz 下游探针02 §9 #7 ai05 调整)
      • 探针iam gRPC + core-edu gRPC + data-ana gRPC + Redis超时 1s/服务
      • 任一失败返回 503 + degraded=true
    • metrics 指标全量落地02 §6.4 表格 11 项指标)
    • tracer auto-instrumentationshttp/nestjs/express/ioredis/grpc-js
    • logger 字段对齐parentId/childId/operation/traceId
  • 验收标准
    • /readyz 返回 4 项依赖状态
    • /metrics 暴露 parent_bff_* 指标
    • Jaeger 可看到 dashboard 请求完整 span 链

P4.8:单元 + 集成测试≥80% 覆盖)

  • 负责人ai05
  • 依赖P4.7
  • 交付物
    • test/unit/child-guard.test.ts(越权拦截 + 缓存命中 + singleflight
    • test/unit/orchestrator.test.ts(并行编排 + 部分失败降级)
    • test/unit/dataloader.test.ts(批量去重)
    • test/unit/graphql-complexity.test.tsdepth/cost 限制)
    • test/integration/dashboard.test.ts3 子女 × 3 下游并行Redis Testcontainers
    • test/integration/readyz.test.tsiam 故障时 503
    • vitest.config.ts(覆盖率阈值 80%
  • 验收标准:覆盖率 ≥ 80%10 项关键用例02 §11.2)全部通过

P5.1msg gRPC client 接入

  • 负责人ai05
  • 依赖msg gRPC 50056 就绪ai10或 mock
  • 交付物
    • src/clients/msg.client.tsMsgClient interface + gRPC impl + mock impl
    • env.ts 启用 MsgServiceUrl / MsgGrpcTarget
  • 验收标准mock 模式下 NotificationService.ListNotifications / MarkAsRead 可调

P5.2Notification Resolver + 偏好配置

  • 负责人ai05
  • 依赖P5.1 + msg.proto 补 child_id 字段ISSUE-007 仲裁结果)
  • 交付物
    • src/graphql/resolvers/notification.resolver.tsnotifications query + markNotificationRead mutation
    • src/graphql/resolvers/notification-preference.resolver.tsnotificationPreferences query + updateNotificationPreferences mutation
    • src/parent/dto/parent-inputs.dto.tsUpdateNotificationPreferencesSchema Zod 校验)
  • 验收标准notifications Query 返回家长通知列表(含 childId偏好更新后缓存失效

P5.3push-gateway HTTP /internal/push 接入

  • 负责人ai05
  • 依赖push-gateway /internal/push 就绪ai02或 mock
  • 交付物
    • src/clients/http/push-http.client.tsHTTP POST /internal/pushU2 仲裁)
    • env.ts 启用 PushGatewayUrl
  • 验收标准mock 模式下 pushViaHttp 返回 success

P5.4Kafka consumer 订阅 + 缓存失效

  • 负责人ai05
  • 依赖Kafka topic 已创建C5 仲裁edu.notification.sent/read/recalled/failed + edu.teaching.grade.recorded/homework.graded/exam.published
  • 交付物
    • src/shared/kafka/kafka.consumer.tsconsumer group: parent-bff-event-subscriber
    • src/shared/kafka/handlers/notification-push.handler.ts(偏好过滤 + push-gateway 推送)
    • src/shared/kafka/handlers/cache-invalidation.handler.ts(成绩/作业/考试事件失效对应缓存)
    • 幂等性Redis SETNX event_id 去重
    • DLQedu.parent-bff.dlq
  • 验收标准
    • 收到 edu.teaching.grade.recorded 后 bff:parent:grades:{childId} 缓存失效
    • 家长关闭"成绩推送"偏好时,该家长不收到推送
    • 重复 event_id 不重复处理

P5.5:通知偏好过滤逻辑

  • 负责人ai05
  • 依赖P5.4
  • 交付物:通知偏好过滤逻辑集成到 notification-push.handler02 §5.4
    • 拉取家长 NotificationPreferencesRedis 缓存 300s
    • 按 eventTypeMap 映射事件类型 → 偏好开关
    • 取 prefs.channels 与 event.channels 交集
  • 验收标准:偏好开关为 false 时不推送channels 无交集时不推送

P6.1opossum 熔断器 per-service

  • 负责人ai05
  • 依赖P5 完成
  • 交付物
    • src/clients/grpc/circuit-breaker.tsopossumper-downstream-service 独立 circuitiam/core-edu/data-ana/msg
    • 熔断开启时抛 BFF_PARENT_SERVICE_UNAVAILABLE(503)
    • metrics: parent_bff_circuit_state Gauge
  • 验收标准:下游连续失败 5 次熔断开启30s 后半开探测

P6.2HPA + podAntiAffinity

  • 负责人ai05
  • 依赖P6.1
  • 交付物infra/k8s/helm/parent-bff/ Chart对齐 004 §1.2 端口)
    • HPA 2-10 副本CPU 70% / 内存 80% 触发)
    • podAntiAffinity 跨节点分布
    • values-dev.yaml / values-staging.yaml / values-prod.yaml
  • 验收标准helm template 通过HPA 可根据负载扩缩

P6.3SLO 告警规则 + 灰度发布

  • 负责人ai05
  • 依赖P6.2
  • 交付物
    • infra/prometheus/rules.yml 追加 parent-bff 告警规则P95 > 200ms / 错误率 > 0.1% / 可用性 < 99.9%
    • infra/grafana/dashboards/parent-bff.json 面板
    • 灰度发布:按 parentId hash 路由流量百分比K8s Service + Istio/Envoy weight
  • 验收标准Prometheus 告警规则 lint 通过Grafana 面板可展示 parent-bff 指标

§4 依赖与就绪信号

4.1 我依赖的上游就绪标志

上游 就绪信号 责任方 阻塞阶段 状态
iam gRPC 50052 + GetChildrenByParent RPC HealthService.Check = SERVING + GetChildrenByParent 可调 ai06 P4P0 阻塞)
iam_student_guardians 表 表已建 + Repository 查询方法可用 ai06 P4P0 阻塞)
core-edu gRPC 50053 HealthService.Check = SERVING + Exam/Homework/Grade Service 可调 ai08 P4
core-edu ClassService.GetClass proto 补全 + RPC 实现ISSUE-008 待仲裁) ai08 或 classes P4
data-ana gRPC 50055 HealthService.Check = SERVING + AnalyticsService 可调 ai11 P4
msg gRPC 50056 HealthService.Check = SERVING + NotificationService 可调 ai10 P5
msg.proto Notification.child_id proto 字段补全ISSUE-007 待仲裁) ai10 P5
push-gateway /internal/push HTTP 端点可用 ai02 P5
api-gateway /parent 路由 /api/v1/parent/* → parent-bff:3010 代理生效 ai01 P4
Kafka topic 已创建 edu.notification.sent/read/recalled/failed + edu.teaching.* coord/infra P5
Redis 已部署 redis://edu-redis:6379 可达 coord/infra P4
buf.gen.yaml gRPC 插件 TS gRPC client 代码生成可用 coord P4
ai03 DownstreamClient 抽象 teacher-bff clients/ 抽象层可参考 ai03 P4

4.2 我的就绪信号(供下游消费)

信号 检查方式 消费方
parent-bff GraphQL :3010 启用 GET /healthz 返回 200 api-gateway / K8s
/readyz 返回 200含 4 下游 gRPC 连通性) GET /readyz 返回 200 K8s readinessProbe
GraphQL schema 可内省 POST /graphql 返回 schema parent-portalai15
核心 Query 可执行 dashboard / myChildren / childGrades / childAnalytics parent-portal
核心 Mutation 可执行 selectChild / markNotificationReadP5 parent-portal
DataScope=CHILDREN 校验生效 家长查询未绑定 childId 返回 403 集成测试
metrics 暴露 GET /metrics 返回 parent_bff_* 指标 Prometheus

4.3 全并行 Mock 策略

开发期间上游未就绪时parent-bff 使用 mock 完成全部 P4-P6 代码,最后统一集成测试。

下游 Mock 方式 切换真实时机
iam gRPC grpc-mock 拦截 + 固定 UserInfoparent 角色)+ 固定 2 个 ChildInfo iam 就绪信号
core-edu gRPC grpc-mock 拦截 + 固定成绩/作业/考试 core-edu 就绪信号
data-ana gRPC grpc-mock 拦截 + 固定学情/趋势 data-ana 就绪信号
msg gRPC grpc-mock 拦截 + 固定 10 条通知(含 childId msg 就绪信号
push-gateway HTTP fetch mock + 返回 success push-gateway 就绪信号
Redis Testcontainers 真实 Redis 实例
Kafka kafkajs mock + jest.mock Kafka topic 创建

关键iam.GetChildrenByParent 的 mock 必须返回与 core-edu mock 数据一致的 student_id否则 ChildGuard 越权校验会失败。


§5 跨模块协作需求(需 coord 协调)

# 需求 涉及 AI 阻塞阶段 协调内容
1 iam 补 GetChildrenByParent RPC + iam_student_guardians 表 ai06 P4P0 I6 裁决已定ai06 P2.1 即补
2 core-edu ClassService 归属仲裁 + proto 补全 ai08 / classes P4 ISSUE-008 待 coord 仲裁
3 msg.proto Notification 补 child_id 字段 ai10 P5 ISSUE-007 待 coord 仲裁
4 api-gateway 新增 /parent 路由 ai01 P4 main.go + config.go 新增 ParentBffURL
5 004 §4 依赖图同步 C6 仲裁(补 DataAna + Msg coord P4 ISSUE-004
6 parent-portal 文档同步 GraphQL 决策 ai15 P4 ISSUE-005 跨模块契约冲突
7 buf.gen.yaml 补 gRPC TS 插件 coord P4 02 §7.3 #7
8 docker-compose.deploy.yml 新增 parent-bff 服务 coord P4 端口 3010 + edu-net
9 full-stack-runbook 端口矩阵追加 3010 coord P4 02 §7.3 #5
10 shared-ts/contracts/graphql/parent-bff.graphql 建库 ai05 P4 SDL-first 集中管理