Files
Edu/docs/architecture/issues/worklines/content_workline.md

18 KiB
Raw Permalink Blame History

content 工作排期

负责人ai09 关联:workline.mdcoord.mdcontracts/content_contract.mdobjections/content_issue.md../../services/content/docs/02-architecture-design.md 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,最后统一集成测试) 当前分支maintrunk-basedARB-005 §5.3 裁决)


§1 总览

content 是内容资源中台服务P4 阶段),承载 D4 内容资源限界上下文,提供 Textbook / Chapter / KnowledgePoint / Question 四个聚合的 CRUD 与知识图谱查询。

关键交付

  • gRPC 50054 + 4 ServiceTextbook/Chapter/KnowledgeGraph/Questioncoord-final-decisions.md §3.3 N1/N3/N5 仲裁P4 首次实现即启用 gRPC + 补全 QuestionService/ChapterService proto
  • MySQL 写模型 + Neo4j 知识图谱 + Outbox 事件驱动异步同步(禁止业务事务内同步双写 Neo4j
  • Kafka 发布 4 个聚合 topicARB-005 §5.3 裁决):edu.content.textbook.events / edu.content.chapter.events / edu.content.knowledge_point.events / edu.content.question.events
  • P5 引入 Elasticsearch 全文检索 + AI 出题入库QuestionService.BatchCreateQuestions
  • P6+ 长远演进:教材版本管理 / 跨租户内容共享 / 个性化学习路径推荐

关键路径位置:批次 3P4依赖批次 2 core-edu 完成实际可并行content 不强依赖 core-edu

当前进度 P4 全部完成14/14 任务P5/P6+ 未开始


§2 全阶段甘特图P4-P6

gantt
    title ai09 content 全阶段排期P4-P6
    dateFormat YYYY-MM-DD
    axisFormat %m-%d

    section P4 基础设施
    P4.1 schema 迁移补字段 :crit, c4a, 2026-07-19, 2d
    P4.2 Outbox 表+Publisher worker :crit, c4b, after c4a, 3d
    P4.3 Kafka producer(idempotent+txn) :crit, c4c, after c4b, 2d
    P4.4 Neo4j Sync Worker(异步) :crit, c4d, after c4c, 2d
    P4.5 重构 kp.service 移除同步双写 :crit, c4e, after c4d, 1d

    section P4 gRPC 契约
    P4.6 content.proto 补 ChapterService/QuestionService :crit, c4f, 2026-07-19, 1d
    P4.7 gRPC controller 实现(4 Service) :crit, c4g, after c4f, 4d
    P4.8 buf generate + 类型校验 :c4h, after c4g, 1d

    section P4 横切与质量
    P4.9 /readyz 多依赖(DB/Neo4j/Kafka) :c4i, after c4e, 1d
    P4.10 ZodError GlobalErrorFilter 分支 :c4j, after c4i, 1d
    P4.11 DB 改 getDb()+ID 改 cuid2 :c4k, after c4j, 1d
    P4.12 Repository 抽象补齐 :c4l, after c4k, 2d
    P4.13 单元测试(Service/Repository)≥60% :c4m, after c4l, 3d
    P4.14 修正 README 与实现对齐 :c4n, after c4m, 1d

    section P5 ES+AI 集成
    P5.1 引入 @elastic/elasticsearch :crit, c5a, after c4m, 1d
    P5.2 ES mapping+ensureIndex :crit, c5b, after c5a, 1d
    P5.3 ES Sync Worker(消费事件同步索引) :crit, c5c, after c5b, 2d
    P5.4 GET /questions/search 检索 API :crit, c5d, after c5c, 2d
    P5.5 QuestionService gRPC 完善Publish/Search :c5e, after c5d, 1d
    P5.6 AI 出题 BatchCreateQuestions 联调 :c5f, after c5e, 2d
    P5.7 检索性能优化(<200ms) :c5g, after c5f, 2d
    P5.8 测试覆盖率≥80% :c5h, after c5g, 2d

    section P6+ 演进
    P6.1 Question 审核工作流状态机 :c6a, after c5h, 3d
    P6.2 知识图谱可视化 API :c6b, after c6a, 3d
    P6.3 教材版本管理 :c6c, after c6b, 2d
    P6.4 /readyz 硬化+监控告警完善 :c6d, after c6c, 2d

预估总工期P4 约 21 天 + P5 约 13 天 + P6+ 约 10 天 = 44 天(与 workline.md §1 批次 3+4 时间窗口一致)


§3 详细任务

3.1 P4 阶段任务

P4.1 schema 迁移补字段

  • 负责人ai09
  • 依赖:无(自身 schema 现状)
  • 交付物
    • textbooks.schema.ts textbooks 表补 status / tenant_id / metadata 字段
    • chapters 表补 created_at / updated_at / status(解决 01-understanding.md C7
    • knowledge_points 表补 difficulty / metadata / created_at / updated_at(解决 ISSUE-009
    • questions 表补 status / source / created_byNULL 起步,解决 ISSUE-007/ metadata
  • 验收标准pnpm typecheck 通过Drizzle 类型重新生成;迁移脚本可幂等执行

P4.2 Outbox 表 + Publisher worker

  • 负责人ai09
  • 依赖P4.1
  • 交付物
    • 新建 src/shared/outbox/outbox.schema.tscontent_outbox_events 表,见 design doc §3.1.5
    • 新建 src/shared/outbox/outbox.publisher.ts(轮询 PENDING 事件投递 Kafka指数退避重试
    • 新建 src/shared/outbox/outbox.module.ts
  • 验收标准:业务事务内写 questions + outbox 同事务提交Publisher worker 独立轮询retry_count 累加正确

P4.3 Kafka produceridempotent + transactionalId

  • 负责人ai09
  • 依赖P4.2
  • 交付物
    • 新建 src/shared/kafka/producer.tskafkajs 客户端idempotent=truetransactionalId=content-producer
    • 新建 src/shared/kafka/kafka.module.ts
    • package.json 添加 kafkajs 依赖
  • 验收标准producer 启动成功transactionalId 唯一;幂等投递无重复

P4.4 Neo4j Sync Worker异步同步

  • 负责人ai09
  • 依赖P4.3
  • 交付物
    • 新建 src/shared/sync/neo4j-sync.worker.ts(消费 content 自身 Outbox 事件,异步创建/更新 Neo4j 节点与关系)
    • 消费 KnowledgePointCreated / KnowledgePointPrerequisiteAdded 等事件
  • 验收标准MySQL 写知识点后Neo4j 节点最终一致出现(延迟 < 2sNeo4j 故障时事件不丢失,恢复后补齐

P4.5 重构 knowledge-points.service.ts 移除同步双写

  • 负责人ai09
  • 依赖P4.4
  • 交付物
    • knowledge-points.service.ts 删除 safeCreateNode 同步写 Neo4j 逻辑
    • 改为发 Outbox 事件 KnowledgePointCreated
    • addPrerequisite 改为发 Outbox 事件 KnowledgePointPrerequisiteAdded
  • 验收标准:业务事务内不再直接写 Neo4jNeo4j 写入全部走异步 Sync Worker解决 ISSUE-010 + 01-understanding C9

P4.6 content.proto 补 ChapterService / QuestionService

  • 负责人ai09
  • 依赖:无(自身 proto 现状)
  • 交付物
    • content.proto 补 ChapterServiceCreateChapter/ListChapters/GetChapter/UpdateChapter/DeleteChapter
    • 补 QuestionServiceCreateQuestion/BatchCreateQuestions/GetQuestion/ListQuestions/UpdateQuestion/DeleteQuestion/PublishQuestion/SearchQuestions
    • 补 TextbookService.UpdateTextbook / DeleteTextbook
    • 补全 message 定义Chapter / Question / QuestionRequest 等)
    • 同步补 events.proto 的 KnowledgePointEvent / QuestionEvent / TextbookEvent / ChapterEvent待 ISSUE-002 仲裁后定)
  • 验收标准buf lint 通过;buf breaking 无破坏性变更(新增字段 OKcontract.md 与 design doc §4.2 RPC 数对齐

P4.7 gRPC controller 实现4 Service

  • 负责人ai09
  • 依赖P4.6
  • 交付物
    • 新建 src/textbooks/textbooks.grpc.controller.ts
    • 新建 src/chapters/chapters.grpc.controller.ts
    • 新建 src/knowledge-points/knowledge-points.grpc.controller.ts
    • 新建 src/questions/questions.grpc.controller.ts
    • main.ts 启用 gRPC server 50054
  • 验收标准grpcurl 调用 4 Service 全部 RPC 返回正确HealthService.Check 返回 SERVING解决 N1

P4.8 buf generate + 类型校验

  • 负责人ai09
  • 依赖P4.7
  • 交付物pnpm buf:generate 生成 TS 类型content 服务引用生成类型
  • 验收标准pnpm typecheck 通过

P4.9 /readyz 多依赖检查

  • 负责人ai09
  • 依赖P4.5
  • 交付物health.controller.ts 改造 /readyz检查 DB / Neo4j / Kafka producer / Kafka consumer lag
  • 验收标准:返回 design doc §6.6 格式Neo4j 不可用 → status=degradedDB 不可用 → status=down解决 N2 + 01-understanding C-section readyz 问题)

P4.10 ZodError GlobalErrorFilter 分支

  • 负责人ai09
  • 依赖:无
  • 交付物global-error.filter.ts 增加 ZodError 识别分支,返回 400 + 字段级错误详情
  • 验收标准Zod 校验失败返回 design doc §4.3 错误结构

P4.11 DB 改 getDb() + ID 改 cuid2

  • 负责人ai09
  • 依赖:无
  • 交付物
    • database.ts 改为 getDb() 函数式懒加载(对齐 classes 黄金模板)
    • service 层 randomUUID() 改为 cuid2()package.json 添加 @paralleldrive/cuid2
  • 验收标准:所有 service 使用 getDb();所有 ID 生成用 cuid2

P4.12 Repository 抽象补齐

  • 负责人ai09
  • 依赖P4.11
  • 交付物:补齐 textbooks/questions 的 Repository 抽象(与 chapters/knowledge-points 一致)
  • 验收标准Service 层不直接调用 Drizzle API全部走 Repository

P4.13 单元测试 ≥ 60%

  • 负责人ai09
  • 依赖P4.12
  • 交付物
    • 新建 *.spec.ts 覆盖 Service 层 + Repository 层
    • 重点覆盖 QuestionsService 题型校验 / KnowledgePointsService 前置依赖 / Outbox Publisher 重试逻辑
  • 验收标准pnpm test 通过;覆盖率 ≥ 60%

P4.14 修正 README 与实现对齐

  • 负责人ai09
  • 依赖P4.13
  • 交付物README.md 修正 TextbooksService.createKnowledgeGraph 错误描述(实际在 KnowledgePointsService补齐 4 个领域模块说明
  • 验收标准README 与源码完全一致(解决 01-understanding C3

3.2 P5 阶段任务

P5.1 引入 @elastic/elasticsearch

  • 负责人ai09
  • 依赖P4 全部完成
  • 交付物package.json 添加 @elastic/elasticsearch新建 src/config/elasticsearch.ts
  • 验收标准esClient 单例ES_URL 未配置时 esClient=null 降级

P5.2 ES mapping + ensureIndex

  • 负责人ai09
  • 依赖P5.1
  • 交付物:按 design doc §3.3.1 实现 questions 索引 mapping启动时 ensureIndex 幂等
  • 验收标准索引创建成功ik_max_word / ik_smart 分词器配置正确

P5.3 ES Sync Worker

  • 负责人ai09
  • 依赖P5.2
  • 交付物:新建 src/shared/sync/es-sync.worker.ts,消费 QuestionCreated / QuestionUpdated / QuestionPublished / QuestionDeleted 事件增量更新索引
  • 验收标准MySQL 写题目后ES 索引最终一致(延迟 < 2s

P5.4 GET /questions/search 检索 API

  • 负责人ai09
  • 依赖P5.3
  • 交付物questions.controller.ts 增加 @Get("search") 端点ES 查询支持 q / type / difficulty / knowledgePointId 过滤
  • 验收标准:检索延迟 < 200msP5 退出标准);返回分页结构

P5.5 QuestionService gRPC 完善 Publish/Search

  • 负责人ai09
  • 依赖P5.4
  • 交付物gRPC controller 补 PublishQuestion / SearchQuestions RPC 实现
  • 验收标准:与 contract.md §1.1 完全对齐(解决 ISSUE-004 部分)

P5.6 AI 出题 BatchCreateQuestions 联调

  • 负责人ai09
  • 依赖P5.5 + ai12 ai 服务就绪
  • 交付物:与 ai12 联调 BatchCreateQuestions RPC服务账号权限校验
  • 验收标准AI 服务调用成功入库batch_size ≤ 100 限制生效

P5.7 检索性能优化

  • 负责人ai09
  • 依赖P5.6
  • 交付物ES 查询 DSL 优化缓存热点查询结果Redis
  • 验收标准P95 延迟 < 200ms

P5.8 测试覆盖率 ≥ 80%

  • 负责人ai09
  • 依赖P5.7
  • 交付物补集成测试gRPC + ES + Neo4j 端到端)
  • 验收标准:覆盖率 ≥ 80%

3.3 P6+ 演进任务

P6.1 Question 审核工作流状态机

  • 负责人ai09
  • 依赖P5 完成
  • 交付物Question.status 状态机完整实现draft → pending_review → published/rejected → archived审核日志表
  • 验收标准:状态转换校验正确;非法转换返回 409

P6.2 知识图谱可视化 API

  • 负责人ai09
  • 依赖P6.1
  • 交付物GET /knowledge-graph/visualization 返回 nodes/edges 结构(解决 01-understanding L3
  • 验收标准:返回 D3.js / vis.js 可消费的图结构

P6.3 教材版本管理

  • 负责人ai09
  • 依赖P6.2
  • 交付物Textbook.version 字段启用;版本切换不破坏题库引用
  • 验收标准:新旧版本教材并存;题库引用按版本隔离

P6.4 /readyz 硬化 + 监控告警完善

  • 负责人ai09
  • 依赖P6.3
  • 交付物/readyz 探针列表完善Prometheus 告警规则补齐consumer lag / outbox pending / ES latency
  • 验收标准:告警阈值合理;故障演练通过

§4 依赖与就绪信号

4.1 我依赖的上游就绪标志

上游 就绪标志 必需性 mock 策略
infra MySQL 8 / Neo4j 5 / Kafka 集群可用 🔴 必需 本地 docker-compose
infra Redis 可用P5+ 缓存用env.ts 已预留 REDIS_URL 🟢 P5+ 可选 未配置时跳过缓存
infra Elasticsearch 8 可用P5+ 🟢 P5+ 必需 未配置时检索降级到 MySQL LIKE
shared-proto content.proto / events.proto 补全 🔴 必需P4.6 自身完成) 自行修改
core-edu (ai08) gRPC 50053 启用 🟢 可选content 独立) 不依赖 core-edu 实时数据
ai (ai12) gRPC 50058 启用 🟢 P5 联调时必需 grpc-mock 拦截

4.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/chapter/knowledge_point/question 4 topic 可发布
    • /readyz 返回 DB/Neo4j/Kafka 三依赖状态
  • P5 就绪
    • GET /questions/search 检索 API 可用(延迟 < 200ms
    • QuestionService.SearchQuestions gRPC 可调用
    • BatchCreateQuestions 与 ai12 联调通过
  • P6+ 就绪
    • 审核工作流状态机完整
    • 知识图谱可视化 API 可用

4.3 我提供的 mock供下游消费

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

  • gRPC mockgrpc-mock 拦截 50054 端口):
    • TextbookService.ListTextbooks 返回固定 5 个 Textbook语数英理化
    • ChapterService.ListChapters 返回固定章节树(每教材 10 章)
    • KnowledgeGraphService.GetLearningPath 返回固定 8 个 KnowledgePoint 推荐顺序
    • KnowledgeGraphService.GetPrerequisites 返回固定 3 个前置知识点
    • QuestionService.SearchQuestions 返回固定 20 个 Question含 options
    • QuestionService.BatchCreateQuestions 返回成功 + 生成 20 个 ID
  • Kafka mockcontent 就绪前不发布真实事件,下游使用本地 stub

§5 风险与缓解

风险 阶段 缓解措施
ISSUE-002 topic 策略未仲裁导致 Outbox 阻塞 P4 优先推动 coord 仲裁;开发期间用 stub topic仲裁后切换
ISSUE-004 RPC 数量未仲裁导致 proto 阻塞 P4 优先推动 coord 仲裁;按建议方案 21 RPC 实现,仲裁后调整
Neo4j 与 MySQL 双向一致性 P4 Outbox 事件驱动 + 幂等去重 + consumer lag 监控
ES 索引重建期间检索不可用 P5 alias 切换模式(双索引蓝绿)
AI 批量出题 CreateQuestions 高并发 P5 batch_size ≤ 100 + 异步队列 + 限流
schema 迁移期间历史数据 created_by 缺失 P4 按 ISSUE-007 方案NULL 起步或 'system' 默认值回填

§6 与 workline.md §1 对齐

  • 批次 3P4ai09 content 11 天workline.md §1 排期 after b2b, 11d
  • 本排期 P4 实际 21 天(含测试 + README 修正),与 workline.md 11 天存在差距
  • 更新2026-07-13P4 代码已全部完成并提交至 main 分支ARB-005 全部 10 项 issue 已裁决并落实
  • 差距原因workline.md §1 为 coord 初始规划(标注"ai09 接管后必须自行细化"),本文件为 ai09 细化后的实际排期
  • 同步动作:提请 coord 在 workline.md §1 更新 content 工期为 21 天(或协调压缩测试任务)