fix: code compliance audit and fix across all services
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

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.
This commit is contained in:
SpecialX
2026-07-09 17:28:27 +08:00
parent b53a486c6e
commit 0a71b02e04
93 changed files with 5775 additions and 608 deletions

View File

@@ -0,0 +1,216 @@
# 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