docs: ai 协作文档体系重构与多 ai 仲裁结果落地

1.AI 协作文档体系重构(objections/worklines/contracts+matrix.md)

2.coord 仲裁文档(final-decisions/cross-review/final-rulings/orchestration)

3.各服务 01/02 文档补全

4.共享包初始化(shared-ts/shared-go/hooks/ui-components/ui-tokens)

5.Proto 契约补全

6.004 架构影响地图更新

7.端口分配表

8.设计规格文档
This commit is contained in:
SpecialX
2026-07-10 12:58:22 +08:00
parent 2a2a56f541
commit faaaf29f67
120 changed files with 23201 additions and 2 deletions

View File

@@ -0,0 +1,198 @@
# 模块理解确认书 — classes
> AIai07TS / 教学组织 · 黄金模板)
> 阶段:阶段 1 交付物
> 日期2026-07-10
> 关联:[004 架构影响地图](../../../docs/architecture/004_architecture_impact_map.md)、[AI 分配方案](../../../docs/architecture/ai-allocation.md)、[pending-features P1](../../../docs/architecture/roadmap/pending-features.md)、[项目规则](../../../.trae/rules/project_rules.md)
>
> **本确认书定位**classes 是 Edu 微服务的 **黄金模板**ai-allocation.md §3.4),是其余 8 个 TS 服务的对照基准。本确认书既是对 classes 现状的审计,也是为其他 AI 提供的"读这一份即可理解黄金模板全貌"的入口。
---
## 1. 我在架构中的位置
- **层级**L5 业务微服务层004 §3.1 六层架构)
- **业务领域****D2 教学组织领域**004 §1.1b承载班级Class聚合根
- **上游(谁调用我)**
- `api-gateway`Go/GinHTTP 反向代理 `/api/v1/classes/*``http://classes:3001/classes/*`Gateway 已注册 classes 路由块,含精确路径 + 通配路径)
- `teacher-bff`NestJSP2 起通过 GraphQL 聚合调用 classes 班级列表(教师仪表盘)
- 未来:`student-bff``parent-bff`(同样走 BFF 聚合)
- **下游(我调用谁)**
- `MySQL`(独占库 `classes_db`,连接串 `DATABASE_URL`mysql2 连接池 + Drizzle ORM
- `Redis`(依赖已声明 `ioredis`env 已留 `REDIS_URL` 占位当前未启用P3 合并入 core-edu 后启用班级列表缓存)
- `Kafka`(依赖已声明 `kafkajs`当前未启用P3 起 Outbox 事件发布 `edu.org.class.created` 等)
- **通信方式**
- 入口:**HTTP/REST**(当前实现,端口 3001
- 出口MySQLDrizzle ORM
- 演进proto 已定义 `ClassService`5 个 RPCP3 起 core-edu 合并 classes 后启用 gRPC server 50053
- **不持有跨服务状态**:无本地内存缓存,无 WebSocket 连接
### 1.1 黄金模板职责
classes 除了承载 D2 教学组织领域(班级 CRUD业务外**首要职责是作为黄金模板**
| 黄金模板职责 | 说明 |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| 横切关注点基准 | 错误处理 / 可观测性 / 安全 / 契约 / 测试 / 文档 / 配置 / Dockerfile 全部落地,其他 TS 服务对齐 |
| 目录结构基准 | `src/{main,app.module,config,middleware,<domain>,shared}` 标准结构 |
| 对照 checklist 源 | 产出黄金模板对照 checklist见 [02 架构设计 §10](./02-architecture-design.md#10-黄金模板对照-checklist供其他-ts-服务自检))供 ai01-ai10 自检 |
| 模式回写 | 各阶段新模式实现后回写本模板Outbox 模式 P3 / 长连接 P5 / CDC P4 |
---
## 2. 我的限界上下文
### 2.1 我负责的聚合 / 实体
| 聚合根 | 实体 / 值对象 | 当前表 | 职责 |
| ----------------- | ----------------------------------------- | --------- | --------------------------------- |
| **Class**(班级) | name、gradeId、headTeacherId、description | `classes` | 班级 CRUD、按年级过滤、班主任归属 |
> **演进**P3 合并入 core-edu 后classes 表与 `subjects`(学科)、`enrollment`(选课)同属 D2 教学组织域,由 core-edu 统一承载(见 004 §1.3 CICD→Edu 映射)。
### 2.2 业务领域归属
- **D2 教学组织领域**004 §1.1bclasses 独占此领域当前P3 起与 subjects、enrollment 共同组成 D2
- 上游依赖:无业务领域依赖(教学组织是基础数据,不依赖其他业务领域)
- 下游被依赖:
- core-edu D3 教学核心域(考试/作业按班级归属)
- data-ana D6 智能洞察域(班级维度统计聚合)
- msg D5 沟通通知域(班级群组广播)
### 2.3 我不负责什么(边界外)
- ❌ 学科subjects→ core-eduP3 新增D2 教学组织)
- ❌ 选课 / 学生分班enrollment→ core-eduP3 新增)
- ❌ 考试 / 作业 / 成绩 → core-eduD3 教学核心)
- ❌ 教材 / 知识点 / 题库 → contentD4 内容资源)
- ❌ 站内信 / 通知投递 → msgD5 沟通通知)
- ❌ 学情分析 / 掌握度计算 → data-anaD6 智能洞察)
- ❌ 用户 / 角色 / 权限管理 → iamD1 身份认证)
- ❌ JWT 校验 → api-gatewayclasses 仅读 `x-user-id` / `x-user-roles` 头)
- ❌ 年级grade数据 → 当前 classes 仅持有 `gradeId` 外键引用,年级实体归属待 core-edu P3 定义(当前由前端/管理端维护)
---
## 3. 我与外部的契约
### 3.1 我消费的 proto message从 shared-proto
- 当前**不消费**任何外部 protoclasses 是基础数据源,不反向依赖业务服务)
- 未来 P3 起core-edu 合并 classes 后,消费 `iam.proto``BatchGetUsers`(班主任信息批量查询)
### 3.2 我暴露的契约
#### 当前 REST API已实现见 [classes.controller.ts](../src/classes/classes.controller.ts)
| Method | Path | 权限 | 请求体 / 参数 | 响应 | 说明 |
| ------ | -------------- | ---------------- | -------------------------- | ---------------------------------- | ---------------------------------- |
| POST | `/classes` | `CLASSES_CREATE` | `{name, gradeId, ...}` | `{success, data: ClassResponse}` | 创建班级 |
| GET | `/classes` | `CLASSES_READ` | `?gradeId=<uuid>`(可选) | `{success, data: ClassResponse[]}` | 列表,支持按年级过滤 |
| GET | `/classes/:id` | `CLASSES_READ` | path: `id` | `{success, data: ClassResponse}` | 单条查询 |
| PUT | `/classes/:id` | `CLASSES_UPDATE` | path:`id` + `{name?, ...}` | `{success, data: ClassResponse}` | 更新(空 body 抛 ValidationError |
| DELETE | `/classes/:id` | `CLASSES_DELETE` | path: `id` | `{success: true}` | 删除(先校验存在) |
> **响应信封**:遵循 ActionState004 §11.5),成功 `{success:true, data:T}`,失败 `{success:false, error:{code,message,details?,traceId?}}`。
#### 健康检查(见 [health.controller.ts](../src/shared/health/health.controller.ts)
| Method | Path | 鉴权 | 用途 |
| ------ | ---------- | ---- | ------------------------------------------------------------------- |
| GET | `/healthz` | 无 | liveness进程存活 |
| GET | `/readyz` | 无 | readiness校验 DB `SELECT 1`,失败 503 |
| GET | `/metrics` | 无 | Prometheus 指标抓取(见 [main.ts](../src/main.ts) 第 23-26 行注册) |
#### Proto 契约(见 [classes.proto](../../../packages/shared-proto/proto/classes.proto)
```protobuf
package next_edu_cloud.classes.v1;
service ClassService {
rpc CreateClass(CreateClassRequest) returns (Class);
rpc GetClass(GetClassRequest) returns (Class);
rpc ListClasses(ListClassesRequest) returns (ListClassesResponse);
rpc UpdateClass(UpdateClassRequest) returns (Class);
rpc DeleteClass(DeleteClassRequest) returns (Empty);
}
```
> **proto 完备性**5 个 RPC 与 REST 端点一一对应,已包含分页字段(`page_size` / `page_token`REST 实现尚未落地分页。P3 合并后由 core-edu 启用 gRPC server 50053004 §16.7.3 #1
#### 我发布的领域事件当前未实现P3 由 core-edu 接管)
| 事件 | 触发时机 | Topic遵循 004 §7.2 | 消费者 |
| ------------------ | ------------ | --------------------------- | -------------------------------- |
| `ClassCreated` | 班级创建成功 | `edu.org.class.created` | data-ana建班级维度宽表行 |
| `ClassUpdated` | 班级信息变更 | `edu.org.class.updated` | data-ana、msg班主任变更通知 |
| `ClassDeleted` | 班级删除 | `edu.org.class.deleted` | data-ana、core-edu关联检查 |
| `ClassTransferred` | 班主任变更 | `edu.org.class.transferred` | msg通知新/旧班主任、data-ana |
> **事件 message 契约**`events.proto` 已定义 `ClassEvent`event_id / aggregate_id / event_type / occurred_at / class_id / name / action / metadata见 [events.proto](../../../packages/shared-proto/proto/events.proto) 第 15-24 行。Topic 命名遵循 004 §7.2 `edu.<domain>.<aggregate>.<action>` 强制格式。
---
## 4. 我的技术栈
| 维度 | 选型 | 说明 |
| -------- | --------------------------------- | --------------------------------------------------------------- |
| 语言 | TypeScript 5.6+ | ESM 模式(`"type": "module"`),相对 import 用 `.js` 后缀 |
| 框架 | NestJS 10 | 装饰器 + DI适合 DDD 分层 |
| ORM | Drizzle ORM 0.31 | 参数化查询,类型安全,替代 TypeORM |
| 数据库 | MySQL 8mysql2 驱动) | 连接池 `connectionLimit: 10` |
| 校验 | Zod 3.23 | 输入 DTO 校验controller 层 `schema.parse(body)` |
| 日志 | pino 9 + pino-prettydev | 结构化 JSON`base:{service,version}` |
| 指标 | prom-client 15 | 自定义 Counter/Histogram + 默认进程指标,`/metrics` 端点 |
| 链路 | OpenTelemetry SDK + OTLP exporter | auto-instrumentationsserviceName=`classes` |
| 测试 | Vitest 2.1 + @vitest/coverage-v8 | 单元测试mock repository阈值 60%(待提升至 80% |
| 容器 | node:20-alpine多阶段构建 | builder + runtime 两阶段(项目规则要求 node:22-alpine待对齐 |
| ID 生成 | uuid v4 | 当前实现project_rules 要求 cuid2黄金模板待迁移 |
| 预留依赖 | ioredis、kafkajs | 已声明但未使用,为 P3 Redis 缓存 + Kafka 事件预留 |
---
## 5. 我的阶段归属
- **阶段****P1 地基阶段**(已实现,黄金模板)
- **当前阶段目标**pending-features P1classes 域 CRUD 端到端跑通 + 全横切关注点落地 + 30 分钟可复制新服务
- **依赖上游阶段产出**P1 是地基classes 是最早交付的服务)
- **未来演进路径**
- P3合并入 core-eduai08 负责classes 表 + subjects + enrollment 共同组成 D2 教学组织域;启用 gRPC server 50053
- P3补齐 Outbox 事件发布能力(`shared/outbox/` 目录)
- P3启用 Redis 班级列表缓存TTL 5 分钟,事件驱动失效,见 004 §6.3
- P3落地 DataScope 6 级 WHERE 注入(见 004 §5.3,当前 PermissionGuard 仅做角色级校验)
---
## 6. 我需要对齐的黄金模板项(对照 classes 自身——作为基准的自我审计)
> classes 是黄金模板本身,本节为**自我审计**,确认各项已落地,供其他 TS 服务对照。
| 检查项 | 状态 | 证据 | 待整改 |
| ------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------ | ---------- |
| 权限装饰器 `@RequirePermission` | ✅ | [permission.guard.ts](../src/middleware/permission.guard.ts) + controller 全部方法装饰 | — |
| 错误码前缀 `CLASSES_` | ✅ | [application-error.ts](../src/shared/errors/application-error.ts) 7 类错误码均带前缀 | — |
| loggerpino | ✅ | [logger.ts](../src/shared/observability/logger.ts) | — |
| metricsprom-client | ✅ | [metrics.ts](../src/shared/observability/metrics.ts) + `/metrics` 端点 | — |
| tracerOTel | ⚠️ | [tracer.ts](../src/shared/observability/tracer.ts) 第 20 行仍用 `console.log`,需改 `logger.info` | P1 整改 |
| `/healthz` | ✅ | [health.controller.ts](../src/shared/health/health.controller.ts) liveness | — |
| `/readyz` | ✅ | readiness 校验 DB `SELECT 1`,失败 503 | — |
| 优雅关闭SIGTERM | ✅ | [main.ts](../src/main.ts) 第 31-34 行 + [lifecycle.service.ts](../src/shared/lifecycle/lifecycle.service.ts) | — |
| Zod 输入验证 | ✅ | [classes.dto.ts](../src/classes/classes.dto.ts) + controller `schema.parse(body)` | — |
| GlobalErrorFilter | ✅ | [global-error.filter.ts](../src/shared/errors/global-error.filter.ts) 捕获 ZodError + ApplicationError | — |
| Dockerfile 多阶段 | ✅ | [Dockerfile](../Dockerfile) builder + runtime 两阶段 | node:20→22 |
| 测试覆盖率 | ⚠️ | [vitest.config.ts](../vitest.config.ts) 阈值 60%,需提升至 80% | P1 整改 |
| `shared/outbox/` 目录 | ❌ | 缺失,需补齐事件发布能力 | P3 补齐 |
| `typeorm` 冗余依赖 | ❌ | [package.json](../package.json) 第 33 行仍声明 typeorm已用 Drizzle需移除 | P1 整改 |
| `@Req()``@Query()` | ❌ | [classes.controller.ts](../src/classes/classes.controller.ts) 第 49-53 行 list 方法仍用 `@Req()` | P1 整改 |
| ID 生成 cuid2 | ❌ | [classes.service.ts](../src/classes/classes.service.ts) 第 1 行用 uuid v4 | P3 迁移 |
> **整改项汇总**4 项 P1 立即整改tracer console.log / 测试覆盖率 / typeorm 移除 / @Req 替换)+ 2 项 P3 演进outbox / cuid2详见 [02 架构设计 §11 整改清单](./02-architecture-design.md#11-整改清单与里程碑)。
---
## 7. 待 coord 仲裁 / 提请事项
| # | 议题 | 我的倾向 | 影响 |
| --- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------- | ------------------------------------------- |
| 1 | classes 在 P3 合并入 core-edu 后,黄金模板源码是否保留独立目录 `services/classes/` | 保留作为只读对照基准core-edu 复制其结构) | 影响 ai08 合并策略与黄金模板 checklist 归属 |
| 2 | `node:20-alpine``node:22-alpine` 升级是否在 P1 立即做? | 立即做project_rules §15.8 镜像预拉清单已是 node:22-alpine | 影响所有 TS 服务 Dockerfile 基准 |
| 3 | cuid2 迁移时机P1 黄金模板立即迁移,还是 P3 合并时统一迁移? | P1 立即迁移(黄金模板应先行,避免 ai08 继承 uuid 遗留) | 影响 classes 表主键、proto message 字段类型 |