feat(student-bff): 完整实现 student-bff 聚合层
包含 src 全部实现、Dockerfile、shared-ts/bff 包等
This commit is contained in:
@@ -478,6 +478,30 @@
|
||||
| ParentSession 值对象 | parentId/roles/dataScope:CHILDREN/requestedChildId/traceId,每次请求重建不跨请求(004 §12.1 无状态约束) |
|
||||
| 通知偏好配置 | NotificationPreference(渠道开关 channels[] + 频率限制 frequency_limit + 静默时段 quiet_hours),P4 通过 msg 服务管理 |
|
||||
|
||||
### 2.14.1 student-bff(TS/NestJS/GraphQL,P3)
|
||||
|
||||
> student-bff 是学生场景域 BFF 聚合层,GraphQL Yoga + gRPC 下游通信。本节仅记录 student-bff **特有**的"场景→技术"映射,通用 NestJS 映射见 §1.4。
|
||||
|
||||
| 场景 | 技术/规则 |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| P3 API 风格 | **GraphQL Yoga**(coord §B1 裁决,P2 起直接 GraphQL,禁止 REST 渐进);schema 存放 `packages/shared-ts/contracts/graphql/student-bff.schema.graphql`(president §2.2.1) |
|
||||
| P3 下游通信 | **gRPC 首次即用**(coord §B2 裁决,@grpc/grpc-js + @grpc/proto-loader,禁止 HTTP fetch);DownstreamClient 抽象复用 shared-ts(coord §B8,3 BFF 统一) |
|
||||
| P3 错误码前缀 | `BFF_STUDENT_`(coord §B5 裁决,BFF 在前,非 `STUDENT_BFF_`);i18n key `error.bffStudent.<code_snake>`(coord §F4) |
|
||||
| P3 越权防御 | AuthorizationGuard 强制 `studentId = userId`(coord §B4);场景 A 抛 `ForbiddenResourceError`,场景 B 抛 `IdentityMismatchError`(president §2.7);DEV_MODE 放行(president §2.9 方案 D)|
|
||||
| P3 降级模式 | 方案 B(president §2.6):`success=true + data 内 degraded=true + degradedFields`,下游部分失败仍返回部分数据 |
|
||||
| P3 Redis 缓存 | 5-30s 短缓存(coord §B6),TTL ±20% 随机抖动防雪崩;CacheService 封装 get/set/invalidate/invalidateByPrefix |
|
||||
| P3 ESM 相对 import 路径深度 | 嵌套目录(如 `src/student/events/`、`src/student/guards/`)引用 shared 层需 `../../shared/` 前缀(非 `../shared/`),NodeNext + .js 后缀 |
|
||||
| P5 GraphQL Subscription SSE | GraphQL Yoga 原生 SSE 传输;AsyncGenerator 桥接 gRPC server-streaming(chunkQueue + resolveWait 机制将 Node ReadableStream 'data'/'end'/'error' 事件转为 async iterable) |
|
||||
| P5 DownstreamClient.callStream| gRPC server-streaming 调用 `callFn.call(client, request, meta, { deadline })`,返回 Node ReadableStream,需手动转换为 AsyncIterable;finally 块调用 `stream.destroy?.()` 清理 |
|
||||
| P5 Push-gateway 模块化 | 从 EventSubscriber 解耦推送逻辑为独立 PushGatewayService(DI 注入),fetch POST + AbortSignal.timeout(3000),失败软处理(仅 warn 日志,不抛异常) |
|
||||
| P5 Kafka 事件订阅 | coord §B7 裁决:P2-P4 不订阅,P5 起订阅 7 个 topic;消费者组 `student-bff-event-subscriber`;Redis SETNX `event_id` 幂等去重 |
|
||||
| P6 熔断器设计 | opossum 库,每下游服务一个独立 CircuitBreaker 实例(Map 缓存);action 函数闭包捕获动态参数;状态变更监听同步 Prometheus 指标(student_bff_circuit_state Gauge) |
|
||||
| P6 熔断器配置 | timeout 5000ms,errorThresholdPercentage 50,resetTimeout 30000,volumeThreshold 10,rollingCountTimeout 60000(coord §G11) |
|
||||
| Mock 模式 | `env.MOCK_UPSTREAM=true` 时 DownstreamClient 返回固定数据(config/mock-data.ts),callStream 产出单个 mock chunk 后结束 |
|
||||
| /readyz 探针 | 检查 6 个下游服务可达性(iam/classes/core-edu/content/msg/ai/data-ana),必需失败返回 503,可选软失败返回 200 + degraded=true |
|
||||
| ActionState 信封 | coord §G8 裁决:成功 `{success: true, data, meta?}`,失败 `{success: false, error: {code, message, i18nKey, details?, traceId?}}`;ok()/fail()/degraded() 工具函数 |
|
||||
| GraphQL Resolver 测试 Mock | vi.mock 模拟 env/metrics/logger,vi.stubGlobal 模拟 fetch,mockContext 工厂函数注入 downstream/redis mock 对象;Vitest 覆盖率 ≥ 80% |
|
||||
|
||||
### 2.15 student-portal(学生端微前端 Remote,P3)
|
||||
|
||||
> student-portal 复用 teacher-portal Shell 暴露的 AppShell / usePermission / ApiClient / ErrorBoundary / 设计令牌 / A11y 工具集,本节仅记录 student-portal **特有**的"场景→技术"映射,通用前端映射见 §2.12。
|
||||
|
||||
Reference in New Issue
Block a user