Files
Edu/docs/architecture/issues/worklines/teacher-bff_workline.md
2026-07-10 15:05:50 +08:00

16 KiB
Raw Blame History

teacher-bff 工作排期

负责人ai03 关联:workline.mdcoord.md §1 ARB-001contracts/teacher-bff_contract.mdpresident-final-rulings.md §3.1/§7.3coord-final-decisions.md §2 B1-B8 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,最后统一集成测试) 裁决依据B1 P2 即 GraphQL / B2 首次实现即 gRPC / B3 豁免 @RequirePermission / B4 越权防御 / B5 BFF_TEACHER_ 前缀 / B6 Redis 短缓存 / B7 P2-P4 不订阅 Kafka / B8 DownstreamClient 抽象


§1 总览

teacher-bff 是教学场景域聚合层BFF全阶段目标

阶段 核心交付 裁决依据
P2 GraphQL schema 第一版5 Query + admin 预留)+ DownstreamClient 抽象 + iam gRPC + AuthorizationGuard + ActionState 信封 B1/B2/B3/B4/B5/B8 + ARB-001 + §3.1
P3 core-edu gRPC 扩展exams/homework/grades Query + Mutation+ AuthorizationGuard 接入 core-edu + Redis 聚合缓存 §2.3 跨阶段扩展例外
P4 content + data-ana gRPC 扩展(学情分析 Query+ DataLoader 全量接入 §2.3 + §2.8
P5 ai + msg gRPC 扩展SSE 流式 + notifications Query+ Kafka consumerpush-gateway 落地后) B7
P6 admin 命名空间实现 + 硬化(熔断/重试/超时/HPA/mTLS §5.1 + P6 硬化

§2 全阶段甘特图P2-P6

gantt
    title ai03 teacher-bff 全阶段排期
    dateFormat YYYY-MM-DD
    axisFormat %m-%d

    section P2 GraphQL 基础8d
    schema第一版+admin预留(ARB-001) :crit, a3a, 2026-07-10, 2d
    Yoga endpoint+5 Query Resolver :crit, a3b, after a3a, 3d
    DownstreamClient+iam gRPC :crit, a3c, after a3a, 2d
    AuthorizationGuard越权防御(B4) :crit, a3d, after a3b, 1d
    ActionState信封+降级模式B :a3e, after a3b, 1d
    /readyz探针注册表+iam探针 :a3f, after a3d, 1d
    错误码迁移BFF_TEACHER_+回写02 :a3g, after a3e, 1d

    section P3 core-edu 扩展5d
    CoreEduClient gRPC(exams/homework/grades) :crit, a3h, after a3g, 2d
    Mutation(createExam/assignHomework/recordGrade) :a3i, after a3h, 1d
    AuthorizationGuard接入core-edu+Redis缓存 :a3j, after a3h, 1d
    /readyz+core-edu探针 :a3k, after a3j, 1d

    section P4 content+data-ana 扩展4d
    ContentClient+DataAnaClient gRPC :a3l, after a3k, 2d
    学情分析Query+DataLoader全量 :a3m, after a3l, 1d
    /readyz+content+data-ana探针 :a3n, after a3m, 1d

    section P5 ai+msg 扩展8d
    AiClient+MsgClient gRPC :a3o, after a3n, 2d
    SSE流式透传+notifications Query :a3p, after a3o, 2d
    Kafka consumer(push-gateway落地后) :a3q, after a3p, 2d
    /readyz+ai+msg探针 :a3r, after a3q, 1d
    Should Have补全(OTel/metrics/DataLoader/Redis) :a3s, after a3r, 1d

    section P6 admin+硬化3d
    admin命名空间实现 :a3t, after a3s, 1d
    熔断/重试/超时 :a3u, after a3t, 1d
    Nice to Have补全(Zod全量/优雅关闭) :a3v, after a3u, 1d

总工期28dP2 8d + P3 5d + P4 4d + P5 8d + P6 3d与 workline.md §1 总时间线对齐批次1 8d + 批次2 5d + 批次4 8d + P4/P6 合并 7d


§3 详细任务

P2GraphQL 基础 + DownstreamClient + 越权防御(批次 18d

裁决依据president §3.1 Must Have 13 项teacher-bff 无 DBG10/G11 不适用,实际 11 项 + DownstreamClient + admin 预留)

3.1 GraphQL schema 第一版 + admin 预留2dP0 阻塞 ai13

  • 负责人ai03
  • 依赖coord 仲裁 ARB-001已裁决
  • 交付物
    • packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql — P2 schema5 Query: dashboard/viewports/me/classes/class + admin 命名空间占位)
    • admin 命名空间预留schema 中声明 admin Query/Mutation 类型骨架(无实际 ResolverP6 实现
  • 验收标准5 Query SDL 定义完整 + admin 占位类型声明 + depth ≤ 7 + cost ≤ 1000
  • 裁决引用ARB-001 §1.2/§1.3 + president §5.1/§2.17

3.2 Yoga endpoint + 5 Query Resolver3dP0 阻塞 ai13

  • 负责人ai03
  • 依赖3.1 schema + iam gRPC 50052ai06 P2.1
  • 交付物
    • POST /graphql Yoga GraphQL endpoint
    • 5 Query Resolverdashboard / viewports / me / classes / class
    • Dashboard Resolver P2 实现方式ISSUE-032P2 仅调 iam gRPC未启用字段返回 null + extensions.warning = "field_unavailable_in_p2"
  • 验收标准5 Query 可执行 + ActionState 信封 + 降级模式 Bsuccess=true + error=null + data 内 degraded 字段)
  • 裁决引用B1 + ARB-001 §1.4 + president §2.6/§2.8

3.3 DownstreamClient 抽象 + iam gRPC2dP0 阻塞 ai04/ai05

  • 负责人ai03
  • 依赖iam gRPC 50052ai06 P2.1
  • 交付物
    • src/clients/ DownstreamClient 抽象层B8BFF 模式 v2 标准抽象3 个 BFF 统一使用,回写 teacher-bff
    • IamClient gRPC 实现:@grpc/grpc-js + @bufbuild/protobuf,调 iam:50052
    • gRPC interceptor注入 trace contexttraceparent+ x-user-id metadata + metrics
  • 验收标准IamClient gRPC 调 iam GetUserInfo/GetViewports/GetEffectiveAccess 成功
  • 裁决引用B2首次实现即 gRPC+ B8DownstreamClient 抽象)

3.4 AuthorizationGuard 越权防御1dP0

  • 负责人ai03
  • 依赖3.2 Resolver
  • 交付物
    • src/middleware/authorization.guard.ts — AuthorizationGuard 接口(canAccessClass(userId, classId): Promise<boolean>
    • P2 内部实现DEV_MODE 放行 + 生产拒绝(保守策略)
    • 错误码:BFF_TEACHER_FORBIDDEN_RESOURCEteacherId 与资源无归属)+ BFF_TEACHER_IDENTITY_MISMATCHJWT teacherId 与 body 不一致)
  • 验收标准Guard 接口定义 + DEV_MODE 放行 + 生产拒绝 + 2 个越权错误码
  • 裁决引用B4 + president §2.7(错误码语义)+ §2.9(越权防御 P2 实现)

3.5 ActionState 信封 + 降级模式 B1d

  • 负责人ai03
  • 依赖3.2 Resolver
  • 交付物GlobalErrorFilter + ActionState 信封success/errors/data+ 降级模式 B
  • 验收标准GraphQL errors 数组扩展 ActionState 字段,extensions.code = BFF_TEACHER_*
  • 裁决引用G8 + president §2.6

3.6 /readyz 探针注册表 + iam 探针1d

  • 负责人ai03
  • 依赖3.3 IamClient
  • 交付物
    • src/shared/health/readiness.probe.ts — DownstreamHealthCheck 注册表模式
    • P2 探针Redis + iam gRPC 50052teacher-bff 无 DB2 项)
  • 验收标准/readyz 返回 2 项检查结果 + 必需依赖失败返回 503
  • 裁决引用G2 + president §2.4(探针按阶段扩展)

3.7 错误码迁移 + 回写 02 文档1d

  • 负责人ai03
  • 依赖3.2-3.6
  • 交付物
    • application-error.ts 全量迁移 TEACHER_BFF_*BFF_TEACHER_*
    • 回写 02 文档4 处 GetTeacherDashboardStatsGetTeacherDashboardISSUE-035+ B1/B2/B4/B8 裁决对齐
  • 验收标准:源码零 TEACHER_BFF_* + 02 文档与裁决一致
  • 裁决引用B5 + G14 + president §3.4 回写义务

P2 横切项(贯穿 3.1-3.7

状态 说明
pino 结构化日志G4 已具备 logger.ts
/healthz livenessG3 已具备 health.controller.ts
GlobalErrorFilterG8 已具备 global-error.filter.ts
ESM import .js 后缀G12 已具备 源码已用 .js
import typeG13 已具备 源码已用 import type
OTel tracerG6 ⚠️ Should Have P2 可降级为 logger-onlyP5 补全
/metrics 业务指标G5 ⚠️ Should Have P2 仅暴露 process metrics
DataLoaderB1 ⚠️ Should Have P2 可先用普通 resolverP4 全量接入
Redis 5-30s 短缓存B6 ⚠️ Should Have P3 接入聚合缓存
Zod 全量验证G7 ⚠️ Nice to Have P2 先校验核心 QueryP6 全量
优雅关闭 SIGTERMG9 ⚠️ Nice to Have P2 已有基础P6 补全关闭顺序

P2 退出标准POST /graphql 可用 + 5 Query Resolver + DownstreamClient + AuthorizationGuard + ActionState 信封 + /readyz 2 项探针 + 错误码 BFF_TEACHER_* + admin 命名空间预留。


P3core-edu gRPC 扩展(批次 25d

裁决依据§2.3 跨阶段扩展例外(新增下游 gRPC 调用 + AuthorizationGuard 内部实现替换 + /readyz 探针扩展)

3.8 CoreEduClient gRPC2dP0

  • 负责人ai03
  • 依赖core-edu gRPC 50053ai08 P3
  • 交付物
    • CoreEduClient gRPC 实现ExamService / HomeworkService / GradeService
    • GraphQL Query 扩展exams(classId) / homework(classId) / grades(examId)
    • Dashboard Resolver 扩展null 字段替换为 core-edu 真实数据
  • 验收标准3 个 Query 返回 core-edu 数据 + Dashboard null 字段消除
  • 裁决引用§2.3 跨阶段扩展例外 + §2.8 Dashboard Resolver 扩展

3.9 Mutation 透传1d

  • 交付物createExam / assignHomework / recordGrade Mutation透传 core-edu gRPC
  • 验收标准3 个 Mutation 可执行 + 返回 ActionState 信封

3.10 AuthorizationGuard 接入 core-edu + Redis 缓存1d

  • 交付物
    • AuthorizationGuard 内部实现替换DEV_MODE 放行 → 真实 gRPC 校验
    • Redis 缓存:GetClassesByTeacher 结果缓存key: authz:teacher:{teacherId}:classesTTL 5min
  • 验收标准:生产环境越权防御生效 + Redis 缓存命中
  • 裁决引用president §2.9P3 接入 core-edu 后替换 Guard 实现)

3.11 /readyz + core-edu 探针1d

  • 交付物/readyz 探针注册表扩展 core-edu gRPC 50053 探针3 项Redis + iam + core-edu
  • 验收标准/readyz 返回 3 项检查结果

P3 退出标准core-edu gRPC 3 Query + 3 Mutation + AuthorizationGuard 生产生效 + Redis 缓存 + /readyz 3 项探针。


P4content + data-ana gRPC 扩展4d

裁决依据§2.3 跨阶段扩展例外

3.12 ContentClient + DataAnaClient gRPC2d

  • 依赖content gRPC 50054ai09 P4+ data-ana gRPC 50055ai11 P4
  • 交付物
    • ContentClient gRPCKnowledgeGraphServiceGetPrerequisites / GetLearningPath
    • DataAnaClient gRPCAnalyticsServiceGetClassPerformance / GetStudentWeakness / GetLearningTrend / GetTeacherDashboard
    • GraphQL Query 扩展knowledgePath / classPerformance / studentWeakness / learningTrend / teacherDashboard
  • 验收标准5 个 Query 返回真实数据

3.13 DataLoader 全量接入1d

  • 交付物DataLoader 覆盖全部 N+1 风险点UserLoader / ClassLoader / ExamLoader / HomeworkLoader / GradeLoader
  • 验收标准DataLoader per-request 实例 + 批量化窗口 16ms
  • 裁决引用B1 Should Have → P4 全量接入

3.14 /readyz + content + data-ana 探针1d

  • 交付物/readyz 探针扩展 content + data-ana5 项Redis + iam + core-edu + content + data-ana

P4 退出标准content + data-ana gRPC + 5 Query + DataLoader 全量 + /readyz 5 项探针。


P5ai + msg gRPC 扩展 + SSE + Kafka批次 48d

裁决依据B7P5 push-gateway 落地后再订阅 Kafka

3.15 AiClient + MsgClient gRPC2d

  • 依赖ai gRPC 50057ai12 P5+ msg gRPC 50056ai10 P5
  • 交付物
    • AiClient gRPCAiServiceChat / StreamChat streaming / GenerateQuestion / OptimizeExpression
    • MsgClient gRPCNotificationServiceListNotifications / SearchNotifications / MarkAsRead
    • GraphQL Query 扩展notifications + MutationgenerateQuestion / markNotificationAsRead

3.16 SSE 流式透传2d

  • 交付物GET /ai/chat/stream SSE 端点ai.StreamChat gRPC stream → BFF → 前端 EventSource
  • 验收标准SSE 三层透传端到端通 + 背压处理 + 超时取消
  • 裁决引用02 文档 §10

3.17 Kafka consumer2dpush-gateway 落地后)

  • 交付物
    • Kafka consumer 订阅 edu.identity.user.role_changed / edu.identity.role.updated,精确失效 Redis 权限缓存
    • 幂等性:基于 event_id 去重Redis SETNX
  • 验收标准:权限变更秒级缓存失效 + 幂等消费
  • 裁决引用B7P5 push-gateway 落地后再订阅)

3.18 /readyz + ai + msg 探针 + Should Have 补全2d

  • 交付物
    • /readyz 探针扩展 ai + msg7 项Redis + iam + core-edu + content + data-ana + ai + msg
    • Should Have 补全OTel tracer 全链路 + /metrics 业务指标 + Redis 聚合缓存 5-30s
  • 验收标准/readyz 7 项 + OTel 全链路 trace + 缓存命中率 ≥ 60%

P5 退出标准ai + msg gRPC + SSE 流式 + notifications Query + Kafka consumer + /readyz 7 项探针 + Should Have 补全。


P6admin 命名空间 + 硬化3d

裁决依据president §5.1admin-portal 复用 teacher-bff+ P6 硬化

3.19 admin 命名空间实现1d

  • 依赖admin-portalai16 P6
  • 交付物
    • admin schema 命名空间 Resolver 实现P2 预留的占位类型填充实际 Resolver
    • admin Query/Mutation用户管理 / 角色权限管理 / 学校设置 / 组织管理 / 审计日志查询
  • 验收标准admin namespace 可内省 + admin-portal 可消费
  • 裁决引用president §5.1admin-portal 复用 teacher-bff GraphQL endpoint

3.20 熔断 / 重试 / 超时1d

  • 交付物
    • Circuit Breakeropossumper-downstream-service
    • RetrygRPC interceptor仅幂等 RPC指数退避
    • Timeoutper-RPC 3s聚合总超时 5s
  • 验收标准:熔断/重试/超时生效 + 降级策略覆盖

3.21 Nice to Have 补全1d

  • 交付物Zod 全量验证 + 优雅关闭顺序HTTP→Redis→gRPC→Kafka→Tracer+ 测试覆盖率 ≥ 80%
  • 验收标准Zod 全 Controller 覆盖 + SIGTERM 顺序关闭 + Vitest 覆盖率 ≥ 80%

P6 退出标准admin namespace 实现 + 熔断/重试/超时 + Zod 全量 + 测试 ≥ 80% + SLO 99.9%。


§4 依赖与就绪信号

4.1 我依赖的上游就绪信号

上游 就绪信号 阶段 状态
iamai06 gRPC 50052 + 8 RPCGetUserInfo/GetViewports/GetEffectivePermissions/GetEffectiveAccess/Logout/GetPublicKey/BatchGetUsers/GetChildrenByParent P2
core-eduai08 gRPC 50053 + ExamService/HomeworkService/GradeService P3
contentai09 gRPC 50054 + KnowledgeGraphService P4
data-anaai11 gRPC 50055 + AnalyticsService含 GetTeacherDashboardISSUE-027 补全) P4
aiai12 gRPC 50057 + AiService含 StreamChat P5
msgai10 gRPC 50056 + NotificationService P5
push-gatewayai02 /internal/push 落地B7 Kafka 订阅前提) P5
admin-portalai16 admin schema 需求确认 P6

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

阶段 就绪信号 消费方
P2 POST /graphql 可用 + 5 Query + admin 预留 teacher-portalai13
P2 DownstreamClient 抽象B8 回写) student-bffai04/ parent-bffai05
P3 exams/homework/grades Query + Mutation teacher-portalai13
P4 学情分析 Query + DataLoader teacher-portalai13
P5 SSE 流式 + notifications Query teacher-portalai13
P6 admin namespace 可用 admin-portalai16

§5 跨阶段扩展例外验收清单

裁决依据president §2.3ISSUE-020。每次跨阶段扩展时对照检查。

  • 扩展时更新 02-architecture-design.md 下游调用矩阵
  • 扩展时更新 packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql
  • 扩展时运行 pnpm run arch:scan 更新 arch.db
  • 未修改已有 RPC 调用签名或返回类型
  • 未删除已实现的 RPC 调用
  • 未修改 GraphQL schema 已有字段类型(仅新增字段)
  • 未修改 /readyz 已有探针检查项(仅新增)