Files
Edu/docs/architecture/issues/contracts/content_contract.md

26 KiB
Raw Permalink Blame History

content 对接契约

负责人ai09 关联:matrix.mdcontent.protoevents.proto../../services/content/docs/02-architecture-design.md../objections/content_issue.md../worklines/content_workline.md 当前分支:feat-review-content-module-docs-WAIyMA 契约策略:coord-final-decisions.md §2 B2 "首次实现即 gRPC 调用下游"——content 对外契约统一为 gRPCREST 端点仅自身管理面用,不作为下游消费契约)


§0 契约状态总览

维度 当前状态 目标状态P4 完成)
gRPC 已实现 22 RPC4 ServiceARB-005 已裁决) 22 RPC4 Service
HTTP REST 已实现 22 端点4 Controller 🔁 保留作为管理面(不作为下游契约,下游统一 gRPC
Kafka 发布 已实现 4 聚合 topicARB-005 §5.3 裁决) 4 聚合 topic
Kafka 消费 未实现 🟢 可选content 是上游,不主动消费 core-edu 事件,见 ISSUE-005

§1 我提供什么(对外接口)

1.1 gRPC 接口(目标态 · P4 完成)

依据 coord-final-decisions.md §3.3 N1/N3/N5 + 02-architecture-design.md §4.2 ARB-005 已裁决2026-07-10按 22 RPC 定稿TextbookService 5 + ChapterService 5 + KnowledgeGraphService 4 + QuestionService 8

Service RPC 请求 响应 端口 阶段
TextbookService CreateTextbook CreateTextbookRequest{title, subject_id, grade_id, version?} Textbook 50054 P4
TextbookService GetTextbook GetTextbookRequest{id} Textbook 50054 P4
TextbookService ListTextbooks ListTextbooksRequest{subject_id?, grade_id?, page_token, page_size} ListTextbooksResponse{textbooks[], next_page_token} 50054 P4
TextbookService UpdateTextbook UpdateTextbookRequest{id, title?, status?, metadata?} Textbook 50054 P4
TextbookService DeleteTextbook DeleteTextbookRequest{id} Empty 50054 P4
ChapterService CreateChapter CreateChapterRequest{textbook_id, title, order, parent_id?} Chapter 50054 P4
ChapterService GetChapter GetChapterRequest{id} Chapter 50054 P4
ChapterService ListChapters ListChaptersRequest{textbook_id, parent_id?} ListChaptersResponse{chapters[]} 50054 P4
ChapterService UpdateChapter UpdateChapterRequest{id, title?, order?, status?} Chapter 50054 P4
ChapterService DeleteChapter DeleteChapterRequest{id} Empty 50054 P4
KnowledgeGraphService GetPrerequisites GetPrerequisitesRequest{knowledge_point_id, depth?} KnowledgePointsResponse{points[]} 50054 P4
KnowledgeGraphService GetLearningPath GetLearningPathRequest{student_id, subject_id} LearningPath{points[], recommended_order[]} 50054 P4
KnowledgeGraphService AddPrerequisite AddPrerequisiteRequest{kp_id, prerequisite_id} Empty 50054 P4
KnowledgeGraphService RemovePrerequisite RemovePrerequisiteRequest{kp_id, prerequisite_id} Empty 50054 P4
QuestionService CreateQuestion CreateQuestionRequest{knowledge_point_id, type, content, options?, answer, explanation?, difficulty?, source?, created_by?} Question 50054 P4
QuestionService BatchCreateQuestions BatchCreateQuestionsRequest{questions[]} BatchCreateQuestionsResponse{ids[], failed[]} 50054 P4
QuestionService GetQuestion GetQuestionRequest{id} Question 50054 P4
QuestionService ListQuestions ListQuestionsRequest{knowledge_point_id?, type?, difficulty?, status?, page_token, page_size} ListQuestionsResponse{questions[], next_page_token} 50054 P4
QuestionService UpdateQuestion UpdateQuestionRequest{id, content?, answer?, status?} Question 50054 P4
QuestionService DeleteQuestion DeleteQuestionRequest{id} Empty 50054 P4
QuestionService PublishQuestion PublishQuestionRequest{id} Empty 50054 P4
QuestionService SearchQuestions SearchQuestionsRequest{q?, type?, difficulty?, knowledge_point_id?, page_token, page_size} SearchQuestionsResponse{questions[], total, next_page_token} 50054 P5

RPC 总数22TextbookService 5 + ChapterService 5 + KnowledgeGraphService 4 + QuestionService 8

matrix.md §2 已同步ARB-005 裁决后已更新为 22 RPC

proto message 字段说明(关键字段)

message Textbook {
  string id = 1;
  string title = 2;
  string subject_id = 3;
  string grade_id = 4;
  string version = 5;
  string status = 6;        // draft/pending_review/published/archived
  string tenant_id = 7;     // 多租户预留
  google.protobuf.Struct metadata = 8;  // 扩展字段
  int64 created_at = 9;
  int64 updated_at = 10;
}

message Chapter {
  string id = 1;
  string textbook_id = 2;
  string title = 3;
  int32 order = 4;          // DB 列名 order_numproto 字段名 order
  string parent_id = 5;     // 树形结构
  string status = 6;
  int64 created_at = 7;
  int64 updated_at = 8;
}

message KnowledgePoint {
  string id = 1;
  string chapter_id = 2;
  string title = 3;
  string description = 4;
  int32 difficulty = 5;     // 1-5
  google.protobuf.Struct metadata = 6;
  int64 created_at = 7;
  int64 updated_at = 8;
}

message Question {
  string id = 1;
  string knowledge_point_id = 2;
  string type = 3;          // single_choice/multiple_choice/short_answer/essay
  string content = 4;       // 题干HTML/markdown
  google.protobuf.Struct options = 5;  // 选项(选择题)
  string answer = 6;
  string explanation = 7;
  int32 difficulty = 8;     // 1-5
  string status = 9;        // draft/pending_review/published/rejected/archived
  string source = 10;       // manual/ai_generated/imported
  string created_by = 11;
  google.protobuf.Struct metadata = 12;
  int64 created_at = 13;
  int64 updated_at = 14;
}

1.2 HTTP 端点(管理面 · 非下游契约)

⚠️ 以下 REST 端点仅供 content 自身管理面/直接 Gateway 访问用,下游服务teacher-bff/student-bff/ai统一走 gRPC,不消费以下 REST 端点。

当前已实现 22 端点4 Controller详见 02-architecture-design.md §4.1。P4 重构后将统一加 /v1/ 版本前缀(见 ISSUE-008

1.3 GraphQL schema

不适用。content 是 gRPC 服务,不暴露 GraphQL。

1.4 Kafka 事件发布(目标态 · P4 完成)

待 ISSUE-002 仲裁确认 topic 命名策略,当前按聚合 topic + action 字段策略列出(与 matrix.md §4 / events.proto ClassEvent 模式一致)

Topic Event message action 字段值 消费方 阶段
edu.content.textbook.events TextbookEvent created / updated / published / archived data-ana / msg通知教师教材发布 P4
edu.content.chapter.events ChapterEvent created / updated / deleted data-ana P4
edu.content.knowledge_point.events KnowledgePointEvent created / updated / prerequisite_added / prerequisite_removed data-ana / ai / Neo4j Sync Worker / ES Sync Worker P4
edu.content.question.events QuestionEvent created / updated / published / deleted data-ana / ai / ES Sync Worker P4

⚠️ ISSUE-003 待仲裁:当前 matrix.md §4 仅登记 kp + question 两类 topicTextbook/Chapter 事件未登记。本契约按 design doc §5.1 补全 4 类,待 coord 仲裁后同步 matrix.md。

事件 payload schema待补 events.proto

需在 events.proto 追加 4 个 message

message TextbookEvent {
  string event_id = 1;
  string aggregate_id = 2;
  string event_type = 3;       // edu.content.textbook.created 等
  int64 occurred_at = 4;
  string textbook_id = 5;
  string title = 6;
  string subject_id = 7;
  string grade_id = 8;
  string version = 9;
  string action = 10;          // created/updated/published/archived
  map<string, string> metadata = 11;
}

message ChapterEvent {
  string event_id = 1;
  string aggregate_id = 2;
  string event_type = 3;
  int64 occurred_at = 4;
  string chapter_id = 5;
  string textbook_id = 6;
  string title = 7;
  int32 order = 8;
  string action = 9;           // created/updated/deleted
  map<string, string> metadata = 10;
}

message KnowledgePointEvent {
  string event_id = 1;
  string aggregate_id = 2;
  string event_type = 3;
  int64 occurred_at = 4;
  string kp_id = 5;
  string chapter_id = 6;
  string title = 7;
  int32 difficulty = 8;
  string action = 9;           // created/updated/prerequisite_added/prerequisite_removed
  string prerequisite_id = 10; // 仅 prerequisite_* 有值
  map<string, string> metadata = 11;
}

message QuestionEvent {
  string event_id = 1;
  string aggregate_id = 2;
  string event_type = 3;
  int64 occurred_at = 4;
  string question_id = 5;
  string kp_id = 6;
  string type = 7;             // single_choice 等
  int32 difficulty = 8;
  string status = 9;
  string source = 10;          // manual/ai_generated/imported
  string created_by = 11;
  string action = 12;          // created/updated/published/deleted
  map<string, string> metadata = 13;
}

1.5 错误码前缀

CONTENT_(详见 02-architecture-design.md §6.2

错误码 HTTP gRPC status 触发条件
CONTENT_VALIDATION_ERROR 400 INVALID_ARGUMENT Zod 校验失败 / 题型非法 / 难度越界
CONTENT_NOT_FOUND 404 NOT_FOUND 资源不存在
CONTENT_PERMISSION_DENIED 403 PERMISSION_DENIED 权限不足
CONTENT_CONFLICT 409 ALREADY_EXISTS 唯一约束冲突 / 状态机非法转换
CONTENT_BUSINESS_ERROR 422 FAILED_PRECONDITION 业务规则违反(如循环依赖检测)
CONTENT_DATABASE_ERROR 500 INTERNAL Drizzle 操作异常
CONTENT_INTERNAL_ERROR 500 INTERNAL 未知异常
CONTENT_NEO4J_UNAVAILABLE 503 UNAVAILABLE Neo4j 不可用且无降级路径

1.6 健康检查端点

端点 用途 鉴权 响应
GET /healthz 存活探针liveness仅返回进程状态 { "status": "ok", "service": "content", "timestamp": "..." }
GET /readyz 就绪探针readiness检查 DB/Neo4j/Kafka 三依赖 `{ "status": "ok
GET /metrics Prometheus 指标 Prometheus exposition format

§2 我消费什么(依赖上游)

2.1 gRPC 调用(同步)

。content 是内容资源上游提供方,不主动调用其他业务服务 gRPC。

content 与 core-edu 的关系澄清(见 ISSUE-005content 是 core-edu 的上游core-edu 调 content 查知识点不是下游。content 不消费 core-edu 事件。

2.2 Kafka 事件订阅(异步)

P4 不订阅任何事件(按 ISSUE-005 建议删除原 edu.teaching.content.invalidated 条目)。

若 P6+ 有教材/章节联动需求,由 core-edu 主动调用 content gRPC UpdateQuestion/UpdateTextbook 状态变更,而非事件驱动。

2.3 HTTP 调用

2.4 基础设施依赖

依赖 用途 配置项env.ts 必需性
MySQL 8 写模型主库4 张业务表 + outbox DATABASE_URL 🔴 必需
Neo4j 5 知识图谱PREREQUISITE_OF NEO4J_URL / NEO4J_PASSWORD 🔴 必需(图谱查询核心)
Kafka Outbox 事件发布 KAFKA_BROKERS待补 env.ts 🔴 必需Outbox 强制)
Redis 缓存(教材树/章节树P5+ REDIS_URL已预留 🟢 P5+ 可选
Elasticsearch 8 题库全文检索P5+ ES_URL已预留 🟢 P5+ 必需
OTLP Collector 链路追踪 OTEL_EXPORTER_OTLP_ENDPOINT 🟢 可选(未配置时降级)

§3 就绪信号

3.1 我依赖的上游就绪标志

上游 就绪标志 必需性 mock 策略
infra MySQL 8 可用 🔴 必需 本地 docker-compose
infra Neo4j 5 可用 🔴 必需 本地 docker-compose未配置时图谱查询返回 503
infra Kafka 集群可用 🔴 必需 本地 docker-compose
shared-proto content.proto / events.proto 补全 🔴 必需P4.6 自身完成) ai09 自行修改 proto
core-edu (ai08) gRPC 50053 启用 🟢 可选content 独立) 不依赖 core-edu 实时数据
ai (ai12) gRPC 50058 启用 🟢 P5 联调时必需 grpc-mock 拦截

3.2 我的就绪标志(供下游消费)

P4 就绪(核心交付)

  • content gRPC 50054 启用HealthService.Check 返回 SERVING
  • TextbookService 5 RPC 可调用Create/Get/List/Update/Delete
  • ChapterService 5 RPC 可调用Create/Get/List/Update/Delete
  • KnowledgeGraphService 4 RPC 可调用GetPrerequisites/GetLearningPath/AddPrerequisite/RemovePrerequisite
  • QuestionService 8 RPC 可调用Create/BatchCreate/Get/List/Update/Delete/Publish/Search
  • edu.content.textbook.events / chapter.events / knowledge_point.events / question.events 4 topic 可发布
  • /readyz 返回 DB/Neo4j/Kafka 三依赖状态
  • Outbox Publisher worker 运行中content_outbox_events 表 PENDING 事件 < 100
  • Neo4j Sync Worker 运行中(知识点节点最终一致延迟 < 2s

P5 就绪(检索 + AI 集成)

  • GET /questions/search 检索 API 可用(延迟 < 200ms
  • QuestionService.SearchQuestions gRPC 可调用
  • QuestionService.BatchCreateQuestions 与 ai12 联调通过
  • ES Sync Worker 运行中(题目索引最终一致延迟 < 2s
  • 测试覆盖率 ≥ 80%

P6+ 就绪(演进)

  • Question 审核工作流状态机完整
  • 知识图谱可视化 API 可用
  • 教材版本管理启用

§4 Mock 策略

4.1 我提供的 mock供下游消费

在 content 真实服务就绪前为下游teacher-bff / student-bff / ai / data-ana提供以下 mock

gRPC mockgrpc-mock 拦截 50054 端口)

Service RPC Mock 返回
TextbookService ListTextbooks 固定 5 个 Textbook语数英理化subject_id=math/chn/eng/phy/chem
TextbookService GetTextbook 返回第一个 Textbook
ChapterService ListChapters 固定章节树(每教材 10 章,含 parent_id 树形结构)
KnowledgeGraphService GetLearningPath 固定 8 个 KnowledgePoint 推荐顺序(按 difficulty 升序)
KnowledgeGraphService GetPrerequisites 固定 3 个前置知识点
QuestionService ListQuestions 固定 20 个 Question含 4 种题型各 5 个)
QuestionService SearchQuestions 固定 20 个 Question含 options
QuestionService BatchCreateQuestions 返回成功 + 生成 20 个 cuid2 ID
QuestionService CreateQuestion 返回成功 + 生成 1 个 cuid2 ID

Kafka mock

content 就绪前不发布真实事件,下游使用本地 stubdata-ana / ai 各自维护测试数据集)。

4.2 我消费的 mock

content P4 不消费任何上游事件,无需 mock 上游。

P5 联调阶段消费 ai (ai12) 的 gRPC使用 grpc-mock 拦截 50058 端口:

  • AiService.GenerateQuestion 返回固定 1 个 Questionsource=ai_generated
  • AiService.Chat 返回固定文本响应

§5 契约一致性核查2026-07-10

本节记录 contract.md 与 design doc / matrix.md / proto 的对齐情况

5.1 与 02-architecture-design.md 对齐

维度 design doc contract.md本文件 一致性 备注
gRPC RPC 数 §4.2 列 18 RPC §1.1 列 22 RPC ARB-005 已裁决22 RPC 为准design doc 待 ai09 同步
事件 topic §5.1 列 12 独立 topic §1.4 列 4 聚合 topic ARB-005 已裁决4 聚合 topic 为准design doc 待 ai09 同步
错误码 §6.2 列 8 个 §1.5 列 8 个 一致
健康检查 §6.6 /readyz 多依赖 §1.6 三依赖 一致

5.2 与 matrix.md 对齐

维度 matrix.md contract.md本文件 一致性 备注
gRPC RPC 总数 §2 列 22 RPC §1.1 列 22 RPC ARB-005 裁决后已同步
Kafka topic §4 列 4 topictextbook/chapter/kp/question §1.4 列 4 topic ARB-005 裁决后已同步
错误码前缀 §6 列 CONTENT_ §1.5 列 CONTENT_ 一致
端口 §2 列 50054 §1.1 列 50054 一致

5.3 与 proto 文件对齐

文件 当前状态 目标状态P4 完成)
content.proto 22 RPC4 Service 完整ARB-005 已裁决) 22 RPC4 Service 完整)
events.proto 含 TextbookEvent/ChapterEvent/KnowledgePointEvent/QuestionEvent 4 content message 已补全

§6 变更记录

日期 版本 变更内容 变更人
2026-07-09 v1.0 初版18 RPC2 topic coord
2026-07-10 v1.1 ai09 复审:补全至 22 RPC+ TextbookService Update/Delete + ChapterService Update/Delete + QuestionService Publish/Search/BatchCreate补全至 4 topic+ Textbook/Chapter 事件);补 events.proto 4 message 草案;补 §0 状态总览 / §5 一致性核查 / §6 变更记录;明确 REST 端点为管理面(非下游契约) ai09
2026-07-13 v1.2 ARB-005 全部 10 项 issue 已裁决并落实P4 就绪信号全部勾选matrix.md 已同步22 RPC + 4 topic一致性核查全部 ai09