Files
Edu/docs/architecture/ai03-phase1-understanding.md
SpecialX 0a71b02e04
Some checks failed
CI / quality-ts (push) Failing after 48s
CI / quality-go (push) Failing after 4s
CI / quality-proto (push) Failing after 2s
CI / deploy (push) Has been skipped
fix: code compliance audit and fix across all services
NestJS (6 services): implement @RequirePermission decorator with
SetMetadata+Reflector, register APP_GUARD globally, fix as assertions
to type guards, add explicit return types, fix import type for express,
fix /metrics implicit any, replace native Error with ApplicationError,
remove typeorm remnants, register LifecycleService.

teacher-bff: add logger, ApplicationError, GlobalErrorFilter, forward
real userId to downstream, log downstream failures, migrate health
controller to shared/health.

Go (2 services): interface to any, doc comments, CORS dev whitelist,
JWT secret fail-fast, push-gateway internal API auth, metrics and
readyz endpoints, remove dead code.

Python (2 services): lifespan return type, dev_mode to bool, data-ana
APIRouter, ai POST body model, ClickHouse async wrapping.
2026-07-09 17:28:27 +08:00

217 lines
15 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.
# ai03 阶段 1 交付物:模块理解确认书
> AI 标识ai03
> 负责模块teacher-bffP2、core-eduP3
> 阶段:架构设计外包 · 阶段 1全局理解
> 日期2026-07-09
> 关联文档:[ai-allocation.md](./ai-allocation.md)、[004 架构影响地图](./004_architecture_impact_map.md)、[pending-features.md](./roadmap/pending-features.md)
---
## 模块理解确认书 — teacher-bff
### 1. 我在架构中的位置
- **层级**BFF 聚合层L4
- **上游**api-gatewayGo/Gin通过 HTTP 转发请求,注入 `x-user-id` / `x-user-roles`
- **下游**iam3002、classes3001、core-edu3004P3 后扩展 content、data-ana、ai
- **通信方式**
- 当前REST `fetch`(同步)
- 目标态004 §4.1 / pending-features P2**gRPC** 调下游业务服务 + **GraphQL Yoga** 对前端暴露 + DataLoader 防 N+1
- **端口**3003见 [teacher-bff env.ts](../../services/teacher-bff/src/config/env.ts)
### 2. 我的限界上下文
- **聚合职责**:教学场景域(教师 / 教导主任 / 教研组长 共用)的数据聚合、裁剪、协议转换
- **业务领域**:跨 D2 教学组织 + D3 教学核心 + D1 身份认证(只读拉取视口/权限)
- **我不负责**
- 不持有业务状态(无 DB 写入,无 Outbox
- 不做权限决策(依赖 Gateway JWT 校验 + 下游服务 `@RequirePermission`
- 不直接访问任何业务服务数据库
- **复用策略**004 §5.4):教导主任 / 教研组长复用 Teacher BFF通过视口差异化L1 导航扩展管理菜单L4 DataScope 扩大到年级)
### 3. 我与外部的契约
- **消费的 proto message**
- `iam.v1.IamService`GetUserInfo / getEffectivePermissions视口 + DataScope
- `classes.v1.ClassService`ListClasses / GetClass
- `core_edu.v1.ExamService / HomeworkService / GradeService`:全部 RPC
- **暴露的 API**(当前 REST目标 GraphQL
- `GET /teacher/dashboard` — 聚合 IAM 用户信息 + classes 列表
- `GET /teacher/viewports` — 拉取 IAM 视口配置L1 导航)
- `GET /teacher/classes/:classId/exams` — 聚合 core-edu 考试列表
- `GET /teacher/classes/:classId/homework` — 聚合 core-edu 作业列表
- `GET /teacher/exams/:examId/grades` — 聚合 core-edu 成绩列表
- **错误码前缀**BFF 自身错误用 `BAD_GATEWAY`(下游不可达);业务错误透传下游 `CORE_EDU_*` / `IAM_*` / `CLASSES_*`
- **缓存**:聚合结果 Redis 短缓存 5-30s004 §6.3,当前未实现)
### 4. 我的技术栈
- 语言TypeScript 5.5+ESM 模式,相对 import 带 `.js` 后缀)
- 框架NestJS 10
- 下游通信:当前 `fetch`REST→ 目标 `@grpc/grpc-js` + `@bufbuild/protobuf`
- 对前端:目标 GraphQL Yoga + DataLoader
- 缓存Redis待引入
- 可观测pino logger + prom-client metrics + OpenTelemetry tracer已具备 [tracer.ts](../../services/teacher-bff/src/shared/observability/tracer.ts)
### 5. 我的阶段归属
- **P2 身份**:教师登录 → 获取 JWT → 访问 teacher-portal → 侧边栏按 viewports.L1 渲染 → 空白 Dashboard
- **P3 扩展**:考试/作业/成绩的 GraphQL 查询与 mutation
- **依赖上游**P1 黄金模板 classes、P2 iamgetEffectivePermissions + 视口)
### 6. 我需要对齐的黄金模板项(对照 classes 服务)
- [ ] 权限装饰器 `@RequirePermission`**BFF 不做权限决策**当前无目标态BFF 不加 Guard仅校验 `x-user-id` 存在)
- [x] 错误处理:[GlobalErrorFilter](../../services/teacher-bff/src/shared/errors/global-error.filter.ts) + ApplicationError 层次
- [x] logger / metrics / tracer 三支柱(已具备)
- [x] `/healthz` 健康检查HealthModule 已注册)
- [ ] `/readyz`(当前 HealthController 仅 liveness无下游就绪探针
- [x] 优雅关闭 SIGTERMmain.ts 已处理)
- [ ] 测试覆盖率 ≥ 80%**当前 0%**,无测试文件)
- [ ] Dockerfile 多阶段构建(需核对)
- [ ] Zod 输入验证(当前 Controller 直接透传 unknown**未做 Zod 校验**
- [x] GlobalErrorFilter 统一兜底
---
## 模块理解确认书 — core-edu
### 1. 我在架构中的位置
- **层级**业务微服务层L5
- **上游**teacher-bff聚合层、api-gateway直接路由 `/api/v1/exams` 等)
- **下游**MySQL独占库、Kafka事件发布、Redis待引入高并发提交锁
- **通信方式**
- 入口:当前 REST`/exams``/homework``/grades`
- 目标态proto 注释P3 起转 gRPC`core_edu.v1.ExamService/HomeworkService/GradeService` 已定义)
- 出口Kafka 事件Outbox 模式发布)
- **端口**3004见 [core-edu env.ts](../../services/core-edu/src/config/env.ts)
### 2. 我的限界上下文
- **聚合职责**:跨 **D2 教学组织**classes 模块,待合并)+ **D3 教学核心**exams / homework / grades
- **聚合根**Exam、Homework、Grade、Class待合并
- **我不负责**
- 不负责题库内容(→ content 服务)
- 不负责学情分析(→ data-ana 服务,消费 core-edu 事件)
- 不负责通知投递(→ msg 服务,消费 core-edu 事件)
- **数据自治**:独占 `core_edu` 数据库,表前缀 `core_edu_*`
### 3. 我与外部的契约
- **暴露的 gRPC 契约**[core_edu.proto](../../packages/shared-proto/proto/core_edu.proto),已定义待实现):
- `ExamService`CreateExam / GetExam / ListExamsByClass / UpdateExam / DeleteExam
- `HomeworkService`AssignHomework / GetHomework / ListHomeworkByClass / SubmitHomework
- `GradeService`RecordGrade / GetGrade / ListGradesByStudent/Exam/Homework
- **发布的领域事件**[events.proto](../../packages/shared-proto/proto/events.proto) + [outbox.publisher.ts TOPIC_MAP](../../services/core-edu/src/shared/outbox/outbox.publisher.ts)
| 事件 | Topic | 触发时机 | 消费者 |
| ------------------ | ------------------- | --------------------- | ------------- |
| exam.created | edu.exam.events | CreateExam 事务内 | msg、data-ana |
| exam.updated | edu.exam.events | UpdateExam | msg |
| exam.deleted | edu.exam.events | DeleteExam | data-ana |
| homework.assigned | edu.homework.events | AssignHomework | msg、data-ana |
| homework.submitted | edu.homework.events | SubmitHomework | data-ana、msg |
| homework.graded | edu.homework.events | **未实现**P3 待补) | msg、data-ana |
| grade.recorded | edu.grade.events | RecordGrade | data-ana、msg |
| grade.updated | edu.grade.events | **未实现**P3 待补) | data-ana |
| class.transferred | edu.class.events | classes 合并后 | data-ana |
- **消费的事件**`edu.identity.user.created`IAM初始化教师默认班级关联**当前未消费**P3 待补)
- **错误码前缀**`CORE_EDU_*`(见 [application-error.ts CoreEduErrorCode](../../services/core-edu/src/shared/errors/application-error.ts)
### 4. 我的技术栈
- 语言TypeScript 5.5+ESM 模式)
- 框架NestJS 10
- ORMDrizzle ORMmysql2 driver直接 `db` 导出,**与 classes 的 `getDb()` 不一致**
- 存储MySQL 8独占库、Redis待引入、Kafkakafkajsidempotent + transactionalId
- 可观测pino + prom-client + OTel已具备
### 5. 我的阶段归属
- **P3 核心教学**:考试全生命周期 + Outbox + Kafka 事件落地
- **退出标准**:教师创建考试 → 发布 → 学生作答 → 教师批改 → 事件到 Kafka → 成绩统计更新 → 全链路可观测
- **依赖上游**P1 classes 黄金模板、P2 iam用户身份 + 权限)
### 6. 我需要对齐的黄金模板项(对照 classes 服务)
- [x] 权限装饰器 `@RequirePermission`exams.controller 全覆盖;需核对 homework/grades controller
- [x] 错误码前缀 `CORE_EDU_*`(已用 [CoreEduErrorCode 枚举](../../services/core-edu/src/shared/errors/application-error.ts)
- [x] logger / metrics / tracer 三支柱
- [x] `/healthz` 健康检查
- [ ] `/readyz`(需补 DB SELECT 1 / Kafka 连接探针)
- [x] 优雅关闭 SIGTERMmain.ts 已处理 outboxPublisher.stop + disconnectKafka
- [ ] 测试覆盖率 ≥ 80%**当前 0%**,无测试文件)
- [ ] Dockerfile 多阶段构建(需核对)
- [ ] Zod 输入验证(**当前 Controller 直接接收 body未 Zod 校验**classes 用 zod schema
- [x] GlobalErrorFilter 统一兜底
- [x] Outbox 模式(事务内写业务表 + outbox 表,独立 publisher 投递)
---
## §10 服务审计表 — ai03
> 对照 [黄金模板 classes 服务](../../services/classes/src/),审计已实现的两服务。状态:✅ 达标 / ⚠️ 部分 / ❌ 缺失
| 服务 | 权限装饰器 | 错误码前缀 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile |
| ----------- | --------------------------------------- | --------------------------------- | ------- | -------------- | ------- | -------- | ------- | -------- | ---------- | ---------- |
| teacher-bff | ⚠️ 无BFF 不做权限决策,依赖 Gateway | ⚠️ 用 `BAD_GATEWAY`(无自有前缀) | ✅ pino | ✅ prom-client | ✅ OTel | ✅ | ❌ | ✅ | 0% ❌ | 待核对 |
| core-edu | ✅ `@RequirePermission(EXAM_*)` 全覆盖 | ✅ `CORE_EDU_*` | ✅ pino | ✅ prom-client | ✅ OTel | ✅ | ❌ | ✅ | 0% ❌ | 待核对 |
### 审计发现的关键差距P3 阶段 2 设计需解决)
**teacher-bff**
1. ❌ 通信方式:当前 REST `fetch`,目标 gRPC + GraphQLP2 退出标准要求 GraphQL Yoga + DataLoader
2. ❌ 无 Redis 聚合缓存004 §6.3 要求 5-30s 短缓存)
3. ❌ 无 DataLoader防 N+1pending-features P2 明确要求)
4. ❌ 无 `/readyz` 下游就绪探针
5. ⚠️ env 配置用 `IamServiceUrl`/`ClassesServiceUrl`REST URL转 gRPC 后需改为 gRPC target
6. ⚠️ 无 Zod 输入验证
7. ⚠️ 无测试
**core-edu**
1. ❌ 考试生命周期状态机缺失(当前仅 `draft` 初值,无 `published → in_progress → grading → graded → archived` 转换与校验)
2. ❌ 作业状态机不完整(仅 `assigned → submitted`,缺 `graded`pending-features 要求 `HomeworkGraded` 事件)
3. ❌ 成绩录入无业务校验(不校验 exam/homework 是否存在、score 是否在 totalScore 范围内、是否重复录入)
4. ❌ 作业提交高并发优化缺失004 §9.2 要求 Redis 分布式锁 + 排队)
5. ❌ 无 `grade.updated` / `homework.graded` 事件触发点proto 已定义service 未实现)
6. ❌ 未消费 IAM `user.created` 事件(初始化教师默认关联)
7. ⚠️ Drizzle `db` 直接导出 vs classes 的 `getDb()` 函数式 — **不一致**,建议统一为 `getDb()`
8. ⚠️ [kafka.ts](../../services/core-edu/src/config/kafka.ts) 用 `console.log`/`console.warn`,应改用结构化 logger
9. ⚠️ classes 模块在 core-edu 仅有 `classes.module.ts` 占位,**P3 待合并**classes 服务代码迁入 + 删除独立 services/classes
10. ⚠️ 入口仍为 RESTproto gRPC 契约已定义但未接入 `@grpc/grpc-js` + buf generate 代码
11. ❌ 无 Zod 输入验证Controller 直接接收 `body: CreateExamInput`,未走 zod schema
12. ❌ 无测试
### 跨模块契约对齐待确认项(提请 coord 交叉审查)
| 待确认项 | 我方期望 | 对方模块 | 状态 |
| ---------------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------- |
| iam `getEffectivePermissions(userId)` 返回结构 | `{permissions, viewports, dataScope}` | iamai02 | ⚠️ 当前 teacher-bff 调 `/iam/viewports``/iam/me`,未定义此聚合 API 的 proto |
| iam `user.created` 事件 topic | `edu.identity.user.created` | iamai02 | ⚠️ 004 §7.2 定义,但 core-edu 未消费,需确认 iam 是否发布 |
| core-edu 端口 3004 | 不冲突 | 全局端口矩阵 | 待 coord 核对 |
| Kafka topic 命名 | `edu.exam.events` / `edu.homework.events` / `edu.grade.events` / `edu.class.events` | 004 §7.2 用 `edu.teaching.*` 前缀 | ⚠️ **不一致**004 文档用 `edu.teaching.exam.published`,代码用 `edu.exam.events`,需 coord 仲裁统一 |
| data-ana 消费 core-edu 事件 | 消费 `exam.created` / `homework.submitted` / `grade.recorded` | data-anaai06 | 待 ai06 确认消费契约 |
| msg 消费 core-edu 事件 | 消费 `exam.created` / `homework.assigned` / `grade.recorded` 触发通知 | msgai05 | 待 ai05 确认消费契约 |
---
## 下一步(阶段 2 入口)
待 coord 审核本确认书通过后ai03 进入阶段 2按 [ai-allocation.md §5 ai03 设计重点](./ai-allocation.md#ai03--教学场景域) 产出两份模块架构设计文档:
1. **teacher-bff 模块架构设计**GraphQL schemaQuery/Mutation 按场景域组织、DataLoader 批量去重、并行 gRPC 编排、聚合缓存 TTL、教师角色差异化视口推导
2. **core-edu 模块架构设计**classes 黄金模板对齐、考试生命周期状态机、Outbox 事件定义、成绩计算配置化、作业提交高并发Redis 锁 + 排队)、排课/考勤数据模型
阶段 2 设计需先解决上述 12 项差距与 6 项跨模块契约对齐。
---
**AI Agent**: ai03 (teacher-bff + core-edu)
**Coordinator**: coord-ai
**Branch**: 单仓库并行模式(直接 push main