# classes 对接契约 > 负责人:ai07 > 关联:[matrix.md](../matrix.md)、[classes.proto](../../../packages/shared-proto/proto/classes.proto)、[events.proto](../../../packages/shared-proto/proto/events.proto)、[02-architecture-design.md](../../../services/classes/docs/02-architecture-design.md) > 状态:黄金模板(P1 已实现),P3 合并入 core-edu --- ## §1 我提供什么(对外接口) ### 1.1 gRPC 接口(如有) | Service | RPC | 请求 | 响应 | 端口 | | ------------ | ----------- | ------------------ | ------------------- | ------------------------------- | | ClassService | CreateClass | CreateClassRequest | Class | 50053(P3 启用,core-edu 承载) | | ClassService | GetClass | GetClassRequest | Class | 50053 | | ClassService | ListClasses | ListClassesRequest | ListClassesResponse | 50053 | | ClassService | UpdateClass | UpdateClassRequest | Class | 50053 | | ClassService | DeleteClass | DeleteClassRequest | Empty | 50053 | > **注意**:classes 当前仅 REST(端口 3001),gRPC server 50053 在 P3 合并入 core-edu 后启用。proto 契约已就绪(classes.proto),由 core-edu 实现承载。 ### 1.2 HTTP 端点(如有) | Method | Path | 权限 | 说明 | | ------ | -------------- | ---------------- | ----------------------------- | | POST | `/classes` | `CLASSES_CREATE` | 创建班级 | | GET | `/classes` | `CLASSES_READ` | 列表(可选 `?gradeId=` 过滤) | | GET | `/classes/:id` | `CLASSES_READ` | 单条查询 | | PUT | `/classes/:id` | `CLASSES_UPDATE` | 更新 | | DELETE | `/classes/:id` | `CLASSES_DELETE` | 删除(先校验存在) | | GET | `/healthz` | 无 | liveness | | GET | `/readyz` | 无 | readiness(校验 DB) | | GET | `/metrics` | 无 | Prometheus 指标 | > **响应信封**:ActionState(`{success:true, data:T}` / `{success:false, error:{code,message,details?,traceId?}}`) ### 1.3 GraphQL schema(如 BFF) 不适用。classes 是业务服务,非 BFF。 ### 1.4 Kafka 事件发布(如有) | Topic | Event | 消费方 | 阶段 | | --------------------------- | --------------------------------- | ------------------------------- | ------------------- | | `edu.org.class.created` | ClassEvent(action: created) | data-ana(建宽表行) | P3(core-edu 承载) | | `edu.org.class.updated` | ClassEvent(action: updated) | data-ana、msg(班主任变更通知) | P3 | | `edu.org.class.deleted` | ClassEvent(action: deleted) | data-ana、core-edu(关联检查) | P3 | | `edu.org.class.transferred` | ClassEvent(action: transferred) | msg(通知新/旧班主任) | P3 | > **事件 message**:`events.proto` 的 `ClassEvent`(event_id / aggregate_id / event_type / occurred_at / class_id / name / action / metadata) > **发布方式**:Outbox 模式(P3 补齐 `shared/outbox/`),保证事务与事件最终一致 ### 1.5 错误码前缀 `CLASSES_`(004 §11.4 确认保留,P3 合并入 core-edu 后保留历史遗留前缀) | 错误码 | HTTP | 触发条件 | | --------------------------- | ---- | ----------------------------- | | `CLASSES_VALIDATION_ERROR` | 400 | Zod 校验失败 / 空 update body | | `CLASSES_NOT_FOUND` | 404 | 资源不存在 | | `CLASSES_PERMISSION_DENIED` | 403 | PermissionGuard 校验失败 | | `CLASSES_CONFLICT` | 409 | 并发冲突(预留) | | `CLASSES_BUSINESS_ERROR` | 422 | 业务规则违反(预留) | | `CLASSES_DATABASE_ERROR` | 500 | DB 操作失败 | | `CLASSES_INTERNAL_ERROR` | 500 | 未预期异常 | --- ## §2 我消费什么(依赖上游) ### 2.1 gRPC 调用(同步) 当前无。P3 合并入 core-edu 后,可能调用 iam 的 `BatchGetUsers`(班主任信息批量查询)。 ### 2.2 Kafka 事件订阅(异步) | Topic | Event | 消费动作 | 阶段 | | --------------------------- | ---------------------------- | -------------------------------------------- | ---- | | `edu.identity.user.deleted` | UserEvent(action: deleted) | 若 deleted user 是班主任,置空 headTeacherId | P3 | ### 2.3 HTTP 调用(如有) 无。classes 是基础数据源,不反向调用其他服务。 --- ## §3 就绪信号 ### 3.1 我依赖的上游就绪标志 - [ ] MySQL classes_db 可用(已就绪,P1) - [ ] api-gateway `/classes/*` 路由已注册(已就绪,P1) - [ ] P3:iam `BatchGetUsers` gRPC 可用(班主任信息查询) - [ ] P3:Kafka `edu.identity.user.deleted` topic 可消费 ### 3.2 我的就绪标志(供下游消费) - [x] classes REST API 5 端点可用(P1 已实现) - [x] `/healthz` + `/readyz` 可用(P1 已实现) - [x] `/metrics` 可用(P1 已实现) - [ ] P3:gRPC 50053 启用(由 core-edu 承载,`ClassService` 5 RPC 可调用) - [ ] P3:`edu.org.class.created/updated/deleted/transferred` topic 可发布 - [ ] P3:Outbox 模式落地(`shared/outbox/` 目录补齐) --- ## §4 Mock 策略 ### 4.1 我提供的 mock classes 是 P1 黄金模板,REST API 已实现,**下游无需 mock,可直接调用真实服务**。 但为 P3 gRPC 迁移期间兼容,提供以下 mock 供下游在 gRPC 未启用时使用: - **REST mock**(已可用):直接调用 `http://classes:3001/classes/*`,返回真实数据 - **gRPC mock**(P3 过渡期):grpc-mock 拦截 50053,ClassService 5 RPC 返回固定 Class 数据 - **Kafka mock**(P3 过渡期):classes 事件未发布前,下游订阅方使用本地 stub(固定 ClassEvent JSON) ### 4.2 我消费的 mock - P3 期间 iam `BatchGetUsers` 未就绪时,使用 grpc-mock 返回固定用户信息(班主任姓名) - P3 期间 `edu.identity.user.deleted` topic 未就绪时,使用本地 Kafka mock consumer stub