新增 3 个业务域(10 RPC): - ElectiveService: 选修课列表/学生选课记录/选课/退课(含容量与重复校验) - LessonPlanService: 教师备课列表/学生备课列表(仅 published)/详情 - CoursePlanService: 学生课程计划列表/详情 - KnowledgeGraphService.GetKnowledgePath: 与 GetLearningPath 同实现 新增 4 张 MySQL 表(elective_courses/selections/lesson_plans/course_plans),含完整索引。 新增 11 个权限点,覆盖 admin/teacher/student/parent 四角色。 proto 由 4 Service/22 RPC 扩展至 7 Service/32 RPC,v1 全部 RPC 保持向后兼容。 修复 logger.ts pino 导入: default import 在 NodeNext ESM 下不可调用, 改用 named import(与 iam/msg/core-edu 对齐)。 Docker 本地测试全部通过(HTTP + gRPC 双协议),健康检查、 Elective/LessonPlan/CoursePlan CRUD、4 个新 gRPC Service 全部验证通过。 nextstep-v2.md 已创建,记录上下游依赖与 6 项联调待办。
342 lines
21 KiB
Markdown
342 lines
21 KiB
Markdown
# content 下一步工作与上下游依赖(v2)
|
||
|
||
> 模块:content(内容域服务,7 Service / 32 RPC,端口 HTTP 3005 / gRPC 50054)
|
||
> 更新日期:2026-07-14(v2 全部完成,Docker 本地测试通过)
|
||
> 关联文档:[nextstep.md](./nextstep.md)、[02-architecture-design.md](./02-architecture-design.md)
|
||
|
||
---
|
||
|
||
## 1. v2 完成项
|
||
|
||
content 模块在 v1 基础上扩展了 3 个业务域(Elective / LessonPlan / CoursePlan)+ 1 个查询入口(GetKnowledgePath),新增 10 个 RPC、4 张 MySQL 表、11 个权限点,HTTP + gRPC 双协议本地 Docker 全部测试通过。
|
||
|
||
### 1.1 v2 服务能力概览
|
||
|
||
| Service | RPC 数 | v1 已有 | v2 新增 | 核心能力 |
|
||
| --------------------- | ------ | ------- | ------- | ------------------------------------------------------ |
|
||
| TextbookService | 5 | 5 | 0 | 教材 CRUD、归档、版本 |
|
||
| ChapterService | 5 | 5 | 0 | 章节 CRUD、目录树 |
|
||
| KnowledgeGraphService | 5 | 4 | 1 | 知识图谱、学习路径、前置依赖、可视化、GetKnowledgePath |
|
||
| QuestionService | 8 | 8 | 0 | 题目 CRUD、ES 检索、审核状态机、AI 出题 |
|
||
| **ElectiveService** | 4 | 0 | 4 | 选修课列表 / 学生选课记录 / 选课 / 退课 |
|
||
| **LessonPlanService** | 3 | 0 | 3 | 教师备课列表 / 学生备课列表 / 详情 |
|
||
| **CoursePlanService** | 2 | 0 | 2 | 学生课程计划列表 / 详情 |
|
||
| **合计** | **32** | 22 | **10** | **7 Service** |
|
||
|
||
### 1.2 v2 新增 RPC 列表
|
||
|
||
| Service | RPC | 用途 |
|
||
| --------------------- | ------------------------------- | -------------------------------------------------------------------- |
|
||
| KnowledgeGraphService | GetKnowledgePath | 知识图谱路径查询(与 GetLearningPath 同实现,符合上游 BFF 命名约定) |
|
||
| ElectiveService | ListAvailableElectiveCourses | 列出可选选修课(status=open 且有剩余容量) |
|
||
| ElectiveService | ListElectiveSelectionsByStudent | 查询学生已选选修课 |
|
||
| ElectiveService | SelectCourse | 学生选课(含容量校验 + 重复选课校验) |
|
||
| ElectiveService | DropCourse | 学生退课(同步 enrolled_count 减 1) |
|
||
| LessonPlanService | ListLessonPlansByTeacher | 教师视角备课列表 |
|
||
| LessonPlanService | ListLessonPlansByStudent | 学生视角备课列表(仅 status=published) |
|
||
| LessonPlanService | GetLessonPlan | 备课详情 |
|
||
| CoursePlanService | ListCoursePlansByStudent | 学生课程计划列表 |
|
||
| CoursePlanService | GetCoursePlan | 课程计划详情 |
|
||
|
||
### 1.3 v2 新增数据表
|
||
|
||
| 表名 | 用途 | 索引 |
|
||
| --------------------------- | ------------ | ------------------------------------------ |
|
||
| content_elective_courses | 选修课主表 | subject_id / teacher_id / status |
|
||
| content_elective_selections | 学生选课记录 | student_id / course_id / status |
|
||
| content_lesson_plans | 教师备课计划 | teacher_id / class_id / status |
|
||
| content_course_plans | 学生课程计划 | student_id / class_id / plan_type / status |
|
||
|
||
迁移 SQL:[v2-migration.sql](./v2-migration.sql)
|
||
|
||
### 1.4 v2 新增权限点
|
||
|
||
| 权限常量 | admin | teacher | student | parent |
|
||
| -------------------------- | ----- | ------- | ------- | ------ |
|
||
| CONTENT_ELECTIVE_CREATE | ✅ | ✅ | ❌ | ❌ |
|
||
| CONTENT_ELECTIVE_READ | ✅ | ✅ | ✅ | ✅ |
|
||
| CONTENT_ELECTIVE_SELECT | ❌ | ❌ | ✅ | ❌ |
|
||
| CONTENT_LESSON_PLAN_CREATE | ✅ | ✅ | ❌ | ❌ |
|
||
| CONTENT_LESSON_PLAN_READ | ✅ | ✅ | ✅ | ✅ |
|
||
| CONTENT_LESSON_PLAN_UPDATE | ✅ | ✅ | ❌ | ❌ |
|
||
| CONTENT_LESSON_PLAN_DELETE | ✅ | ✅ | ❌ | ❌ |
|
||
| CONTENT_COURSE_PLAN_CREATE | ✅ | ✅ | ❌ | ❌ |
|
||
| CONTENT_COURSE_PLAN_READ | ✅ | ✅ | ✅ | ✅ |
|
||
| CONTENT_COURSE_PLAN_UPDATE | ✅ | ✅ | ❌ | ❌ |
|
||
| CONTENT_COURSE_PLAN_DELETE | ✅ | ✅ | ❌ | ❌ |
|
||
|
||
### 1.5 v2 Docker 本地测试结果(2026-07-14)
|
||
|
||
测试环境:本地 Docker(edu-mysql + edu-neo4j + edu-es + edu-kafka + edu-redis + edu-content-test)
|
||
|
||
```
|
||
镜像:edu/content:test
|
||
容器:edu-content-test(DEV_MODE=true,HTTP 3105 / gRPC 51054)
|
||
|
||
测试 1:健康检查
|
||
GET /healthz → {"status":"ok"} ✅
|
||
GET /readyz → {"status":"ok","dependencies":[mysql:ok, neo4j:ok, kafka:ok, outbox:ok, elasticsearch:ok]} ✅
|
||
|
||
测试 2:Elective CRUD(全部通过)
|
||
POST /electives/courses → 创建选修课 ✅ (id=rtssmkviljmmkpa04npvklq0)
|
||
GET /electives/courses → 列表 ✅ (count=1)
|
||
POST /electives/select → 学生选课 ✅ (id=js987vhi63xnnxyxov2yttbg)
|
||
GET /electives/selections → 学生选课记录 ✅ (count=1, status=selected)
|
||
POST /electives/drop → 退课 ✅
|
||
|
||
测试 3:LessonPlan CRUD(全部通过)
|
||
POST /lesson-plans → 创建备课 ✅ (id=gxgozqgr059y4w0v9ndhm6mt, status=draft)
|
||
PUT /lesson-plans/:id → 发布备课 ✅ (status=published)
|
||
GET /lesson-plans?teacherId=.. → 教师列表 ✅ (count=1)
|
||
GET /lesson-plans?studentId=..&classId=.. → 学生列表(仅 published) ✅ (count=1)
|
||
GET /lesson-plans/:id → 详情 ✅
|
||
DELETE /lesson-plans/:id → 删除 ✅
|
||
|
||
测试 4:CoursePlan CRUD(全部通过)
|
||
POST /course-plans → 创建课程计划 ✅ (id=za9r3arn8hetr5nwjao9dgre, status=active)
|
||
GET /course-plans?studentId=.. → 学生列表 ✅ (count=1)
|
||
GET /course-plans/:id → 详情 ✅
|
||
PUT /course-plans/:id → 更新 ✅ (status=archived)
|
||
DELETE /course-plans/:id → 删除 ✅
|
||
|
||
测试 5:gRPC 4 个新 Service(全部通过)
|
||
ElectiveService.ListAvailableElectiveCourses → ✅ 返回 1 个课程
|
||
LessonPlanService.ListLessonPlansByTeacher → ✅ 返回空(已删除测试数据)
|
||
CoursePlanService.ListCoursePlansByStudent → ✅ 返回空(已删除测试数据)
|
||
KnowledgeGraphService.GetKnowledgePath → ✅ 返回 1 个知识点
|
||
|
||
测试 6:gRPC Controller 注册(启动日志验证)
|
||
7 个 gRPC controller 全部注册 ✅
|
||
8 个 HTTP controller 全部注册 ✅
|
||
Neo4jSyncWorker / EsSyncWorker / OutboxPublisher 全部启动 ✅
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 上游需求满足情况(content → 上游 BFF)
|
||
|
||
content 已实现上游 3 个 BFF 在 nextstep-v2.md 中提出的全部 v2 依赖。
|
||
|
||
### 2.1 teacher-bff(ai03 负责)
|
||
|
||
| # | teacher-bff 依赖项 | content 实现 RPC | 状态 |
|
||
| --- | ---------------------------------------- | -------------------------------------------- | ---- |
|
||
| 1 | gRPC `GetKnowledgePath(classId)` :50054 | `KnowledgeGraphService.GetKnowledgePath` | ✅ |
|
||
| 2 | gRPC `ListTextbooks()` :50054 | `TextbookService.ListTextbooks`(v1 已有) | ✅ |
|
||
| 3 | gRPC `ListLessonPlans(teacherId)` :50054 | `LessonPlanService.ListLessonPlansByTeacher` | ✅ |
|
||
|
||
### 2.2 student-bff(ai04 负责)
|
||
|
||
| # | student-bff 依赖项 | content 实现 RPC | 状态 |
|
||
| --- | ------------------------------------------------- | -------------------------------------------------- | ---- |
|
||
| 1 | `TextbookService.ListTextbooks` | `TextbookService.ListTextbooks`(v1 已有) | ✅ |
|
||
| 2 | `ChapterService.ListChapters` | `ChapterService.ListChapters`(v1 已有) | ✅ |
|
||
| 3 | `KnowledgeGraphService.GetLearningPath` | `KnowledgeGraphService.GetLearningPath`(v1 已有) | ✅ |
|
||
| 4 | `ElectiveService.ListElectiveSelectionsByStudent` | `ElectiveService.ListElectiveSelectionsByStudent` | ✅ |
|
||
| 5 | `ElectiveService.ListAvailableElectiveCourses` | `ElectiveService.ListAvailableElectiveCourses` | ✅ |
|
||
| 6 | `ElectiveService.SelectCourse` | `ElectiveService.SelectCourse` | ✅ |
|
||
| 7 | `ElectiveService.DropCourse` | `ElectiveService.DropCourse` | ✅ |
|
||
| 8 | `LessonPlanService.ListLessonPlansByStudent` | `LessonPlanService.ListLessonPlansByStudent` | ✅ |
|
||
| 9 | `LessonPlanService.GetLessonPlan` | `LessonPlanService.GetLessonPlan` | ✅ |
|
||
| 10 | `CoursePlanService.ListCoursePlansByStudent` | `CoursePlanService.ListCoursePlansByStudent` | ✅ |
|
||
| 11 | `CoursePlanService.GetCoursePlan` | `CoursePlanService.GetCoursePlan` | ✅ |
|
||
|
||
### 2.3 parent-bff(ai05 负责)
|
||
|
||
| # | parent-bff 依赖项 | content 实现 RPC | 状态 |
|
||
| --- | ---------------------------- | -------------------------------------------------------------- | ---- |
|
||
| 1 | `CoursePlanService.List/Get` | `CoursePlanService.ListCoursePlansByStudent` + `GetCoursePlan` | ✅ |
|
||
| 2 | `LessonPlanService.List/Get` | `LessonPlanService.ListLessonPlansByStudent` + `GetLessonPlan` | ✅ |
|
||
| 3 | `ElectiveService.List` | `ElectiveService.ListElectiveSelectionsByStudent` | ✅ |
|
||
|
||
### 2.4 api-gateway(ai01 负责)
|
||
|
||
| 路由 | 转发目标 | 状态 |
|
||
| ------------------------------- | ------------ | ------------------------------ |
|
||
| `/api/v1/textbooks/*` | content:3005 | ✅ v1 已配置 |
|
||
| `/api/v1/chapters/*` | content:3005 | ✅ v1 已配置 |
|
||
| `/api/v1/knowledge-points/*` | content:3005 | ✅ v1 已配置 |
|
||
| `/api/v1/questions/*` | content:3005 | ✅ v1 已配置 |
|
||
| **`/api/v1/electives/*`** | content:3005 | ⏳ 待 api-gateway 补充 v2 路由 |
|
||
| **`/api/v1/lesson-plans/*`** | content:3005 | ⏳ 待 api-gateway 补充 v2 路由 |
|
||
| **`/api/v1/course-plans/*`** | content:3005 | ⏳ 待 api-gateway 补充 v2 路由 |
|
||
| **`/api/v1/knowledge-graph/*`** | content:3005 | ⏳ 待 api-gateway 补充 v2 路由 |
|
||
|
||
---
|
||
|
||
## 3. 下游需求(content 需要谁)
|
||
|
||
### 3.1 MySQL(基础设施)— ✅ 已就绪
|
||
|
||
v2 新增 4 张表已通过 `v2-migration.sql` 在本地 Docker MySQL 中创建。
|
||
|
||
### 3.2 Neo4j / Kafka / Elasticsearch / Redis — ✅ 已就绪
|
||
|
||
v2 复用 v1 基础设施,无新增依赖。
|
||
|
||
### 3.3 ai 服务(ai12 负责)— ⏳ 待联调
|
||
|
||
| # | 依赖项 | 用途 | 状态 |
|
||
| --- | ------------------------------ | ----------------------------------- | ----------------- |
|
||
| 1 | gRPC `GenerateQuestion` :50058 | AI 批量出题(QuestionService 联调) | ⏳ 待 ai 服务就绪 |
|
||
|
||
### 3.4 iam 服务(ai06 负责)— ⏳ 待联调
|
||
|
||
| # | 依赖项 | 用途 | 状态 |
|
||
| --- | -------------------------------------------- | ------------------------------------------- | ------------------ |
|
||
| 1 | JWT 公钥 / JWKS 端点 | 生产模式 JWT 校验(DEV_MODE=true 时已绕过) | ⏳ 待 iam 服务就绪 |
|
||
| 2 | 用户角色信息(admin/teacher/student/parent) | 权限守卫根据角色判断访问权限 | ⏳ 待 iam 服务就绪 |
|
||
|
||
### 3.5 core-edu 服务(ai07 负责)— ⏳ 待联调(v3+)
|
||
|
||
| # | 依赖项 | 用途 | 状态 |
|
||
| --- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
|
||
| 1 | 班级学生名单查询 | LessonPlan 学生视角:按 classId 过滤学生所在班级的备课计划。当前实现需前端在 query 中显式传 classId,未来可由 core-edu 提供学生→班级映射后自动解析 | ⏳ v3+ |
|
||
| 2 | 教师任教科目查询 | LessonPlan/CoursePlan 按 subjectId 过滤时,前端需显式传参。未来可由 core-edu 提供教师→科目映射 | ⏳ v3+ |
|
||
|
||
---
|
||
|
||
## 4. 环境变量(v2 无新增)
|
||
|
||
v2 沿用 v1 全部环境变量,详见 [nextstep.md §4](./nextstep.md#4-环境变量清单)。
|
||
|
||
---
|
||
|
||
## 5. 待上下游完成的工作
|
||
|
||
### 5.1 给 api-gateway(ai01)
|
||
|
||
**v2 路由补充**:在 `services/api-gateway` 的路由配置中新增以下 4 条反向代理规则,剥离 `/api` 前缀后转发到 `content:3005`:
|
||
|
||
| 路由 | 转发目标 | 备注 |
|
||
| --------------------------- | ------------ | ---------------------------------------------------------------------------------------------------- |
|
||
| `/api/v1/electives/*` | content:3005 | 选修课管理(含 /electives/courses、/electives/selections、/electives/select、/electives/drop) |
|
||
| `/api/v1/lesson-plans/*` | content:3005 | 备课计划管理 |
|
||
| `/api/v1/course-plans/*` | content:3005 | 课程计划管理 |
|
||
| `/api/v1/knowledge-graph/*` | content:3005 | 知识图谱可视化(v1 已有路由 `/api/v1/knowledge-points`,但 `/knowledge-graph/visualization` 需补充) |
|
||
|
||
### 5.2 给 teacher-bff(ai03)
|
||
|
||
**content gRPC 客户端联调**:
|
||
|
||
1. 配置 `CONTENT_GRPC_TARGET=content:50054`(已配置)
|
||
2. 在 `services/teacher-bff/src/clients/content/content-grpc.client.ts` 中确认 3 个 RPC 调用:
|
||
- `KnowledgeGraphService.GetKnowledgePath`(request: `{ subject_id }`,response: `LearningPath`)
|
||
- `TextbookService.ListTextbooks`(v1 已有)
|
||
- `LessonPlanService.ListLessonPlansByTeacher`(request: `{ teacher_id }`,response: `ListLessonPlansResponse`)
|
||
3. 移除 mock 降级逻辑,切换到真实 gRPC 调用
|
||
|
||
### 5.3 给 student-bff(ai04)
|
||
|
||
**content gRPC 客户端联调**:
|
||
|
||
1. 配置 `CONTENT_GRPC_TARGET=content:50054`
|
||
2. 确认 11 个 content RPC 调用(详见 §2.2),重点验证 v2 新增 8 个 RPC:
|
||
- ElectiveService(4 个):`ListAvailableElectiveCourses` / `ListElectiveSelectionsByStudent` / `SelectCourse` / `DropCourse`
|
||
- LessonPlanService(2 个):`ListLessonPlansByStudent` / `GetLessonPlan`
|
||
- CoursePlanService(2 个):`ListCoursePlansByStudent` / `GetCoursePlan`
|
||
3. 移除 mock 降级逻辑,切换到真实 gRPC 调用
|
||
|
||
### 5.4 给 parent-bff(ai05)
|
||
|
||
**content gRPC 客户端联调**:
|
||
|
||
1. 配置 `CONTENT_GRPC_TARGET=content:50054`
|
||
2. 确认 6 个 content RPC 调用(详见 §2.3):
|
||
- CoursePlanService.ListCoursePlansByStudent + GetCoursePlan
|
||
- LessonPlanService.ListLessonPlansByStudent + GetLessonPlan
|
||
- ElectiveService.ListElectiveSelectionsByStudent
|
||
3. 移除 mock 降级逻辑,切换到真实 gRPC 调用
|
||
|
||
### 5.5 给 iam(ai06)
|
||
|
||
**生产 JWT 联调**:
|
||
|
||
content 在生产模式下需要 iam 的 JWKS 端点校验 JWT。当前 `DEV_MODE=true` 已绕过校验,使用预定义角色。iam 就绪后:
|
||
|
||
1. 提供 JWKS 端点 URL(配置 `JWT_JWKS_URI`)
|
||
2. JWT payload 中包含 `role` 字段(admin/teacher/student/parent)
|
||
3. content 的 `permission.guard.ts` 已支持上述 4 种角色 + 11 个 v2 权限点
|
||
|
||
### 5.6 给 ai 服务(ai12)
|
||
|
||
**AI 出题联调**:
|
||
|
||
content 的 `QuestionService.BatchCreateQuestions` 已预留 AI 出题入口,需要 ai 服务实现:
|
||
|
||
1. gRPC `GenerateQuestion` :50058
|
||
2. 输入:知识点 ID + 题目数量 + 难度
|
||
3. 输出:题目数组(题干 + 选项 + 答案 + 解析)
|
||
4. content 配置 `AI_GRPC_TARGET=ai:50058`
|
||
|
||
---
|
||
|
||
## 6. 契约变更说明
|
||
|
||
### 6.1 proto 变更
|
||
|
||
**文件**:`packages/shared-proto/proto/content.proto`
|
||
|
||
**v2 新增**:
|
||
|
||
- 1 个 RPC(`KnowledgeGraphService.GetKnowledgePath`)
|
||
- 3 个 Service(`ElectiveService` / `LessonPlanService` / `CoursePlanService`)
|
||
- 9 个新 RPC
|
||
- 13 个新 message(ElectiveCourse / ElectiveSelection / LessonPlan / CoursePlan 及其 Request/Response)
|
||
|
||
**向后兼容**:v1 全部 22 个 RPC 保持不变,无破坏性变更。
|
||
|
||
### 6.2 数据库变更
|
||
|
||
**文件**:`infra/init-sql/02-all-services-schema.sql`(已更新 4.6-4.9 节)+ `services/content/docs/v2-migration.sql`
|
||
|
||
**v2 新增 4 张表**:见 §1.3。
|
||
|
||
### 6.3 权限变更
|
||
|
||
**文件**:`services/content/src/middleware/permission.guard.ts`
|
||
|
||
**v2 新增 11 个权限点**:见 §1.4。
|
||
|
||
---
|
||
|
||
## 7. 关键文件路径
|
||
|
||
| 文件 | 用途 |
|
||
| -------------------------------------------------------------- | -------------------------------------- |
|
||
| `packages/shared-proto/proto/content.proto` | gRPC 契约(v2: 32 RPC / 7 Service) |
|
||
| `services/content/src/electives/` | 选修课模块(schema/dto/repo/svc/ctrl) |
|
||
| `services/content/src/lesson-plans/` | 备课计划模块 |
|
||
| `services/content/src/course-plans/` | 课程计划模块 |
|
||
| `services/content/src/grpc/elective.grpc.controller.ts` | 选修课 gRPC controller |
|
||
| `services/content/src/grpc/lesson-plan.grpc.controller.ts` | 备课计划 gRPC controller |
|
||
| `services/content/src/grpc/course-plan.grpc.controller.ts` | 课程计划 gRPC controller |
|
||
| `services/content/src/grpc/knowledge-graph.grpc.controller.ts` | 知识图谱 gRPC controller(v2 扩展) |
|
||
| `services/content/src/grpc/grpc-types.ts` | gRPC TypeScript 类型定义 |
|
||
| `services/content/src/middleware/permission.guard.ts` | 权限守卫(v2 新增 11 权限) |
|
||
| `services/content/docs/v2-migration.sql` | v2 数据库迁移 SQL |
|
||
| `infra/init-sql/02-all-services-schema.sql` | 全量 schema(含 v2 新表) |
|
||
|
||
---
|
||
|
||
## 8. 剩余工作
|
||
|
||
| # | 工作项 | 阶段 | 状态 |
|
||
| ------------------------------ | ------------------------------------------------------ | ------- | ---------------- |
|
||
| 1 | Elective / LessonPlan / CoursePlan 三业务域实现 | v2 | ✅ 完成 |
|
||
| 4 张新表 + 迁移 SQL | v2 | ✅ 完成 |
|
||
| 11 个新权限点 + 角色映射 | v2 | ✅ 完成 |
|
||
| GetKnowledgePath RPC | v2 | ✅ 完成 |
|
||
| HTTP + gRPC 双协议 Docker 测试 | v2 | ✅ 完成 |
|
||
| 2 | api-gateway 补充 4 条 v2 路由 | v2 联调 | ⏳ 待 ai01 |
|
||
| 3 | teacher-bff / student-bff / parent-bff 切换到真实 gRPC | v2 联调 | ⏳ 待 ai03/04/05 |
|
||
| 4 | iam 生产 JWT 联调 | v2 联调 | ⏳ 待 ai06 |
|
||
| 5 | ai 服务 AI 出题联调(BatchCreateQuestions) | 联调 | ⏳ 待 ai12 |
|
||
| 6 | core-edu 班级/科目映射(学生视角自动解析 classId) | v3+ | ⏳ 待 ai07 |
|
||
|
||
content 模块 v2 自身功能已全部完成,剩余工作均为上下游联调。
|
||
|
||
---
|
||
|
||
**本文件由 content 模块维护,上下游工作项请各负责 AI 完成后通知更新状态。**
|