chore(teacher-bff): merge teacher-bff full implementation into main
This commit is contained in:
@@ -420,28 +420,28 @@
|
||||
|
||||
### 2.9 ai(Python/FastAPI,P5)
|
||||
|
||||
| 场景 | 技术/规则 |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| LLM Provider 适配 | 4 适配器(OpenAI/Anthropic/Baichuan/Ollama)+ ProviderFailoverChain + CircuitBreaker(3 次失败 60s 熔断) |
|
||||
| 降级模式方案 B | success=true + error=null + data 内 degraded=true + degraded_reason(总裁 §2.6,非顶层 degraded 字段) |
|
||||
| ActionState 信封 | 所有 HTTP 响应统一 `{success, data, error:{code,message,details?,traceId?}}`(004 §11.5 强制) |
|
||||
| 路由前缀 | /v1/ai 前缀(APIRouter prefix="/v1/ai"),Gateway 代理 /api/v1/ai/* → /v1/ai/* |
|
||||
| gRPC server | grpc.aio 端口 50058,8 RPC + 3 interceptor(Logging/Auth/Error) |
|
||||
| 评估三道防线 | RuleValidator(JSON/字段/难度校验)→ LLMJudge(语义评分)→ QualityGate(综合决策门控) |
|
||||
| 备课工作流 | P5 用 asyncio.create_task + Redis 状态存储(24h TTL),P6+ 评估 Temporal |
|
||||
| 工作流状态机 | pending→analyzing→generating→pending_review→persisted/failed,生成失败重试最多 3 次 |
|
||||
| 限流三维度 | user 10/min + IP 30/min + school 100/min,Redis Lua 原子令牌桶,Redis 不可用降级放行 |
|
||||
| 用量记录 | Redis INCRBY 按 user/school/month 维度,35 天过期;Kafka 发布 AIUsageEvent 到 edu.ai.usage topic |
|
||||
| Kafka 派生数据豁免 Outbox | AIUsageEvent 为派生数据,004 §12.2 豁免 Outbox,直接 aiokafka producer(事务性 + 幂等) |
|
||||
| 安全层全本地 | PIIRedactor(5 类 PII 正则脱敏)+ InputSanitizer(prompt injection 检测)+ OutputModerator(5 类敏感内容审核) |
|
||||
| 六边形架构端口模式 | ContentClient/DataAnaClient/IamClient 均为抽象接口 + Mock + gRPC 实现,全并行模式用 Mock |
|
||||
| 权限校验 | PermissionGuard 5 权限点(ai:chat / ai:question:generate / ai:expression:optimize / ai:lesson:generate / confirm) |
|
||||
| dev_mode tracer | dev_mode=true 时跳过 OTel exporter 初始化 + 跳过权限校验 |
|
||||
| proto 包名 | 保持 `next_edu_cloud.<domain>.v1`(coord G17 裁决覆盖 project_rules §5) |
|
||||
| proto_gen 排除 ruff | pyproject.toml `[tool.ruff] exclude = ["src/ai/proto_gen"]`,自动生成文件不参与 lint |
|
||||
| ruff UP017 | `datetime.now(timezone.utc)` 改用 `datetime.now(datetime.UTC)` 别名(Python 3.12+) |
|
||||
| ruff SIM103/SIM110 | `if x: return False; return True` 改 `return not x`;for 循环改 `all()` 表达式 |
|
||||
| PowerShell 不支持 && | RunCommand 用 cwd 参数指定工作目录,不用 `cd ... && uv run` |
|
||||
| 场景 | 技术/规则 |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| LLM Provider 适配 | 4 适配器(OpenAI/Anthropic/Baichuan/Ollama)+ ProviderFailoverChain + CircuitBreaker(3 次失败 60s 熔断) |
|
||||
| 降级模式方案 B | success=true + error=null + data 内 degraded=true + degraded_reason(总裁 §2.6,非顶层 degraded 字段) |
|
||||
| ActionState 信封 | 所有 HTTP 响应统一 `{success, data, error:{code,message,details?,traceId?}}`(004 §11.5 强制) |
|
||||
| 路由前缀 | /v1/ai 前缀(APIRouter prefix="/v1/ai"),Gateway 代理 /api/v1/ai/* → /v1/ai/* |
|
||||
| gRPC server | grpc.aio 端口 50058,8 RPC + 3 interceptor(Logging/Auth/Error) |
|
||||
| 评估三道防线 | RuleValidator(JSON/字段/难度校验)→ LLMJudge(语义评分)→ QualityGate(综合决策门控) |
|
||||
| 备课工作流 | P5 用 asyncio.create_task + Redis 状态存储(24h TTL),P6+ 评估 Temporal |
|
||||
| 工作流状态机 | pending→analyzing→generating→pending_review→persisted/failed,生成失败重试最多 3 次 |
|
||||
| 限流三维度 | user 10/min + IP 30/min + school 100/min,Redis Lua 原子令牌桶,Redis 不可用降级放行 |
|
||||
| 用量记录 | Redis INCRBY 按 user/school/month 维度,35 天过期;Kafka 发布 AIUsageEvent 到 edu.ai.usage topic |
|
||||
| Kafka 派生数据豁免 Outbox | AIUsageEvent 为派生数据,004 §12.2 豁免 Outbox,直接 aiokafka producer(事务性 + 幂等) |
|
||||
| 安全层全本地 | PIIRedactor(5 类 PII 正则脱敏)+ InputSanitizer(prompt injection 检测)+ OutputModerator(5 类敏感内容审核) |
|
||||
| 六边形架构端口模式 | ContentClient/DataAnaClient/IamClient 均为抽象接口 + Mock + gRPC 实现,全并行模式用 Mock |
|
||||
| 权限校验 | PermissionGuard 5 权限点(ai:chat / ai:question:generate / ai:expression:optimize / ai:lesson:generate / confirm) |
|
||||
| dev_mode tracer | dev_mode=true 时跳过 OTel exporter 初始化 + 跳过权限校验 |
|
||||
| proto 包名 | 保持 `next_edu_cloud.<domain>.v1`(coord G17 裁决覆盖 project_rules §5) |
|
||||
| proto_gen 排除 ruff | pyproject.toml `[tool.ruff] exclude = ["src/ai/proto_gen"]`,自动生成文件不参与 lint |
|
||||
| ruff UP017 | `datetime.now(timezone.utc)` 改用 `datetime.now(datetime.UTC)` 别名(Python 3.12+) |
|
||||
| ruff SIM103/SIM110 | `if x: return False; return True` 改 `return not x`;for 循环改 `all()` 表达式 |
|
||||
| PowerShell 不支持 && | RunCommand 用 cwd 参数指定工作目录,不用 `cd ... && uv run` |
|
||||
|
||||
### 2.10 shared-proto(契约包)
|
||||
|
||||
@@ -592,3 +592,27 @@
|
||||
| P3 MF 降级与版本协商 | Remote `remoteEntry.js` 加载失败 → fallback 独立页面 + 错误提示;共享依赖版本不匹配 → 运行时协商降级 |
|
||||
| P3 AI 答疑 SSE 流式(P5) | `POST /student/ai/stream-chat` SSE 流式响应 + `streamingText` 逐字渲染 + 打字机效果 + AbortController 取消 |
|
||||
| P3 权限点命名 | 与 student-bff §3.2 对齐 `STUDENT_*_READ` 风格(`STUDENT_DASHBOARD_READ`/`STUDENT_EXAM_READ`/`STUDENT_HOMEWORK_SUBMIT`/`STUDENT_GRADE_READ` 等) |
|
||||
|
||||
### 2.16 teacher-bff(TS/NestJS,P2)
|
||||
|
||||
> teacher-bff 是 GraphQL 聚合层(B1 裁决:P2 起直接 GraphQL),无 DB,无 @RequirePermission(B3 豁免),做数据权限防御(B4)。本节记录 teacher-bff 特有的"场景→技术"映射。
|
||||
|
||||
| 场景 | 技术/规则 |
|
||||
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| P2 GraphQL 直接实现 | B1 裁决:P2 起直接 GraphQL Yoga(禁止 REST 过渡),POST /graphql endpoint + SDL-first schema(packages/shared-ts/contracts/graphql/) |
|
||||
| P2 gRPC 下游通信 | B2 裁决:首次实现即 gRPC(禁止 REST fetch),@grpc/grpc-js + @grpc/proto-loader 动态加载 proto(无生成代码依赖) |
|
||||
| DownstreamClient 抽象 | B8 裁决:3 个 BFF 共用标准抽象层(src/clients/),base.client.ts + grpc.factory.ts + per-service client(iam/client.interface + grpc + mock) |
|
||||
| DEV_MODE mock 开关 | TEACHER_BFF_DEV_MODE=true → IamClient 走 mock(固定数据);false → gRPC(未就绪 RPC 降级 mock + warning,president §2.6 降级模式 B) |
|
||||
| 越权防御 3 类错误码 | president §2.7:UNAUTHORIZED(401) / FORBIDDEN_RESOURCE(403 场景 A 资源无归属) / IDENTITY_MISMATCH(403 场景 B JWT 与 body 不一致) |
|
||||
| AuthorizationGuard P2 策略 | president §2.9:P2 DEV_MODE 放行 + 日志告警,生产保守拒绝;P3+ 接入 core-edu.GetClassesByTeacher 真实校验 |
|
||||
| /readyz 探针注册表 | president §2.4:DownstreamHealthCheck 注册表模式,P2 = Redis + iam gRPC(2 项),按阶段扩展(P3=3/P4=5/P5=7);必需依赖失败返 503,可选失败返 200+degraded |
|
||||
| Dashboard Resolver P2 实现 | president §2.8:P2 仅调 iam gRPC(user+viewports 有数据),未启用字段返 null + extensions.warning="field_unavailable_in_p2" |
|
||||
| admin 命名空间预留 | president §5.1:P2 预留 schema(AdminQuery/AdminMutation 类型声明),Resolver 返 null/空;P6 实现 Resolver 真实数据(admin-portal 复用 teacher-bff GraphQL endpoint) |
|
||||
| 错误码 BFF_TEACHER_ 前缀 | B5 + G14 裁决:统一 BFF_ 前缀(非 TEACHER_BFF_),含 10 个错误码(validation/unauthorized/forbidden_resource/identity_mismatch/not_found/conflict/business/upstream_unavailable/aggregation_failed/internal) |
|
||||
| ESM .js 后缀 | G12 裁决:NestJS ESM 模式下相对 import 必须带 .js 后缀(构建产物),所有源码 import 路径已对齐 |
|
||||
| import type 强制 | G13 裁决:仅类型导入用 `import type`,运行时导入用 `import` |
|
||||
| gRPC 健康检查 | grpc.health.v1.Health/Check 标准协议,makeUnaryRequest + 2s 超时,解析 HealthCheckResponse.status varint |
|
||||
| ioredis ESM 导入类型 | `import IORedis from "ioredis"` ESM 下报 TS2709/TS2351,改用命名导入 `import { Redis } from "ioredis"`,类型注解用 `Redis` 而非 `IORedis` |
|
||||
| NestJS HttpAdapter 路由注册 | `app.getHttpAdapter().get()` 的 RequestHandler 与 Express 类型不兼容,改用 `getInstance() as Application` 获取 Express 实例后注册路由 |
|
||||
| graphql-yoga v5 context | YogaInitialContext 不含 response,context 回调只解构 `{ request }`,buildGraphQLContext 只接收 request(P5+ SSE 再扩展 response) |
|
||||
| readonly 属性延迟初始化 | `readonly` 属性只能在构造函数赋值,需在 initLogger() 方法中重新赋值时移除 readonly 修饰符 |
|
||||
|
||||
Reference in New Issue
Block a user