25 KiB
模块理解确认书 — data-ana
AI 标识:ai11(v2 由 ai11 审核 ai06 v1 后修订) 负责模块:data-ana(P4) 语言:Python 3.12+ / FastAPI 0.115+ 阶段:架构设计外包 · 阶段 1(全局理解)v2 审核版 日期:2026-07-09(v1 by ai06)/ 2026-07-10(v2 审核修订 by ai11) 关联文档:ai-allocation.md、004 架构影响地图、pending-features.md、known-issues.md 审核修订说明:ai-allocation.md §3.2 将 data-ana 重新分配给 ai11(ai 单独分配给 ai12),ai11 接手后对 ai06 v1 进行审核,本版为 v2 修订。 v2.1 审核修订(ai11):核查发现多处 004 章节引用断裂(§4.2/§11.4/§11.5/§15.3 在 004 正文中不存在,coord-cross-review §6 整改清单要求 coord 补充但尚未落实),已改为引用 coord-cross-review.md 对应裁决;修正 topic 命名统一为
edu.insight.mastery.updated;补充 events.proto AIUsageEvent 缺失说明。
阶段 1 必读清单完成确认
按 ai-allocation.md §4,ai11 必读 7 份全局文档 + 全部 .proto + services/data-ana/ 骨架源码:
| # | 文档 | 状态 |
|---|---|---|
| 1 | README.md | ✅ 已读 |
| 2 | MIGRATION_GUIDE.md | ✅ 已读 |
| 3 | 004 架构影响地图 | ✅ 已读(v2 重点核对 §1.2/§4.2/§7.2/§11.5/§12.2/§15.3 已仲裁项) |
| 4 | pending-features.md | ✅ 已读 |
| 5 | project_rules.md | ✅ 已读(workspace 规则) |
| 6 | coding-standards.md | ✅ 已读(重点 §4 Python 规范) |
| 7 | multi-ai-collaboration.md | ✅ 已读 |
| 8 | packages/shared-proto/proto/*.proto(8 份,重点 analytics.proto + events.proto) |
✅ 已读 |
| 9 | services/data-ana/src/ 全部源码(main/config/cdc_consumer/clickhouse_client) |
✅ 已读 |
ai11 不需要读 classes 黄金模板(ai-allocation.md §4 矩阵 ai11 列对黄金模板行为 "—"),但审计表横切关注点对齐仍参考 classes 标准。
1. 我在架构中的位置
- 层级:业务微服务层(L5),属 D6 智能洞察领域(004 §1.1b)
- 上游:
- api-gateway 直接 HTTP 代理
/api/v1/analytics/*→ data-ana:3006(见 api-gateway main.go:142-148) - teacher-bff / student-bff / parent-bff 聚合查询(004 §4.1 + §4.2:BFF → 业务服务 gRPC,P4 启用 gRPC)
- ai 服务通过 gRPC 反查学情数据(004 §4.1:AI → DataAna gRPC,AI 出题编排时调
GetStudentWeakness/GetLearningTrend)
- api-gateway 直接 HTTP 代理
- 下游:
- ClickHouse(独占读模型,宽表
student_dashboard_view/student_errors/mastery_snapshot/ai_usage_log) - Redis(DataScope 缓存 5min + 预警去重位图 + CDC 幂等去重 SETNX,004 §6.3 缓存策略矩阵)
- Kafka(消费 Debezium CDC 事件 + 发布
edu.insight.mastery.updated派生数据事件) - iam gRPC(调
GetEffectiveDataScope解析数据范围,已仲裁 P4 补全,见 coord-cross-review.md §2 #3)
- ClickHouse(独占读模型,宽表
- 通信方式:
- 入口:HTTP(
/analytics/*,保留作 Gateway 直连降级)+ gRPCAnalyticsService(P4 启用主入口,BFF 调用) - 出口:Kafka 消费(CDC 主通道 + 领域事件订阅备通道);Kafka 发布(
edu.insight.mastery.updated,未实现,属派生数据豁免 Outbox,见 coord-cross-review.md §3.3 + 004 §12.2)
- 入口:HTTP(
- 端口:HTTP=3006(见 data-ana config.py:7 + api-gateway config.go:55);gRPC=50055(coord-cross-review.md §4.3 全局端口矩阵 + matrix.md §2:P4 启用)
2. 我的限界上下文
- 聚合职责:学情分析读模型构建 + 查询服务,承载 D6 智能洞察领域的"分析/诊断"子域
- 聚合根 / 实体(视图型聚合根,ClickHouse 物化):
StudentDashboard(学生学情宽表视图,ClickHouse 物化)StudentErrorBook(学生错题本,ClickHouse 物化)ClassPerformance(班级成绩聚合,ClickHouse 即时聚合,不物化)MasterySnapshot(知识点掌握度快照,待实现,含历史版本支持趋势查询)AiUsageLog(AI 用量记录,消费 ai 服务edu.insight.ai.usage事件落库,供计费/分析用)AttendanceLog(出勤日志宽表,消费 core-edu CDCcore_edu_attendance,待实现,对应 ai-allocation §5 五张宽表之一)
- 业务领域:D6 智能洞察(与 ai 服务共享领域,ai 偏"生成",data-ana 偏"分析")
- 我不负责:
- 不负责写模型(成绩由 core-edu 写 MySQL,data-ana 只消费 CDC)
- 不负责题库内容(→ content 服务,但消费 content 知识点变更事件用于掌握度维度同步,见 §7)
- 不负责通知投递(→ msg 服务消费 data-ana 发布的
mastery.updated事件触发预警) - 不负责 AI 推理(→ ai 服务,ai 通过 gRPC 反向查询 data-ana 学情数据)
- 不负责双轨读的"实时查主库"侧(BFF 层负责双轨读,data-ana 仅是"聚合查宽表"侧,见 pending-features P4 交付物)
- 数据自治:独占
edu_analyticsClickHouse 数据库(不与 MySQL 写模型混用);可选 Redis(与全局共享实例,键名加data_ana:前缀)
3. 我与外部的契约
消费的 proto message
双通道说明:当前实现走 Debezium CDC(直接监听 MySQL binlog),不消费 events.proto 领域事件。这是 ADR-008 的设计决策。下表"领域事件"为未来双消费备通道(待 P4 后期评估是否启用),CDC 才是当前主通道。
| 来源 | message | 通道状态 | 用途 |
|---|---|---|---|
| events.proto | GradeEvent |
备通道(未消费) | 未来双消费:core-edu 成绩写入事件 → 更新学情宽表 |
| events.proto | ExamEvent |
备通道(未消费) | 未来双消费:考试事件 → 缓存 exam_id→class_id 映射 |
| events.proto | HomeworkEvent |
备通道(未消费) | 未来双消费:作业提交/批改事件 → 更新学情 |
| events.proto | ClassEvent |
备通道(未消费) | 未来双消费:班级变更事件 → 同步班级维度 |
| analytics.proto | GetClassPerformanceRequest 等 |
自身暴露契约(待实现 gRPC server) | P4 启用 gRPC=50055 后暴露 AnalyticsService |
| iam.proto | GetEffectiveDataScopeRequest(待 coord 在 iam.proto 新增,coord-cross-review.md §2 #3 已裁决 P4 补全;当前 iam.proto 仅有 4 RPC,无此 RPC,P4 阻塞项) |
调用契约 | gRPC 调 iam 解析 DataScope,结果 Redis 缓存 5min |
暴露的 API / 事件
HTTP 端点(当前实现,见 main.py;保留作 Gateway 直连降级):
| method | path | 说明 |
|---|---|---|
| GET | /healthz |
liveness |
| GET | /readyz |
readiness(含 ClickHouse + CDC + Redis 状态) |
| GET | /metrics |
Prometheus 指标 |
| GET | /analytics/class/{class_id}/performance |
班级成绩分析(平均分/及格率/参考人数) |
| GET | /analytics/student/{student_id}/weakness |
学生薄弱知识点(mastery < 0.6) |
| GET | /analytics/student/{student_id}/errorbook |
学生错题本 |
响应信封约束:以上 HTTP 端点当前实现为
{success, data, degraded}结构,违反统一响应信封 ActionState(coord-cross-review.md §5.3 已裁决 Python 服务必须改 ActionState,degraded 作为details.degraded子字段)。阶段 2 设计已对齐(见 02-architecture-design.md §4.3)。
gRPC 契约(analytics.proto,P4 启用 server,端口 50055):
GetClassPerformance(GetClassPerformanceRequest) → ClassPerformanceGetStudentWeakness(GetStudentWeaknessRequest) → StudentWeaknessGetLearningTrend(GetLearningTrendRequest) → LearningTrend(当前 HTTP 未暴露)
proto 扩展提案(待 coord 在 shared-proto 新增,见 02-architecture-design.md §4.4):
GetTeacherDashboard/GetStudentDashboard/GetParentDashboard/GetSchoolDashboard:四端 Dashboard 聚合(ai-allocation §5 要求)GetClassWarningList/GetStudentWarningList:预警查询GetMasteryDistribution:掌握度分布stream SubscribeMasteryUpdate:实时掌握度推送(P5+ 演进,供 BFF SSE 透传)
发布的领域事件:
| 事件 | Topic(004 §7.2) | 触发时机 | 消费者(004 §7.3) | Outbox 合规性 |
|---|---|---|---|---|
MasteryUpdated |
edu.insight.mastery.updated |
掌握度计算完成 | core-edu(推荐个性化练习)、msg(预警) | 豁免 Outbox(派生数据,见 coord-cross-review.md §3.3 + 004 §12.2) |
当前未实现发布:data-ana 当前只消费不发布。掌握度计算完成后通过
aiokafka.AIOKafkaProducer直接发布(已豁免 Outbox,coord-cross-review.md §3.3 仲裁结论),下游 core-edu / msg 消费。失败重试 3 次仍失败落mastery_publish_failed本地表。
Topic 命名一致性:本模块统一使用
edu.insight.mastery.updated(与 004 §7.2 + matrix.md §4 对齐)。contract.md 早期版本写edu.data_ana.mastery.events,已在 v2.1 修正。
- 错误码前缀:
DATA_ANA_*(matrix.md §6 错误码前缀矩阵已登记,清单见阶段 2 §6.2) - 缓存:Redis(DataScope 缓存 5min 事件驱动失效 / CDC event_id 幂等去重 SETNX TTL 7d / 预警去重位图);学情宽表走 ClickHouse 实时,CDC 同步延迟 < 5s
4. 我的技术栈
- 语言:Python 3.12+
- 框架:FastAPI 0.115+ / uvicorn
- ORM / 客户端:
clickhouse-connect(HTTP 协议,非原生协议)redis-py[asyncio](待引入,DataScope 缓存 + 幂等去重 + 预警位图)grpc.aio+betterproto(待引入,P4 启用 gRPC server + 调 iam gRPC)
- 消息:
aiokafka(CDC 消费者 AIOKafkaConsumer + 掌握度发布 AIOKafkaProducer) - 配置:
pydantic-settingsBaseSettings(env_prefix="",全大写环境变量) - 可观测:
- 日志:
structlog24.x(make_filtering_bound_logger,注意:旧版make_filtering_logger已废弃;生产改 JSONRenderer) - 指标:
prometheus-client+make_asgi_app()挂载/metrics - 链路:
opentelemetry-sdk+OTLPSpanExporter+FastAPIInstrumentor.instrument_app(app)+grpc.aioserver interceptor(待引入)
- 日志:
- 序列化:JSON(Debezium 事件
schemas.enable=false,直接json.loads)+ protobuf(gRPC) - 测试:pytest + pytest-asyncio + Testcontainers(ClickHouse + Kafka + Redis 真实依赖,当前 0% 覆盖率,目标 ≥ 80%)
- 容器:Dockerfile 多阶段(builder 用
uv sync --frozen,runtime 用python:3.12-slim拷贝.venv,当前单阶段待改造)
5. 我的阶段归属
- P4 内容分析阶段(M11-M13):建 DataAna 服务 + CDC 链路落地
- 退出标准(pending-features P4):学生查看学情诊断 ClickHouse 宽表 5s 内返回 + CDC 链路延迟 < 5s
- 交付物(pending-features P4):DataAna 学情诊断宽表 5s 内返回 + CDC 链路延迟 < 5s + 双轨读策略落地(实时查主库 + 聚合查宽表) + CDC 模式回写黄金模板 README + 打 tag
v0.4.0-p4 - 依赖上游:
- P1 地基:api-gateway 路由 + arch.db 扫描器 Python 支持
- P2 身份:iam
GetEffectiveDataScopegRPC(已仲裁 P4 补全,见 coord-cross-review.md §2 #3;当前 iam.proto 未实现,P4 阻塞项) - P3 核心教学:core-edu 写成绩到 MySQL(Debezium 监听 binlog)+ Outbox 领域事件(备通道)
- P4 同期:content 服务(提供知识点 ID 供掌握度计算,content → data-ana 事件流见 004 §4 服务依赖图)
- 下游依赖我:
- P5 ai 服务通过 gRPC 查询学情数据(004 §4.1:AI → DataAna gRPC)+ 投递
edu.insight.ai.usage用量事件 - P5 msg 服务消费
mastery.updated触发预警
- P5 ai 服务通过 gRPC 查询学情数据(004 §4.1:AI → DataAna gRPC)+ 投递
- 未来阶段演进铺垫(长远性):
- P5:消费
edu.insight.ai.usage落 ai_usage_log;gRPCSubscribeMasteryUpdatestream RPC 供 BFF SSE 透传 - P6:CDC 消费者水平扩展(多实例 + 分区重平衡 + ExamCache Redis 化);ClickHouse 容量规划 + TTL;数据治理(GDPR 删除权);Service Mesh mTLS
- P5:消费
6. 我需要对齐的黄金模板项(对照 classes 服务 + Python 规范)
Python 服务无 NestJS 装饰器体系,权限校验等通过等价方式实现。
- 权限装饰器等价物:当前 HTTP 端点全部裸露,无权限校验。Gateway 层做 JWT 校验,但 data-ana 本身未校验
x-user-id/ DataScope。阶段 2 需设计 FastAPI Depends 权限依赖 + DataScope 过滤注入 - 错误码前缀统一:当前无错误码体系,降级时返回
degraded: true标记但无业务错误码。阶段 2 需定义DATA_ANA_*错误码清单(matrix.md §6 已登记前缀) - 响应信封对齐 ActionState(coord-cross-review.md §5.3 已裁决 P0 整改):当前
{success, data, degraded}偏离结构,须改为{success: true, data: T}/{success: false, error: {code, message, details?, traceId?}},degraded 作为details.degraded子字段 - logger / metrics / tracer 三支柱(已具备,见 main.py + clickhouse_client.py;生产改 JSONRenderer)
/healthz+/readyz健康检查(已具备,readyz 含 ClickHouse ping + CDC 状态;待补 Redis + iam gRPC 连通性检查)- 优雅关闭 SIGTERM:当前 lifespan 仅关闭 CDC task + ClickHouse client,未注册 SIGTERM 信号处理器显式 drain。阶段 2 设计顺序:HTTP stop → gRPC graceful stop 30s → CDC commit offset → Kafka producer flush → ClickHouse close → iam channel close
- 测试覆盖率 ≥ 80%:当前 0%,无 tests/ 目录。阶段 2 设计测试策略:pytest 单元 + pytest-asyncio + Testcontainers(ClickHouse + Kafka + Redis)
- Dockerfile 多阶段构建:当前单阶段(
FROM python:3.12-slim→uv sync→COPY src),非多阶段 - Pydantic 输入验证:当前端点直接接收 path param,无 Pydantic 请求模型校验(应补
ClassPerformanceResponse等 response_model) - 配置通过 pydantic-settings 管理(已具备;待补 Redis / gRPC / 限流 / 降级开关 / feature flags 配置项,见阶段 2 §6.9)
- 异步优先(async def,aiokafka async consumer)
- 类型注解强制:部分函数缺返回值标注(如
init_logger返回BoundLogger但_logger全局变量标注None,需统一) - ruff check 零错误:需阶段 2 验证
- CDC 幂等性加强:当前依赖 ReplacingMergeTree,查询未加
FINAL/argMax,可能读到重复版本(阶段 2 §3.1 修复) - CDC 水平扩展:当前 ExamCache 为内存缓存,多实例部署不同步,阶段 2 §5.3 设计 Redis 化方案
- 数据治理(长远性):GDPR 删除权在 ClickHouse 的实现(mutations 或分区删除)、脱敏字段、审计日志(阶段 2 §10)
服务审计表 — ai11(data-ana,v2 修订)
对照 ai-allocation.md §10 审计模板。data-ana 为 Python/FastAPI,黄金模板对齐按 Python 规范(coding-standards §4)评估。 符号说明:✅ 已实现 | ❌ 缺失 | ⚠️ 部分实现
| 服务 | 权限校验 | 错误码前缀 | 响应信封 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile | Redis | gRPC server |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| data-ana | ❌ | ❌ | ❌(偏离 ActionState) | ✅ structlog | ✅ prometheus | ✅ OTel | ✅ | ⚠️(含 CH+CDC,缺 Redis/iam) | ⚠️ 仅 lifespan 关闭 | 0% | ❌ 单阶段 | ❌ | ❌(P4 待启用 50055) |
审计发现的关键差距(按优先级,v2 修订)
- P0 权限校验缺失:所有
/analytics/*端点裸露,无 DataScope 过滤。学生 A 可查询学生 B 的错题本(越权风险)。阶段 2 必须设计Depends(require_permission)+Depends(inject_data_scope)依赖注入 - P0 响应信封偏离 ActionState(004 §11.5 已仲裁 P0 整改,v2 新增):当前
{success, data, degraded}必须改为 ActionState,degraded 作为details.degraded子字段 - P0 gRPC server 未实现(004 §4.2 P4 启用):analytics.proto 定义了
AnalyticsService但 data-ana 当前仅 HTTP。阶段 2 需引入grpc.aio+betterproto实现 gRPC server,端口 50055 - P1 事件发布缺失:
edu.insight.mastery.updated事件未发布(已豁免 Outbox,004 §15.3 #6 仲裁),下游 core-edu/msg 无法消费。需设计掌握度计算 + Kafka producer 直接发布链路 - P1 ClickHouse schema 不规范:当前
student_dashboard_view实为 MergeTree 表,应为 ReplacingMergeTree(last_updated);查询未加 FINAL/argMax 可能读重复版本。无 DDL 文件管理。阶段 2 需产出完整 ClickHouse DDL(5 张宽表:考试/作业/成绩/掌握度/出勤,对应 ai-allocation §5 要求) - P1 掌握度计算算法缺失:当前
_handle_grades_event用score / 100.0简化,未实现 pending-features 要求的"加权滑动平均 + 遗忘曲线"。阶段 2 §9 给出具体公式 - P1 Dashboard API 不完整(ai-allocation §5 要求):当前仅 3 个查询端点,缺教师/学生/家长/校管理 4 端 Dashboard 聚合 API
- P1 预警阈值设计缺失(ai-allocation §5 要求):未设计预警阈值配置 API 与触发逻辑
- P2 测试覆盖率 0%:无 tests/ 目录,pytest 未配置
- P2 Dockerfile 单阶段:未做多阶段构建(builder + runtime),镜像体积大
- P2 无 Pydantic 响应模型:端点返回
dict而非BaseModel,无response_model校验 - P2 CDC 水平扩展缺失:ExamCache 内存缓存多实例不同步;缺消费者 group_id / 分区重平衡设计
- P2 缓存策略缺失:未引入 Redis,缺 DataScope 缓存 / CDC 幂等去重 / 预警位图
- P2 content 服务交互缺失:004 §4 服务依赖图显示 content → data-ana 事件流,当前未消费 content 知识点变更事件
- P2 数据治理缺失(长远性):GDPR 删除权、脱敏、审计日志未设计
- P2 ClickHouse 容量规划缺失:5 张宽表年增量估算 + TTL + 冷热分层未设计
coord 交叉审查结论对齐(v2 修订,原 v1 标题"待 coord 交叉审查的跨模块契约对齐项")
v1 提请的 5 项跨模块契约对齐项,coord 已在 coord-cross-review.md 完成仲裁。本节 v2.1 改为"对齐状态",并标注落实情况。
| # | 议题(v1 提请) | coord 裁决结论(coord-cross-review.md) | data-ana 文档对齐状态(v2.1) |
|---|---|---|---|
| 1 | data-ana 是否发布 edu.insight.mastery.updated 事件 |
§3.3:派生数据事件豁免 Outbox,允许直接 Kafka producer | ✅ v2 已对齐:§3 标注"豁免 Outbox",阶段 2 §5.2 设计直接 producer 链路 |
| 2 | data-ana / ai 是否需要实现 gRPC server | §2.1:P4 content + data-ana 启用 gRPC | ✅ v2 已对齐:§1 标注"gRPC=50055 P4 启用",阶段 2 §1 分层图含 grpc.aio Server |
| 3 | CDC 直连 vs Outbox 领域事件双通道 | §3.3 + ADR-008:维持 CDC 为主通道;events.proto 作为业务语义补充,待 P4 后期评估是否双消费 | ✅ v2 已对齐:§3 双通道说明 + 标注"领域事件为备通道" |
| 4 | data-ana DataScope 过滤实现位置 | §2 #3:iam 新增 GetEffectiveDataScope gRPC RPC(P4 补全);data-ana 在 ClickHouse 查询 SQL 拼接时注入 WHERE |
✅ v2 已对齐:§3 列出 iam.proto 调用契约;阶段 2 §6.1 设计 inject_data_scope Depends |
| 5 | data-ana ClickHouse DDL 管理位置 | §4:采纳 infra/clickhouse/ddl/(coord 建立),data-ana 提供 DDL 内容 |
✅ v2 已对齐:阶段 2 §3 标注"DDL 文件由 coord 统一管理在 infra/clickhouse/ddl/" |
| 6 | 新增 edu.insight.ai.usage topic(v1 阶段 2 §8.3 #3 提请) |
§3.2:补登,见 004 §7.2;events.proto AIUsageEvent message 待 coord 补充 | ✅ v2 已对齐:阶段 2 §5.1 列出消费此 topic;⚠️ events.proto 缺 AIUsageEvent 定义 |
| 7 | iam GetEffectiveDataScope proto 新增(v1 阶段 2 §8.3 #2 提请) | §2 #3:P4 补全;当前 iam.proto 仅 4 RPC,未实现,P4 阻塞项 | ✅ v2 已对齐:§3 列出 iam.proto 调用契约;⚠️ iam.proto 未实现 |
v1 §8.3 "未决设计决策"3 项全部已被 coord 仲裁,v2 不再列为"未决"。文档后续修订如发现新冲突,按 ai-allocation.md §9.4 proto 变更流程提请 coord。
AI Agent: ai11 (data-ana) — v2 审核修订自 ai06 v1 Branch: 单仓库并行模式(直接提交 main) Coordinator: coord-ai v1 作者: ai06(原同时负责 data-ana + ai,ai-allocation §3.2 v2 重新分配后 data-ana → ai11 / ai → ai12)