Files
Edu/services/student-bff/docs/nextstep-v2.md

388 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# student-bff 下游工作清单 V2Next Steps v2
> 负责人ai04
> 更新日期2026-07-14
> 基于版本v1nextstep.md+ student-portal v2 审计§9 二次核查)后的更新
> 关联:
>
> - [student-portal/docs/nextstep-v2.md](../../../apps/student-portal/docs/nextstep-v2.md)
> - [student-bff/docs/nextstep.md](./nextstep.md)
> - [student-bff_contract.md](../../../docs/architecture/issues/contracts/student-bff_contract.md)
---
## 0. v2 核查总结
| 工作项 | v1 状态 | v2 核查结果 | 阻断级别 |
| ------------------------------------------------- | --------- | --------------- | -------- |
| index.ts 装配 extended resolvers | ❌ 未装配 | ✅ **已修复** | P0 |
| shared-ts schema 补全 43 个操作 SDL | ❌ 未补全 | ✅ **已修复** | P0 |
| myAttendance resolver 实现 | ❌ 缺失 | ✅ **已实现** | P1 |
| startPracticeSession 类型修正Query → Mutation | ❌ 未修正 | ✅ **已修正** | P1 |
| RecordExamViolationInput schema 类型对齐 | ❌ 未发现 | ✅ **已修复** | P0 |
| Dockerfile 多阶段构建(对齐 teacher-bff 模式) | ❌ 失败 | ✅ **已修复** | P0 |
| shared-ts pino NodeNext 类型修复 | ❌ 未发现 | ✅ **已修复** | P0 |
| Docker 构建 + 容器启动 + GraphQL 60 操作验证 | ❌ 未验证 | ✅ **全部通过** | P0 |
**结论:** student-bff v2 全部 P0/P1 工作已完成并验证通过。60 个 GraphQL 操作36 Query + 24 Mutation全部注册并可响应。
---
## 1. student-bff v2 完成项详情
### 1.1 P0index.ts 装配 extended resolvers
**修复前:** `index.ts` 仅装配 11 个基础 resolver22 个 extended Query + 21 个 extended Mutation 已实现但未导入。
**修复后:**
```typescript
import { extendedQueriesResolvers } from "./extended-queries.resolver.js";
import { extendedMutationsResolvers } from "./extended-mutations.resolver.js";
export const studentBffResolvers = {
Query: {
...(authResolvers.Query ?? {}),
// ... 其他基础 resolver
...(extendedQueriesResolvers.Query ?? {}), // ✅ 新增
},
Mutation: {
...(homeworkResolvers.Mutation ?? {}),
...(notificationsResolvers.Mutation ?? {}),
...(extendedMutationsResolvers.Mutation ?? {}), // ✅ 新增
},
Subscription: {
...(aiStreamResolvers.Subscription ?? {}),
},
};
```
**验证:** GraphQL introspection 查询返回 36 Query + 24 Mutation = 60 操作。
### 1.2 P0shared-ts schema 补全
**修复前:** `student-bff.schema.graphql` 仅 822 行,定义 15 Query + 2 Mutation + 1 Subscription。
**修复后:** 1648 行,定义 36 Query + 24 Mutation + 1 Subscription包含所有 input type / enum / payload type。
### 1.3 P1myAttendance resolver 实现
调用 `core-edu.AttendanceService.ListAttendanceByStudent`B4 强制 `userId = studentId`DataScope SELF
### 1.4 P1startPracticeSession 类型修正
从 Query 移到 Mutation语义为创建会话
### 1.5 P0RecordExamViolationInput schema 类型对齐
schema 引用 `RecordExamViolationInput` 但实际定义为 `RecordViolationInput`,已修正为 `recordExamViolation(input: RecordViolationInput!)`
### 1.6 P0Dockerfile 修复
**问题:** 原 Dockerfile 的 COPY 路径未包含 `services/student-bff/` 前缀,且 runtime stage 使用 `--ignore-workspace` 导致 `@edu/shared-ts` 无法解析。
**修复:** 对齐 teacher-bff 模式:
- Builder stage复制 workspace 配置 + shared-proto + shared-ts + student-bff使用 `--filter @edu/student-bff...` 过滤安装(避免 scripts/arch-scan 的 better-sqlite3 原生编译),先构建 shared-ts 再构建 student-bff
- Runtime stage保留 workspace 结构,`pnpm install --prod --filter @edu/student-bff... --ignore-scripts`,复制 shared-ts dist 产物
### 1.7 P0shared-ts pino NodeNext 类型修复
**问题:** pino 在 NodeNext + ESM 模式下 default import 丢失 callable 签名declaration merging 失效)。
**修复:** 通过 namespace import + 显式类型断言恢复可调用性:
```typescript
import * as pinoNs from "pino";
import type { Logger as PinoLogger, LoggerOptions } from "pino";
type PinoFn = (options?: LoggerOptions | unknown) => PinoLogger;
const pino = ((pinoNs as unknown as { default: PinoFn }).default ??
(pinoNs as unknown as PinoFn)) as PinoFn;
```
同时修复 `src/bff/downstream-client.ts:351` 的 IteratorResult 类型窄化问题。
---
## 2. v2 本地 Docker 验证结果2026-07-14
| 验证项 | 结果 | 说明 |
| ------------------------------ | ---- | ----------------------------------------- |
| `pnpm typecheck` | ✅ | 0 errors |
| `pnpm lint` | ✅ | 0 errors, 0 warnings |
| `pnpm test` | ✅ | 70/70 passed5 test files |
| `packages/shared-ts typecheck` | ✅ | 0 errorspino 修复后) |
| `packages/shared-ts build` | ✅ | dist 产物生成成功 |
| Docker 镜像构建 | ✅ | `edu-student-bff:test` 构建成功 |
| 容器启动 | ✅ | NestFactory + GraphQL Yoga 初始化完成 |
| `/healthz` 健康检查 | ✅ | `{"status":"ok","service":"student-bff"}` |
| GraphQL `__typename` 查询 | ✅ | `{"data":{"__typename":"Query"}}` |
| GraphQL introspection | ✅ | 36 Query + 24 Mutation = 60 操作全部注册 |
| `MOCK_UPSTREAM=true` 降级模式 | ✅ | 所有下游调用返回 mock 数据 |
**GraphQL 操作清单60 个,全部已注册):**
- **Query36** currentUser, myClasses, myExams, myHomework, myGrades, myAttendance, textbooks, chapters, learningPath, studentDashboard, myWeakness, myTrend, myNotifications, myNotificationUnreadCount, aiChat, examDetail, homeworkDetail, serverTime, mySchedule, studentGrowth, assignmentAnalysis, myProfile, myMasterySummary, myDiagnosticReports, myErrorBook, announcements, announcementDetail, myLeaveRequests, myElectiveSelections, availableElectiveCourses, myLessonPlans, lessonPlanDetail, myCoursePlans, coursePlanDetail, myReportCard, myPracticeSessions
- **Mutation24** submitHomework, markNotificationAsRead, markAsRead, markAllAsRead, updateNotificationPreference, submitExam, saveExamDraft, recordExamViolation, recordPasteEvent, updateProfile, changePassword, requestExtension, joinClass, leaveClass, addErrorBookItem, updateErrorBookItem, deleteErrorBookItem, markAnnouncementRead, createLeaveRequest, cancelLeaveRequest, selectElectiveCourse, dropElectiveCourse, startPracticeSession, submitPracticeAnswer
---
## 3. 上游依赖api-gateway 路由)
### 3.1 api-gatewayai01 负责)
**v2 核查结果:✅ 路由已注册 + 路径重写已修复**
- `services/api-gateway/main.go``registerBffProxy(api, "student", cfg.StudentBffURL)`
- `services/api-gateway/internal/config/config.go``StudentBffURL: getEnv("STUDENT_BFF_URL", "http://localhost:3009")`
- 路径前缀改写:`/api/v1/student/*``/v1/student/*`proxy.go `registerBffProxy`)✅
- JWT 鉴权 + `x-user-id` / `x-user-roles` / `x-request-id` header 注入 ✅
### 3.2 待 SRE AI 修复P0 部署阻断)
| # | 工作项 | 详情 |
| --- | ----------------------------------------------------- | ---------------------------------------------------------------------- |
| 1 | `infra/docker-compose.deploy.yml` 新增 student-bff | 服务定义缺失,需新增 build context + environment + ports + networks |
| 2 | `infra/docker-compose.deploy.yml` 新增 student-portal | 服务定义缺失 |
| 3 | api-gateway environment 补充 `STUDENT_BFF_URL` | 当前 deploy.yml 缺失,会回退到 `http://localhost:3009`,容器内无法访问 |
**student-bff 建议的 deploy.yml 配置:**
```yaml
student-bff:
build:
context: ./repo
dockerfile: services/student-bff/Dockerfile
container_name: edu-student-bff
restart: unless-stopped
environment:
NODE_ENV: production
PORT: 3009
DEV_MODE: "false"
MOCK_UPSTREAM: "false"
REDIS_URL: redis://edu-redis:6379
KAFKA_BROKERS: edu-kafka:29092
# 下游 gRPC targetsDocker 服务名 + 端口)
IAM_GRPC_TARGET: iam:50052
CORE_EDU_GRPC_TARGET: core-edu:50053
CONTENT_GRPC_TARGET: content:50054
DATA_ANA_GRPC_TARGET: data-ana:50055
MSG_GRPC_TARGET: msg:50056
AI_GRPC_TARGET: ai:50058
ports:
- "${STUDENT_BFF_PORT:-3009}:3009"
depends_on:
iam:
condition: service_healthy
core-edu:
condition: service_healthy
networks:
- edu-net
- edu-shared
```
---
## 4. 下游依赖gRPC 微服务)
### 4.1 iam 服务ai06 负责)
**v2 核查结果:✅ 全部就绪**
iam 已实现 15 个 gRPC RPC包含 student-bff 需要的全部方法:
| gRPC 方法 | 用途 | 状态 |
| ------------------------- | ------------------------- | ---- |
| `GetUserInfo` | `currentUser` Query | ✅ |
| `GetEffectivePermissions` | `currentUser` permissions | ✅ |
| `GetViewports` | `currentUser` viewport | ✅ |
| `GetUserProfile` | `myProfile` Query | ✅ |
| `UpdateProfile` | `updateProfile` Mutation | ✅ |
| `ChangePassword` | `changePassword` Mutation | ✅ |
### 4.2 core-edu 服务ai08 负责)
**v2 核查结果:✅ 全部就绪**
core-edu 已完成 P3.139 Service / 40 RPC 全部就绪24/24 smoke test 通过):
| gRPC 方法 | 用途 | 状态 |
| ------------------------------------------------ | ------------------------------ | ---- |
| `ExamService.GetExam` | `examDetail` Query | ✅ |
| `ExamService.SubmitExam` | `submitExam` Mutation | ✅ |
| `ExamService.SaveExamDraft` | `saveExamDraft` Mutation | ✅ |
| `ExamService.RecordExamViolation` | `recordExamViolation` Mutation | ✅ |
| `HomeworkService.GetHomework` | `homeworkDetail` Query | ✅ |
| `HomeworkService.SubmitHomework` | `submitHomework` Mutation | ✅ |
| `GradeService.ListGradesByStudent` | `myGrades` Query | ✅ |
| `GradeService.GetReportCard` | `myReportCard` Query | ✅ |
| `ScheduleService.GetScheduleByStudent` | `mySchedule` Query | ✅ |
| `AttendanceService.ListAttendanceByStudent` | `myAttendance` Query | ✅ |
| `LeaveRequestService.ListLeaveRequestsByStudent` | `myLeaveRequests` Query | ✅ |
| `LeaveRequestService.CreateLeaveRequest` | `createLeaveRequest` Mutation | ✅ |
| `LeaveRequestService.CancelLeaveRequest` | `cancelLeaveRequest` Mutation | ✅ |
| `ClassService.GetClass` | `myClasses` Query | ✅ |
| `ClassService.ListStudentsByClass` | `myClasses` Query | ✅ |
### 4.3 content 服务ai09 负责)
**v2 核查结果:⚠️ 需确认**
student-bff 需要 8 个 content RPC需 ai09 确认以下 RPC 是否已实现:
| gRPC 方法 | 用途 | 状态 |
| ------------------------------------------------- | -------------------------------- | ------ |
| `TextbookService.ListTextbooks` | `textbooks` Query | 需确认 |
| `ChapterService.ListChapters` | `chapters` Query | 需确认 |
| `KnowledgeGraphService.GetLearningPath` | `learningPath` Query | 需确认 |
| `ElectiveService.ListElectiveSelectionsByStudent` | `myElectiveSelections` Query | 需确认 |
| `ElectiveService.ListAvailableElectiveCourses` | `availableElectiveCourses` Query | 需确认 |
| `ElectiveService.SelectCourse` | `selectElectiveCourse` Mutation | 需确认 |
| `ElectiveService.DropCourse` | `dropElectiveCourse` Mutation | 需确认 |
| `LessonPlanService.ListLessonPlansByStudent` | `myLessonPlans` Query | 需确认 |
| `LessonPlanService.GetLessonPlan` | `lessonPlanDetail` Query | 需确认 |
| `CoursePlanService.ListCoursePlansByStudent` | `myCoursePlans` Query | 需确认 |
| `CoursePlanService.GetCoursePlan` | `coursePlanDetail` Query | 需确认 |
### 4.4 data-ana 服务ai12 负责)
**v2 核查结果:⚠️ 需确认**
student-bff 需要 8 个 data-ana RPC需 ai12 确认以下 RPC 是否已实现:
| gRPC 方法 | 用途 | 状态 |
| ----------------------------------------------- | ------------------------------- | ------ |
| `AnalyticsService.GetStudentDashboard` | `studentDashboard` Query | 需确认 |
| `AnalyticsService.GetStudentWeakness` | `myWeakness` Query | 需确认 |
| `AnalyticsService.GetLearningTrend` | `myTrend` Query | 需确认 |
| `AnalyticsService.GetStudentGrowth` | `studentGrowth` Query | 需确认 |
| `AnalyticsService.GetAssignmentAnalysis` | `assignmentAnalysis` Query | 需确认 |
| `AnalyticsService.GetMasterySummary` | `myMasterySummary` Query | 需确认 |
| `AnalyticsService.ListDiagnosticReports` | `myDiagnosticReports` Query | 需确认 |
| `AnalyticsService.ListErrorBookItems` | `myErrorBook` Query | 需确认 |
| `PracticeService.ListPracticeSessionsByStudent` | `myPracticeSessions` Query | 需确认 |
| `PracticeService.StartPracticeSession` | `startPracticeSession` Mutation | 需确认 |
| `PracticeService.SubmitPracticeAnswer` | `submitPracticeAnswer` Mutation | 需确认 |
### 4.5 msg 服务ai10 负责)
**v2 核查结果:✅ 全部就绪gRPC + REST 混合)**
msg 已实现 13 个 gRPC RPC + 完整 REST API
| gRPC / REST 方法 | 用途 | 状态 |
| ------------------------------------------------- | --------------------------------------- | ---- |
| `NotificationService.ListNotifications` | `myNotifications` Query | ✅ |
| `NotificationService.MarkAsRead` | `markAsRead` Mutation | ✅ |
| `NotificationService.MarkAllAsRead` | `markAllAsRead` Mutation | ✅ |
| `NotificationPreferenceService.GetPreferences` | 通知偏好查询 | ✅ |
| `NotificationPreferenceService.UpdatePreferences` | `updateNotificationPreference` Mutation | ✅ |
| REST `GET /announcements` | `announcements` Query | ✅ |
| REST `GET /announcements/:id` | `announcementDetail` Query | ✅ |
| REST `POST /announcements/:id/read` | `markAnnouncementRead` Mutation | ✅ |
### 4.6 ai 服务ai11 负责)
**v2 核查结果:⚠️ 需确认**
| gRPC 方法 | 用途 | 状态 |
| ------------------------ | ----------------------- | ------ |
| `ChatService.Chat` | `aiChat` Query | 需确认 |
| `ChatService.StreamChat` | `aiStream` Subscription | 需确认 |
### 4.7 push-gatewayai13 负责)
**v2 核查结果:✅ 已验证**
push-gateway 采用通用事件透传机制,三个事件均已 Docker 验证通过:
- `ExamExtended`
- `ExamForceSubmitted`
- `ExamQuestionReordered`
### 4.8 core-edu 事件发布ai08 待修复)
**v2 核查结果:❌ 未实现**
`ExamExtended` / `ExamForceSubmitted` / `ExamQuestionReordered` 事件字面量在 core-edu 源码中仍未找到。这三个事件由教师端触发(延长考试/强制收卷/调整题目),需 core-edu 在相应业务操作中通过 Outbox 发布到 Kafka topic `edu.exam.events`
**影响:** 考试实时推送功能不可用非阻断student-bff 可降级)。
---
## 5. student-bff 需要其他模块配合的工作
### 5.1 SRE AIP0 部署阻断)
1. **新增 `infra/docker-compose.deploy.yml` 中 student-bff 服务定义**(见 §3.2 模板)
2. **新增 `infra/docker-compose.deploy.yml` 中 student-portal 服务定义**
3. **api-gateway environment 补充 `STUDENT_BFF_URL: http://student-bff:3009`**
### 5.2 ai09 content 服务P0 功能阻断)
确认并实现以下 RPC如尚未实现
- ElectiveService 4 RPCListElectiveSelectionsByStudent / ListAvailableElectiveCourses / SelectCourse / DropCourse
- LessonPlanService 2 RPCListLessonPlansByStudent / GetLessonPlan
- CoursePlanService 2 RPCListCoursePlansByStudent / GetCoursePlan
### 5.3 ai12 data-ana 服务P0 功能阻断)
确认并实现以下 RPC如尚未实现
- AnalyticsService 8 RPCGetStudentDashboard / GetStudentWeakness / GetLearningTrend / GetStudentGrowth / GetAssignmentAnalysis / GetMasterySummary / ListDiagnosticReports / ListErrorBookItems
- PracticeService 3 RPCListPracticeSessionsByStudent / StartPracticeSession / SubmitPracticeAnswer
### 5.4 ai11 ai 服务P1 可降级)
确认并实现以下 RPC如尚未实现
- ChatService.Chat同步 AI 答疑)
- ChatService.StreamChatSSE 流式 AI 答疑)
### 5.5 ai08 core-edu 服务P1 事件发布)
实现以下 Kafka 事件发布:
- `ExamExtended`(延长考试时间时发布)
- `ExamForceSubmitted`(强制收卷时发布)
- `ExamQuestionReordered`(调整题目顺序时发布)
发布到 topic `edu.exam.events`student-bff EventSubscriber 消费后转发到 push-gateway。
---
## 6. 联调就绪状态
```
student-portal ──✅──> api-gateway ──✅──> student-bff ──✅──> [60 操作全部注册]
├──✅──> core-edu (40 RPC 就绪)
├──✅──> iam (15 RPC 就绪)
├──✅──> msg (13 RPC + REST 就绪)
├──⚠️──> content (需确认)
├──⚠️──> data-ana (需确认)
├──⚠️──> ai (需确认)
└──❌──> docker-compose 未配置
```
**结论:** student-bff 自身已完全就绪v2 全部 P0/P1 已修复并验证)。待 SRE AI 配置 docker-compose + content/data-ana/ai 服务确认 RPC 后,可进行端到端联调。
---
## 7. 已知限制
| # | 限制 | 说明 |
| --- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| 1 | Dockerfile 使用 `--filter @edu/student-bff...` | 过滤掉 scripts/arch-scan 的 better-sqlite3 原生编译依赖,避免 alpine 缺少 build-essential |
| 2 | Dockerfile 需先构建 shared-ts | student-bff 运行时依赖 `@edu/shared-ts/bff` 的 dist 产物Dockerfile 已包含 shared-ts 构建步骤 |
| 3 | shared-ts pino 需 namespace import | pino 在 NodeNext + ESM 下 default import 丢失 callable 签名,已通过 namespace import 修复 |
| 4 | Kafka 未启动时 EventSubscriber 软失败 | 服务正常启动,但实时事件推送(通知/AI 流式响应)不工作 |
| 5 | 下游 gRPC 未就绪时进入降级模式 | 所有 Query 返回 `degraded=true` + 空数据;所有 Mutation 返回 `success=false` + BAD_GATEWAY |
| 6 | DEV_MODE=true 时跳过 B4 越权校验 | 生产环境必须 `DEV_MODE=false`,由 api-gateway 注入 `x-user-id` header |
---
**本文件由 ai04 维护。student-bff v2 全部工作已完成,待下游服务确认 + SRE 部署配置后可联调。**