# student-bff 下游工作清单(Next Steps) > 负责人:ai04 > 更新日期:2026-07-13 > 关联:[student-portal_contract.md](../../docs/architecture/issues/contracts/student-portal_contract.md)、[student-portal_workline.md](../../docs/architecture/issues/worklines/student-portal_workline.md) --- ## 1. 概述 student-bff 已完成全部 35 Query + 23 Mutation + 1 Subscription 的 schema 与 resolver 实现,Docker 镜像本地构建与运行验证通过(`MOCK_UPSTREAM=false`)。下游 gRPC 服务未启动时,BFF 进入降级模式(方案 B),返回 `degraded: true` + `degradedReason` + `degradedFields`。 **本地 Docker 测试结果(2026-07-13):** - ✅ 镜像构建成功(`edu/student-bff:test`) - ✅ 容器启动正常(端口 3009,NestFactory + GraphQL Yoga 初始化完成) - ✅ `/healthz` 返回 200 - ✅ `MOCK_UPSTREAM=false`,下游未启动时进入降级模式 - ✅ `serverTime` Query 返回本地时间(无下游依赖) - ✅ `myProfile` Query 返回 `degraded=true`,原因为 `DOWNSTREAM_FAILURE: iam.GetUserProfile failed after 3 attempts` - ✅ `mySchedule` Query 返回空 items + `degraded=true` - ✅ `markAsRead` Mutation 返回 `success=false` + `error.code=BFF_STUDENT_BAD_GATEWAY` - ✅ `createLeaveRequest` Mutation 返回 `success=false` + `error.code=BFF_STUDENT_BAD_GATEWAY` - ✅ B4 越权防御生效:无 `x-user-id` header 时返回 401 UnauthorizedError - ✅ Kafka 软失败(不影响服务启动,仅 EventSubscriber 不工作) --- ## 2. 上游依赖(api-gateway 路由) ### 2.1 api-gateway(ai01 负责) **阻塞级别:P0(必须完成才能端到端联调)** | # | 工作项 | 详情 | | --- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | 1 | 新增 `/api/v1/student/graphql` 路由 | 当前 api-gateway 无此路由。需新增 POST `/api/v1/student/graphql` 代理到 student-bff :3009/graphql(ARB-019 §21) | | 2 | JWT 校验 + 用户身份注入 | api-gateway 校验 JWT 后,注入 `x-user-id` / `x-user-roles` / `x-request-id` header 到 student-bff | | 3 | 学生角色校验 | `/api/v1/student/*` 路由组上添加 `student` 角色门禁,拒绝非 student 角色访问 | | 4 | 限流配置 | student-bff 路由组配置 IP 级令牌桶限流 | | 5 | 熔断/重试 | 对 student-bff 后端配置熔断器(opossum 已在 student-bff 内部启用,gateway 层可加外层熔断) | **相关文件:** - `services/api-gateway/main.go`(路由注册) - `services/api-gateway/internal/middleware/auth.go`(JWT 校验) - `services/api-gateway/internal/proxy/proxy.go`(反向代理) - `services/api-gateway/internal/config/config.go`(路由配置) --- ## 3. 下游依赖(gRPC 微服务) ### 3.1 iam 服务(ai06 负责) **阻塞级别:P0(影响用户身份相关功能)** | # | gRPC 方法 | 用途 | 当前状态 | | --- | ---------------- | ------------------------- | -------- | | 1 | `GetUserProfile` | `myProfile` Query | ❌ 缺失 | | 2 | `UpdateProfile` | `updateProfile` Mutation | ❌ 缺失 | | 3 | `ChangePassword` | `changePassword` Mutation | ❌ 缺失 | **proto 位置:** `packages/shared-proto/proto/iam/v1/iam.proto` ### 3.2 core-edu 服务(ai08 负责) **阻塞级别:P0(影响学生核心学习功能)** | # | gRPC 方法 | 用途 | 当前状态 | | --- | ---------------------------- | ------------------------------ | -------- | | 1 | `GetExam` | `examDetail` Query | ❌ 缺失 | | 2 | `SubmitExam` | `submitExam` Mutation | ❌ 缺失 | | 3 | `SaveExamDraft` | `saveExamDraft` Mutation | ❌ 缺失 | | 4 | `RecordExamViolation` | `recordExamViolation` Mutation | ❌ 缺失 | | 5 | `GetHomework` | `homeworkDetail` Query | ❌ 缺失 | | 6 | `GetScheduleByStudent` | `mySchedule` Query | ❌ 缺失 | | 7 | `ListLeaveRequestsByStudent` | `myLeaveRequests` Query | ❌ 缺失 | | 8 | `CreateLeaveRequest` | `createLeaveRequest` Mutation | ❌ 缺失 | | 9 | `CancelLeaveRequest` | `cancelLeaveRequest` Mutation | ❌ 缺失 | | 10 | `GetReportCard` | `myReportCard` Query | ❌ 缺失 | **proto 位置:** `packages/shared-proto/proto/core_edu/v1/core_edu.proto` ### 3.3 content 服务(ai09 负责) **阻塞级别:P0(影响学生内容浏览功能)** | # | gRPC 方法 | 用途 | 当前状态 | | --- | --------------------------------- | -------------------------------- | -------- | | 1 | `ListElectiveSelectionsByStudent` | `myElectiveSelections` Query | ❌ 缺失 | | 2 | `ListAvailableElectiveCourses` | `availableElectiveCourses` Query | ❌ 缺失 | | 3 | `SelectCourse` | `selectElectiveCourse` Mutation | ❌ 缺失 | | 4 | `DropCourse` | `dropElectiveCourse` Mutation | ❌ 缺失 | | 5 | `ListLessonPlansByStudent` | `myLessonPlans` Query | ❌ 缺失 | | 6 | `GetLessonPlan` | `lessonPlanDetail` Query | ❌ 缺失 | | 7 | `ListCoursePlansByStudent` | `myCoursePlans` Query | ❌ 缺失 | | 8 | `GetCoursePlan` | `coursePlanDetail` Query | ❌ 缺失 | **proto 位置:** `packages/shared-proto/proto/content/v1/content.proto` ### 3.4 data-ana 服务(ai12 负责) **阻塞级别:P0(影响学生学情分析功能)** | # | gRPC 方法 | 用途 | 当前状态 | | --- | ------------------------------- | ------------------------------- | -------- | | 1 | `GetStudentGrowth` | `studentGrowth` Query | ❌ 缺失 | | 2 | `GetAssignmentAnalysis` | `assignmentAnalysis` Query | ❌ 缺失 | | 3 | `GetMasterySummary` | `myMasterySummary` Query | ❌ 缺失 | | 4 | `ListDiagnosticReports` | `myDiagnosticReports` Query | ❌ 缺失 | | 5 | `ListErrorBookItems` | `myErrorBook` Query | ❌ 缺失 | | 6 | `ListPracticeSessionsByStudent` | `myPracticeSessions` Query | ❌ 缺失 | | 7 | `StartPracticeSession` | `startPracticeSession` Query | ❌ 缺失 | | 8 | `SubmitPracticeAnswer` | `submitPracticeAnswer` Mutation | ❌ 缺失 | **proto 位置:** `packages/shared-proto/proto/data_ana/v1/data_ana.proto` ### 3.5 msg 服务(ai10 负责) **阻塞级别:P0(影响学生通知与公告功能)** | # | gRPC 方法 | 用途 | 当前状态 | | --- | ------------------------------ | --------------------------------------- | -------- | | 1 | `ListAnnouncements` | `announcements` Query | ❌ 缺失 | | 2 | `GetAnnouncement` | `announcementDetail` Query | ❌ 缺失 | | 3 | `MarkNotificationAsRead` | `markAsRead` Mutation | ❌ 缺失 | | 4 | `MarkAllNotificationsAsRead` | `markAllAsRead` Mutation | ❌ 缺失 | | 5 | `UpdateNotificationPreference` | `updateNotificationPreference` Mutation | ❌ 缺失 | | 6 | `MarkAnnouncementRead` | `markAnnouncementRead` Mutation | ❌ 缺失 | **proto 位置:** `packages/shared-proto/proto/msg/v1/msg.proto` ### 3.6 ai 服务(ai11 负责) **阻塞级别:P1(影响 AI 辅助功能,可降级)** | # | gRPC 方法 | 用途 | 当前状态 | | --- | -------------- | ----------------------- | -------- | | 1 | `StreamAIChat` | `aiStream` Subscription | ❌ 缺失 | **proto 位置:** `packages/shared-proto/proto/ai/v1/ai.proto` ### 3.7 push-gateway(ai13 负责) **阻塞级别:P1(影响实时推送)** | # | 工作项 | 详情 | | --- | ------------------ | ---------------------------------------------------------------- | | 1 | WebSocket 推送端点 | student-bff EventSubscriber 接收 Kafka 事件后转发到 push-gateway | | 2 | Kafka topic 对齐 | student-bff 订阅 `student.notification.*` 等 topic | --- ## 4. student-bff 已完成项汇总 | 工作项 | 状态 | 验证方式 | | ------------------------------------------- | ---- | ------------------------------------------- | | Schema 扩展(13Q+2M → 35Q+23M+1S) | ✅ | `pnpm typecheck` + GraphQL Playground 校验 | | 22 个扩展 Query Resolver | ✅ | Docker 容器 GraphQL 请求测试 | | 21 个扩展 Mutation Resolver | ✅ | Docker 容器 GraphQL 请求测试 | | Zod 输入校验(21 个 Mutation Input Schema) | ✅ | typecheck + 运行时校验 | | B4 越权防御(assertOwnData) | ✅ | 无 `x-user-id` 返回 401 | | 降级模式(方案 B) | ✅ | 下游不可用时返回 `degraded=true` + 原因 | | Redis 缓存(B6 5-30s TTL) | ✅ | CacheService 已注入,TTL 预设已配置 | | Kafka EventSubscriber(软失败) | ✅ | Kafka 不可用时不阻塞启动 | | DataLoader 批量加载 | ✅ | createDataLoaders 已注入 context | | Dockerfile 多阶段构建 | ✅ | `edu/student-bff:test` 构建成功 | | Docker 本地测试(MOCK_UPSTREAM=false) | ✅ | healthz + GraphQL Query/Mutation 全部按预期 | --- ## 5. 联调顺序建议 1. **ai06** 完成 iam gRPC(GetUserProfile / UpdateProfile / ChangePassword) 2. **ai08** 完成 core-edu gRPC(GetExam / SubmitExam / GetHomework / GetScheduleByStudent 等 10 个) 3. **ai09** 完成 content gRPC(8 个选修/教案/课程计划相关) 4. **ai12** 完成 data-ana gRPC(8 个学情分析相关) 5. **ai10** 完成 msg gRPC(6 个通知/公告相关) 6. **ai01** 完成 api-gateway `/api/v1/student/graphql` 路由 + JWT 注入 7. **ai11** 完成 ai gRPC StreamAIChat(P1) 8. **ai13** 完成 push-gateway WebSocket(P1) 9. 端到端联调(student-portal → api-gateway → student-bff → 6 个下游 gRPC 服务) --- ## 6. 已知限制 | # | 限制 | 说明 | | --- | ------------------------------------- | ------------------------------------------------------------------------------------------ | | 1 | Kafka 未启动时 EventSubscriber 软失败 | 服务正常启动,但实时事件推送(通知/AI 流式响应)不工作 | | 2 | 下游 gRPC 未就绪时进入降级模式 | 所有 Query 返回 `degraded=true` + 空数据;所有 Mutation 返回 `success=false` + BAD_GATEWAY | | 3 | DEV_MODE=true 时跳过 B4 越权校验 | 生产环境必须 `DEV_MODE=false`,由 api-gateway 注入 `x-user-id` header | | 4 | pino-pretty 仅 devDependencies | 生产环境 `NODE_ENV=production` 时不启用 pino-pretty transport(输出结构化 JSON) | | 5 | OTEL_EXPORTER_OTLP_ENDPOINT 未配置 | Tracer 被禁用,需配置 OTLP endpoint 启用全链路追踪 | --- **本文件由 ai04 维护,下游工作项请各负责 AI 完成后通知 ai04 更新状态。**