Files
Edu/services/content/docs/nextstep.md
SpecialX 99580fa13a feat(content): docker 本地测试通过 + P5 ES 集成 + P6+ 审核工作流/可视化/可观测性
P5 ES 集成:
- config/elasticsearch.ts: 惰性初始化 + ik_max_word→standard 回退
- shared/sync/es-sync.worker.ts: Kafka 消费 question 事件并索引 ES
- questions search API: ES 优先, MySQL LIKE 降级
- ensureQuestionIndex() 幂等创建, IK 不可用回退 standard
- main.ts: 启动 ensureQuestionIndex + esSyncWorker 生命周期管理

P6+ 审核工作流/可视化/可观测性:
- Question 状态机: draft→pending_review→published→archived
- 非法转换拦截
- 知识图谱可视化 API: Neo4j 优先 + MySQL 降级
- Cypher 返回标量避免 Node 包装对象问题
- 教材版本管理: GET /textbooks/versions + archive
- 5 个 Prometheus 指标 + /readyz Outbox 积压检查

Docker 本地测试 (8 类全通过):
- healthz/readyz (5 依赖 ok)
- REST CRUD (textbook/chapter/kp/question)
- ES 全文检索命中
- 审核工作流状态机 (合法/非法转换)
- Outbox 事件驱动 (8 事件全 published)
- Neo4j 同步 (KnowledgePoint 节点创建)
- 可视化 (nodes/edges 正确)
- Prometheus 指标

docs/nextstep.md: 上游 (MySQL/Neo4j/Kafka/Redis/ES/ai)
+ 下游 (teacher-bff/student-bff/parent-bff/data-ana/api-gateway/ai)
2026-07-14 00:58:50 +08:00

287 lines
17 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.
# content 下一步工作与上下游依赖
> 模块content内容域服务Textbook/Chapter/KnowledgeGraph/Question 四 Service端口 HTTP 3005 / gRPC 50054
> 负责人ai09
> 更新日期2026-07-13P4P6+ 全部完成Docker 本地测试通过)
> 关联文档:[02-architecture-design.md](./02-architecture-design.md)、[content_contract.md](../../../docs/architecture/issues/contracts/content_contract.md)、[content_workline.md](../../../docs/architecture/issues/worklines/content_workline.md)
---
## 1. 模块当前状态
content 模块已完成 P4P6+ 全部批次,提供 Textbook / Chapter / KnowledgeGraph / Question 四个 Service 共 22 个 RPC本地 Docker 镜像构建与运行验证通过(非 mock 数据ES 全文检索、Neo4j 知识图谱、审核工作流状态机、Outbox 事件驱动全部联调通过。
### 1.1 服务能力概览
| Service | RPC 数量 | 核心能力 |
| --------------------- | -------- | --------------------------------------------------------------- |
| TextbookService | — | 教材 CRUD、教材树管理、归档、版本查询 |
| ChapterService | — | 章节 CRUD、章节目录树 |
| KnowledgeGraphService | — | 知识点 CRUD、知识图谱Neo4j、学习路径、前置依赖、可视化 |
| QuestionService | — | 题目 CRUD、ES 全文检索、审核工作流状态机、AI 批量出题(待联调) |
| **合计** | **22** | 4 Service |
### 1.2 P5 完成项ES 集成)
| 验证项 | 状态 | 说明 |
| -------------------------------------- | ---- | -------------------------------------------------------------- |
| Elasticsearch 容器就绪 | ✅ | 本地 Docker edu-es 已就绪 |
| ES config 模块 | ✅ | `src/config/elasticsearch.ts`(惰性初始化 + ik→standard 回退) |
| ES Sync WorkerKafka 消费 → ES 索引) | ✅ | `src/shared/sync/es-sync.worker.ts`event_id 去重 + 软失败) |
| SearchQuestions API 接入 ES | ✅ | ES 优先MySQL LIKE 降级 |
| content_questions 索引映射 | ✅ | `ensureQuestionIndex()` 幂等创建ik 不可用时回退 standard |
| /readyz ES 索引存在性检查 | ✅ | degraded 而非 error |
### 1.3 P6+ 完成项
| 验证项 | 状态 | 说明 |
| ------------------------- | ---- | ------------------------------------------------------------------------------------------- |
| Question 审核工作流状态机 | ✅ | draft→pending_review→published/rejected→archived非法转换拦截 |
| 知识图谱可视化 API | ✅ | `GET /knowledge-graph/visualization`Neo4j 优先 + MySQL 降级 |
| 教材版本管理 | ✅ | `GET /textbooks/versions` + `POST /textbooks/:id/archive` |
| 可观测性硬化 | ✅ | 5 个 Prometheus 指标outbox_pending / neo4j_lag / es_lag / search_total / search_latency |
| /readyz Outbox 积压检查 | ✅ | pending > 100 → degraded |
### 1.4 本地 Docker 验证结果2026-07-13
测试环境:本地 Dockeredu-mysql + edu-neo4j + edu-es + edu-kafka + edu-redis + edu-content-test均接入 `edu-full_default` 网络)
```
镜像edu/content:test
容器edu-content-testDEV_MODE=true
测试 1健康检查
GET /healthz → {"status":"ok","service":"content"} ✅
GET /readyz → {"status":"ok","dependencies":[mysql:ok, neo4j:ok, kafka:ok, outbox:ok(0), elasticsearch:ok]} ✅
测试 2REST CRUD全部通过
POST /textbooks → 创建教材 ✅ (id=l9oo0iycnxlguqvhskjhrksa)
POST /chapters → 创建章节 ✅ (id=qdry24sm4ni2lrdf0fe7is2k)
POST /knowledge-points → 创建知识点 ✅ (id=tuuv90gloo7kf2x1al0b1b6g)
POST /questions → 创建题目 ✅ (id=ellr9gi1mnb9ir7ifxukhixs)
GET /questions/:id → 读取题目 ✅ (status=draft)
GET /questions?knowledgePointId=... → 列表查询 ✅ (count=1)
测试 3ES 全文检索
GET /questions/search?q=3 → total=1 ✅ (ES 索引命中)
GET /questions/search?q=苹果 → total=0 (standard 分析器中文按字切分IK 插件可用时改善)
测试 4审核工作流状态机
POST /questions/:id/submit-review → draft→pending_review ✅
POST /questions/:id/approve → pending_review→published ✅
POST /questions/:id/archive → published→archived ✅
POST /questions/:id/approve → 非法转换正确拒绝 ✅ (CONTENT_VALIDATION_ERROR)
测试 5Outbox 事件驱动
content_outbox_events 表 8 条事件,全部 status=published, retry_count=0 ✅
事件类型textbook.created, chapter.created, knowledge_point.created,
question.created, question.updated×2, question.published, textbook.archived
测试 6Neo4j 知识图谱同步
Neo4j KnowledgePoint 节点已创建 ✅ (id=tuuv90gloo7kf2x1al0b1b6g, difficulty=2)
GET /knowledge-graph/visualization → nodes=1, edges=0 ✅
测试 7教材归档
POST /textbooks/:id/archive → status=archived ✅
测试 8Prometheus 指标
GET /metrics → content_outbox_pending_total=0, content_neo4j_sync_lag_ms=0,
content_es_sync_lag_ms=0, content_question_search_total{source="es"} ✅
```
---
## 2. 上游依赖content 依赖谁)
### 2.1 MySQL基础设施— P0 必需
| 项 | 内容 |
| -------- | -------------------------------------------------------------------------------------------- |
| 端点 | `mysql://edu-mysql:3306/next_edu_cloud` |
| 用途 | 主数据存储textbooks / chapters / knowledge_points / questions / content_outbox_events 表) |
| 状态 | ✅ 本地 Docker edu-mysql 已就绪 |
| 环境变量 | `DATABASE_URL` |
### 2.2 Neo4j基础设施— P0 必需
| 项 | 内容 |
| -------- | ---------------------------------------------------------- |
| 端点 | `bolt://edu-neo4j:7687` |
| 用途 | 知识图谱存储KnowledgePoint 节点 + PREREQUISITE_OF 关系) |
| 状态 | ✅ 本地 Docker edu-neo4j 已就绪 |
| 环境变量 | `NEO4J_URL``NEO4J_PASSWORD` |
### 2.3 Kafka基础设施— P0 必需
| 项 | 内容 |
| -------- | ------------------------------------------------------------------------------- |
| 端点 | `kafka:29092` |
| 用途 | Outbox 事件发布4 个聚合 topic+ Neo4j Sync Worker 消费 + ES Sync Worker 消费 |
| 状态 | ✅ 本地 Docker edu-kafka 已就绪 |
| 环境变量 | `KAFKA_BROKERS` |
### 2.4 Redis基础设施— P1 可选
| 项 | 内容 |
| -------- | ---------------------------------------------------------------- |
| 端点 | `redis://edu-redis:6379` |
| 用途 | 缓存(教材树 / 知识点树读多写少场景env.ts 已预留 `REDIS_URL` |
| 状态 | ✅ 本地 Docker edu-redis 已就绪 |
| 环境变量 | `REDIS_URL` |
### 2.5 Elasticsearch基础设施— P5 必需
| 项 | 内容 |
| -------- | ------------------------------------------ |
| 端点 | `http://edu-es:9200` |
| 用途 | 题目全文检索content_questions 索引) |
| 状态 | ✅ 本地 Docker edu-es 已就绪profile p5 |
| 环境变量 | `ES_URL` |
### 2.6 ai 服务ai12 负责)— P5 联调
| # | 依赖项 | 用途 | 状态 |
| --- | ------------------------------ | -------------------------------------------------------- | ----------------- |
| 1 | gRPC `GenerateQuestion` :50058 | AI 批量出题QuestionService.BatchCreateQuestions 联调) | ⏳ 待 ai 服务就绪 |
**关键环境变量**
- `AI_GRPC_TARGET=ai:50058`(待联调阶段配置)
---
## 3. 下游依赖(谁依赖 content
### 3.1 teacher-bffai03 负责)— gRPC :50054
| # | 依赖项 | 用途 | 状态 |
| --- | --------------------------------------------------- | -------------------- | ---------------------- |
| 1 | gRPC `GetLearningPath(studentId, subjectId)` :50054 | `knowledgePath` 查询 | ✅ content gRPC 已就绪 |
| 2 | gRPC `ListTextbooks(subjectId, gradeId)` :50054 | 教材列表 | ✅ content gRPC 已就绪 |
| 3 | gRPC `ListChapters(textbookId)` :50054 | 章节目录 | ✅ content gRPC 已就绪 |
### 3.2 student-bffai04 负责)— gRPC :50054
| # | 依赖项 | 用途 | 状态 |
| --- | ---------------------------------- | ------------ | ----------------------------------------- |
| 1 | gRPC `ListTextbooks` :50054 | 学生浏览教材 | ✅ content gRPC 已就绪 |
| 2 | gRPC `ListChapters` :50054 | 学生浏览章节 | ✅ content gRPC 已就绪 |
| 3 | gRPC `GetLearningPath` :50054 | 学生学习路径 | ✅ content gRPC 已就绪 |
| 4 | gRPC `SearchQuestions` :50054 | 题目检索 | ✅ content ES 已就绪,待 student-bff 联调 |
| 5 | gRPC `BatchCreateQuestions` :50054 | AI 出题 | ⏳ 待 ai 服务就绪后联调 |
### 3.3 parent-bffai05 负责)— gRPC :50054
| # | 依赖项 | 用途 | 状态 |
| --- | ------------------------------ | -------------------- | ---------------------- |
| 1 | gRPC `ListTextbooks` :50054 | 家长查看孩子教材 | ✅ content gRPC 已就绪 |
| 2 | gRPC `ListChapters` :50054 | 家长查看孩子章节 | ✅ content gRPC 已就绪 |
| 3 | gRPC `GetPrerequisites` :50054 | 孩子学习路径前置依赖 | ✅ content gRPC 已就绪 |
| 4 | gRPC `GetLearningPath` :50054 | 孩子学习路径 | ✅ content gRPC 已就绪 |
### 3.4 data-anaai11 负责)— Kafka 消费
| # | 依赖项 | 用途 | 状态 |
| --- | ----------------------------------------------- | ------------------ | ----------------------- |
| 1 | 消费 topic `edu.content.knowledge_point.events` | 分析知识点难度分布 | ✅ content Kafka 已就绪 |
| 2 | 消费 topic `edu.content.question.events` | 题目来源统计 | ✅ content Kafka 已就绪 |
### 3.5 api-gatewayai01 负责)— HTTP REST :3005
| 能力 | 配置 | 状态 |
| ----------------------------------- | -------------------- | ------------------------- |
| `/api/v1/textbooks` 反向代理 | → content:3005 | ✅ api-gateway 已配置路由 |
| `/api/v1/chapters` 反向代理 | → content:3005 | ✅ api-gateway 已配置路由 |
| `/api/v1/knowledge-points` 反向代理 | → content:3005 | ✅ api-gateway 已配置路由 |
| `/api/v1/questions` 反向代理 | → content:3005 | ✅ api-gateway 已配置路由 |
| `GET /healthz` 端点 | /readyz 下游健康检查 | ✅ 已实现 |
### 3.6 ai 服务ai12 负责)— Kafka 消费
| # | 依赖项 | 用途 | 状态 |
| --- | ---------------------------------------- | ----------------------- | ----------------------- |
| 1 | 消费 topic `edu.content.question.events` | AI 出题时获取知识点信息 | ✅ content Kafka 已就绪 |
---
## 4. 环境变量清单
| 变量 | 必填 | 示例值 | 说明 |
| ----------------------------- | ---- | ---------------------------------------------------- | ------------------ |
| `PORT` | 是 | `3005` | HTTP 监听端口 |
| `GRPC_PORT` | 是 | `50054` | gRPC 监听端口 |
| `DATABASE_URL` | 是 | `mysql://edu:changeme@edu-mysql:3306/next_edu_cloud` | MySQL 连接 |
| `REDIS_URL` | 否 | `redis://edu-redis:6379` | Redis 缓存 |
| `NEO4J_URL` | 否 | `bolt://edu-neo4j:7687` | Neo4j 连接 |
| `NEO4J_PASSWORD` | 否 | `changeme` | Neo4j 密码 |
| `ES_URL` | 否 | `http://edu-es:9200` | Elasticsearch 连接 |
| `KAFKA_BROKERS` | 是 | `kafka:29092` | Kafka broker |
| `JWT_SECRET` | 否 | — | JWT 密钥 |
| `DEV_MODE` | 否 | `false` | 开发模式 |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | 否 | `http://otel-collector:4318` | OTLP 端点 |
| `LOG_LEVEL` | 否 | `info` | 日志级别 |
---
## 5. 剩余工作
| # | 工作项 | 阶段 | 状态 |
| --- | ---------------------------------------------- | ---- | ----------------- |
| 1 | ES 集成config + sync worker + search API | P5 | ✅ 完成 |
| 2 | Question 审核工作流状态机 | P6+ | ✅ 完成 |
| 3 | 知识图谱可视化 API | P6+ | ✅ 完成 |
| 4 | 教材版本管理 | P6+ | ✅ 完成 |
| 5 | 可观测性硬化Prometheus 指标 + readyz 检查) | P6+ | ✅ 完成 |
| 6 | AI 批量出题联调BatchCreateQuestions + ai12 | 联调 | ⏳ 待 ai 服务就绪 |
content 模块自身功能已全部完成,无剩余开发任务。唯一待办为 ai 服务ai12就绪后的 AI 出题联调。
---
## 6. Docker 本地测试
### 6.1 镜像构建
```bash
docker build -t edu/content:test -f services/content/Dockerfile .
```
### 6.2 容器启动
```bash
docker run -d \
--name edu-content-test \
--network edu-full_default \
-p 3005:3005 -p 50054:50054 \
-e DATABASE_URL=mysql://edu:changeme@edu-mysql:3306/next_edu_cloud \
-e NEO4J_URL=bolt://edu-neo4j:7687 \
-e NEO4J_PASSWORD=changeme \
-e ES_URL=http://edu-es:9200 \
-e KAFKA_BROKERS=kafka:29092 \
-e REDIS_URL=redis://edu-redis:6379 \
-e NODE_ENV=production \
-e DEV_MODE=true \
edu/content:test
```
---
## 7. 关键文件路径
| 文件 | 用途 |
| -------------------------------------------------------- | ----------------------------- |
| `packages/shared-proto/proto/content.proto` | gRPC 契约22 RPC |
| `packages/shared-proto/proto/events.proto` | 事件契约4 content message |
| `services/content/src/main.ts` | 服务入口 |
| `services/content/src/app.module.ts` | NestJS 模块注册 |
| `services/content/src/grpc/` | 4 个 gRPC controller |
| `services/content/src/shared/outbox/` | Outbox 模式实现 |
| `services/content/src/shared/sync/neo4j-sync.worker.ts` | Neo4j 异步同步 |
| `services/content/Dockerfile` | Docker 构建 |
| `docs/architecture/issues/contracts/content_contract.md` | 契约文档 |
| `docs/architecture/issues/worklines/content_workline.md` | 工作排期 |
---
**本文件由 ai09 维护,上游/下游工作项请各负责 AI 完成后通知 ai09 更新状态。**