Files
Edu/services/content/README.md
SpecialX b50dd62c9b chore(content): merge content full implementation into main
Merge feat/content-ai09 with complete content service
2026-07-10 19:13:02 +08:00

183 lines
9.8 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 内容资源服务
> 版本1.0P4 完整实现)
> 端口HTTP 3005 / gRPC 50054
## 职责
内容资源限界上下文,管理 Textbook、Chapter、KnowledgePoint、Question 四个聚合。
支持多存储MySQL写模型权威源+ Neo4j知识图谱派生读模型+ ElasticsearchP5 引入,题库全文检索)。
事件驱动Outbox 模式发布 4 个聚合 topicNeo4j Sync Worker 异步消费事件同步图谱。
## 技术栈
- NestJS 10.x + TypeScript 5.6ESM相对 import 带 `.js` 后缀)
- Drizzle ORM 0.31MySQL`getDb()` 函数式懒加载)
- neo4j-driver 5.x知识图谱仅读模型查询
- KafkaJS 2.2idempotent producer + transactionalId
- @grpc/grpc-js + @nestjs/microservicesgRPC server 50054
- @paralleldrive/cuid2(统一 ID 策略)
- Zod 3.xController 层全量 schema.parse
- pino日志+ prom-client指标+ OpenTelemetry追踪
## 开发
```bash
pnpm install
pnpm dev # HTTP 3005 + gRPC 50054
pnpm build
pnpm typecheck
pnpm lint
pnpm test
```
## 环境变量
| 变量 | 说明 |
| ----------------------------- | -------------------------------------------------- |
| `PORT` | HTTP 服务端口(默认 3005 |
| `GRPC_PORT` | gRPC 服务端口(默认 50054 |
| `DATABASE_URL` | MySQL 连接串(必填) |
| `KAFKA_BROKERS` | Kafka broker 列表(逗号分隔,默认 localhost:9092 |
| `NEO4J_URL` | Neo4j Bolt 连接 URL可选 |
| `NEO4J_PASSWORD` | Neo4j 密码(可选) |
| `REDIS_URL` | Redis 连接预留P5+ 缓存) |
| `ES_URL` | Elasticsearch 地址P5 引入) |
| `JWT_SECRET` | JWT 密钥Gateway 校验,服务可选) |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OpenTelemetry OTLP 端点(可选) |
## 模块结构
```
src/
├─ config/ # env / database(getDb) / kafka / neo4j
├─ grpc/ # gRPC controllers4 Service, 22 RPC
│ ├─ grpc.module.ts
│ ├─ grpc-types.ts # 手动定义 proto message TS 类型
│ ├─ textbook.grpc.controller.ts
│ ├─ chapter.grpc.controller.ts
│ ├─ knowledge-graph.grpc.controller.ts
│ └─ question.grpc.controller.ts
├─ textbooks/ # 教材领域schema/repository/service/controller/dto
├─ chapters/ # 章节领域
├─ knowledge-points/ # 知识点领域(含前置依赖管理)
├─ questions/ # 题库领域
├─ shared/
│ ├─ errors/ # ApplicationError + GlobalErrorFilterCONTENT_* 前缀 + ZodError 分支)
│ ├─ health/ # /healthz + /readyzDB/Neo4j/Kafka 多依赖检查)
│ ├─ lifecycle/ # 优雅关闭
│ ├─ observability/ # logger / metrics / tracer
│ ├─ outbox/ # Outbox 模式schema/repository/publisher/service/module/events
│ └─ sync/ # Neo4j Sync Worker消费 Kafka 事件异步同步图谱)
├─ middleware/ # auth.middleware + permission.guard
├─ app.module.ts
└─ main.ts # HTTP + gRPC hybrid app
```
## REST API 端点
### Textbooks
| 方法 | 路径 | 说明 |
| -------- | ---------------- | ------------------------- |
| `POST` | `/textbooks` | 创建教材 |
| `GET` | `/textbooks` | 教材列表(支持分页/过滤) |
| `GET` | `/textbooks/:id` | 教材详情 |
| `PUT` | `/textbooks/:id` | 更新教材 |
| `DELETE` | `/textbooks/:id` | 删除教材 |
### Chapters
| 方法 | 路径 | 说明 |
| -------- | -------------------------------- | -------------- |
| `POST` | `/chapters` | 创建章节 |
| `GET` | `/chapters/textbook/:textbookId` | 按教材列出章节 |
| `GET` | `/chapters/:id` | 章节详情 |
| `PUT` | `/chapters/:id` | 更新章节 |
| `DELETE` | `/chapters/:id` | 删除章节 |
### Knowledge Points
| 方法 | 路径 | 说明 |
| -------- | ----------------------------------------------------- | ------------------------------ |
| `POST` | `/knowledge-points` | 创建知识点 |
| `GET` | `/knowledge-points/chapter/:chapterId` | 按章节列出知识点 |
| `GET` | `/knowledge-points/:id` | 知识点详情 |
| `GET` | `/knowledge-points/:id/prerequisites` | 查询前置依赖(读 Neo4j |
| `POST` | `/knowledge-points/:id/prerequisites` | 添加前置依赖(发 Outbox 事件) |
| `DELETE` | `/knowledge-points/:id/prerequisites/:prerequisiteId` | 移除前置依赖(发 Outbox 事件) |
| `PUT` | `/knowledge-points/:id` | 更新知识点 |
| `DELETE` | `/knowledge-points/:id` | 删除知识点 |
### Questions
| 方法 | 路径 | 说明 |
| -------- | ---------------------------------------------- | ------------------------- |
| `POST` | `/questions` | 创建题目 |
| `GET` | `/questions` | 题目列表(支持分页/过滤) |
| `GET` | `/questions/knowledge-point/:knowledgePointId` | 按知识点列出题目 |
| `GET` | `/questions/:id` | 题目详情 |
| `PUT` | `/questions/:id` | 更新题目 |
| `DELETE` | `/questions/:id` | 删除题目 |
## gRPC API端口 50054
Proto 定义:`packages/shared-proto/proto/content.proto`(包名 `next_edu_cloud.content.v1`
| Service | RPC 数 | 关键方法 |
| ----------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `TextbookService` | 5 | CreateTextbook / GetTextbook / ListTextbooks / UpdateTextbook / DeleteTextbook |
| `ChapterService` | 5 | CreateChapter / GetChapter / ListChapters / UpdateChapter / DeleteChapter |
| `KnowledgeGraphService` | 4 | GetPrerequisites / GetLearningPath / AddPrerequisite / RemovePrerequisite |
| `QuestionService` | 8 | CreateQuestion / BatchCreateQuestions / GetQuestion / ListQuestions / UpdateQuestion / DeleteQuestion / PublishQuestion / SearchQuestions |
**合计 22 RPC。**
## 事件驱动
### Outbox 模式
业务操作create/update/delete在同一事务内写业务表 + `content_outbox_events` 表。
独立 `OutboxPublisher` worker 轮询 pending 记录投递 Kafkaat-least-once最大重试 5 次,指数退避)。
### Kafka Topics4 个聚合 topicaction 字段区分事件类型)
| Topic | 事件类型action |
| ------------------------------------ | ------------------------------------------------------------- |
| `edu.content.textbook.events` | created / updated / published / archived |
| `edu.content.chapter.events` | created / updated / deleted |
| `edu.content.knowledge_point.events` | created / updated / prerequisite_added / prerequisite_removed |
| `edu.content.question.events` | created / updated / published / deleted |
### Neo4j Sync Worker
消费 `edu.content.knowledge_point.events` topic异步同步知识图谱
- `kp.created` / `kp.updated` → MERGE 节点
- `prerequisite_added` → MERGE 关系
- `prerequisite_removed` → DELETE 关系
Neo4j 不可用时非阻塞跳过(不影响 MySQL 写入和主流程)。
## 健康检查
| 端点 | 用途 | 鉴权 |
| -------------- | -------------------------------------------------------- | ---- |
| `GET /healthz` | 存活探针liveness仅返回进程状态 | 无 |
| `GET /readyz` | 就绪探针readiness检查 DB/Neo4j/Kafka失败返回 503 | 无 |
## 质量校验
| 检查项 | 命令 | 状态 |
| -------- | ----------------------- | ----------------- |
| 类型检查 | `pnpm typecheck` | ✅ 0 错误 |
| Lint | `pnpm lint` | ✅ 0 错误 |
| 单元测试 | `pnpm test` | ✅ 182 tests 通过 |
| 覆盖率 | `vitest run --coverage` | ✅ 66.94%≥60% |
## 对外契约
- gRPC proto`packages/shared-proto/proto/content.proto`
- 事件 proto`packages/shared-proto/proto/events.proto`TextbookEvent / ChapterEvent / KnowledgePointEvent / QuestionEvent
- 契约文档:`docs/architecture/issues/contracts/content_contract.md`