# 模块理解确认书 — 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](../../../docs/architecture/ai-allocation.md)、[004 架构影响地图](../../../docs/architecture/004_architecture_impact_map.md)、[pending-features.md](../../../docs/architecture/roadmap/pending-features.md)、[known-issues.md](../../../docs/troubleshooting/known-issues.md) > 审核修订说明:ai-allocation.md §3.2 将 data-ana 重新分配给 ai11(ai 单独分配给 ai12),ai11 接手后对 ai06 v1 进行审核,本版为 v2 修订。 --- ## 阶段 1 必读清单完成确认 按 ai-allocation.md §4,ai11 必读 7 份全局文档 + 全部 `.proto` + `services/data-ana/` 骨架源码: | # | 文档 | 状态 | | --- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | 1 | [README.md](../../../README.md) | ✅ 已读 | | 2 | [MIGRATION_GUIDE.md](../../../MIGRATION_GUIDE.md) | ✅ 已读 | | 3 | [004 架构影响地图](../../../docs/architecture/004_architecture_impact_map.md) | ✅ 已读(v2 重点核对 §1.2/§4.2/§7.2/§11.5/§12.2/§15.3 已仲裁项) | | 4 | [pending-features.md](../../../docs/architecture/roadmap/pending-features.md) | ✅ 已读 | | 5 | [project_rules.md](../../../.trae/rules/project_rules.md) | ✅ 已读(workspace 规则) | | 6 | [coding-standards.md](../../../docs/standards/coding-standards.md) | ✅ 已读(重点 §4 Python 规范) | | 7 | [multi-ai-collaboration.md](../../../docs/standards/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](../../api-gateway/main.go)) - 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`) - **下游**: - 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 补全,见 004 §15.3 #5) - **通信方式**: - 入口:HTTP(`/analytics/*`,保留作 Gateway 直连降级)+ **gRPC** `AnalyticsService`(P4 启用主入口,BFF 调用) - 出口:Kafka 消费(CDC 主通道 + 领域事件订阅备通道);Kafka 发布(`edu.insight.mastery.updated`,**未实现**,属派生数据豁免 Outbox,见 004 §12.2) - **端口**:HTTP=3006(见 [data-ana config.py:7](../src/data_ana/config.py) + [api-gateway config.go:55](../../api-gateway/internal/config/config.go));**gRPC=50055**(004 §1.2 服务清单 + §4.2 gRPC 启用阶段矩阵:P4 启用) ## 2. 我的限界上下文 - **聚合职责**:学情分析读模型构建 + 查询服务,承载 **D6 智能洞察领域**的"分析/诊断"子域 - **聚合根 / 实体**(视图型聚合根,ClickHouse 物化): - `StudentDashboard`(学生学情宽表视图,ClickHouse 物化) - `StudentErrorBook`(学生错题本,ClickHouse 物化) - `ClassPerformance`(班级成绩聚合,ClickHouse 即时聚合,不物化) - `MasterySnapshot`(知识点掌握度快照,**待实现**,含历史版本支持趋势查询) - `AiUsageLog`(AI 用量记录,消费 ai 服务 `edu.insight.ai.usage` 事件落库,供计费/分析用) - `AttendanceLog`(出勤日志宽表,消费 core-edu CDC `core_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_analytics` ClickHouse 数据库(不与 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 新增**,004 §15.3 #5 已裁决 P4 补全) | 调用契约 | gRPC 调 iam 解析 DataScope,结果 Redis 缓存 5min | ### 暴露的 API / 事件 **HTTP 端点**(当前实现,见 [main.py](../src/data_ana/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}` 结构,违反 004 §11.5 统一响应信封 ActionState(Python 服务必须改 ActionState,degraded 作为 `details.degraded` 子字段)。阶段 2 设计已对齐(见 02-architecture-design.md §4.3)。 **gRPC 契约**(analytics.proto,P4 启用 server,端口 50055): - `GetClassPerformance(GetClassPerformanceRequest) → ClassPerformance` - `GetStudentWeakness(GetStudentWeaknessRequest) → StudentWeakness` - `GetLearningTrend(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**(派生数据,见 004 §12.2 + §15.3 #6 已仲裁) | > **当前未实现发布**:data-ana 当前只消费不发布。掌握度计算完成后通过 `aiokafka.AIOKafkaProducer` 直接发布(已豁免 Outbox,004 §15.3 #6 仲裁结论),下游 core-edu / msg 消费。失败重试 3 次仍失败落 `mastery_publish_failed` 本地表。 - **错误码前缀**:`DATA_ANA_*`(004 §11.4 错误码前缀矩阵已登记,清单见阶段 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-settings` BaseSettings(env_prefix="",全大写环境变量) - 可观测: - 日志:`structlog` 24.x(`make_filtering_bound_logger`,**注意**:旧版 `make_filtering_logger` 已废弃;生产改 JSONRenderer) - 指标:`prometheus-client` + `make_asgi_app()` 挂载 `/metrics` - 链路:`opentelemetry-sdk` + `OTLPSpanExporter` + `FastAPIInstrumentor.instrument_app(app)` + `grpc.aio` server 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 `GetEffectiveDataScope` gRPC(已仲裁 P4 补全,见 004 §15.3 #5) - 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:消费 `edu.insight.ai.usage` 落 ai_usage_log;gRPC `SubscribeMasteryUpdate` stream RPC 供 BFF SSE 透传 - P6:CDC 消费者水平扩展(多实例 + 分区重平衡 + ExamCache Redis 化);ClickHouse 容量规划 + TTL;数据治理(GDPR 删除权);Service Mesh mTLS ## 6. 我需要对齐的黄金模板项(对照 classes 服务 + Python 规范) > Python 服务无 NestJS 装饰器体系,权限校验等通过等价方式实现。 - [ ] 权限装饰器等价物:**当前 HTTP 端点全部裸露,无权限校验**。Gateway 层做 JWT 校验,但 data-ana 本身未校验 `x-user-id` / DataScope。**阶段 2 需设计 FastAPI Depends 权限依赖 + DataScope 过滤注入** - [ ] 错误码前缀统一:**当前无错误码体系**,降级时返回 `degraded: true` 标记但无业务错误码。**阶段 2 需定义 `DATA_ANA_*` 错误码清单**(004 §11.4 已登记前缀) - [ ] **响应信封对齐 ActionState**(004 §11.5 已仲裁 P0 整改):当前 `{success, data, degraded}` 偏离结构,须改为 `{success: true, data: T}` / `{success: false, error: {code, message, details?, traceId?}}`,degraded 作为 `details.degraded` 子字段 - [x] logger / metrics / tracer 三支柱(已具备,见 main.py + clickhouse_client.py;生产改 JSONRenderer) - [x] `/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) - [x] 配置通过 pydantic-settings 管理(已具备;**待补 Redis / gRPC / 限流 / 降级开关 / feature flags 配置项**,见阶段 2 §6.9) - [x] 异步优先(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 修订) 1. **P0 权限校验缺失**:所有 `/analytics/*` 端点裸露,无 DataScope 过滤。学生 A 可查询学生 B 的错题本(越权风险)。阶段 2 必须设计 `Depends(require_permission)` + `Depends(inject_data_scope)` 依赖注入 2. **P0 响应信封偏离 ActionState**(004 §11.5 已仲裁 P0 整改,v2 新增):当前 `{success, data, degraded}` 必须改为 ActionState,degraded 作为 `details.degraded` 子字段 3. **P0 gRPC server 未实现**(004 §4.2 P4 启用):analytics.proto 定义了 `AnalyticsService` 但 data-ana 当前仅 HTTP。阶段 2 需引入 `grpc.aio` + `betterproto` 实现 gRPC server,端口 50055 4. **P1 事件发布缺失**:`edu.insight.mastery.updated` 事件未发布(已豁免 Outbox,004 §15.3 #6 仲裁),下游 core-edu/msg 无法消费。需设计掌握度计算 + Kafka producer 直接发布链路 5. **P1 ClickHouse schema 不规范**:当前 `student_dashboard_view` 实为 MergeTree 表,应为 ReplacingMergeTree(last_updated);查询未加 FINAL/argMax 可能读重复版本。无 DDL 文件管理。阶段 2 需产出完整 ClickHouse DDL(5 张宽表:考试/作业/成绩/掌握度/出勤,对应 ai-allocation §5 要求) 6. **P1 掌握度计算算法缺失**:当前 `_handle_grades_event` 用 `score / 100.0` 简化,未实现 pending-features 要求的"加权滑动平均 + 遗忘曲线"。阶段 2 §9 给出具体公式 7. **P1 Dashboard API 不完整**(ai-allocation §5 要求):当前仅 3 个查询端点,缺教师/学生/家长/校管理 4 端 Dashboard 聚合 API 8. **P1 预警阈值设计缺失**(ai-allocation §5 要求):未设计预警阈值配置 API 与触发逻辑 9. **P2 测试覆盖率 0%**:无 tests/ 目录,pytest 未配置 10. **P2 Dockerfile 单阶段**:未做多阶段构建(builder + runtime),镜像体积大 11. **P2 无 Pydantic 响应模型**:端点返回 `dict` 而非 `BaseModel`,无 `response_model` 校验 12. **P2 CDC 水平扩展缺失**:ExamCache 内存缓存多实例不同步;缺消费者 group_id / 分区重平衡设计 13. **P2 缓存策略缺失**:未引入 Redis,缺 DataScope 缓存 / CDC 幂等去重 / 预警位图 14. **P2 content 服务交互缺失**:004 §4 服务依赖图显示 content → data-ana 事件流,当前未消费 content 知识点变更事件 15. **P2 数据治理缺失**(长远性):GDPR 删除权、脱敏、审计日志未设计 16. **P2 ClickHouse 容量规划缺失**:5 张宽表年增量估算 + TTL + 冷热分层未设计 --- ## coord 交叉审查结论对齐(v2 修订,原 v1 标题"待 coord 交叉审查的跨模块契约对齐项") > v1 提请的 5 项跨模块契约对齐项,coord 已在 [coord-cross-review.md](../../../docs/architecture/coord-cross-review.md) 完成仲裁,裁决结论中涉及架构设计意图的部分已沉淀到 004 对应章节(004 §15.3 共性问题 #1-#7)。本节 v2 改为"对齐状态"。 | # | 议题(v1 提请) | coord 裁决结论(004 §15.3) | data-ana 文档对齐状态(v2) | | --- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | 1 | **data-ana 是否发布 `edu.insight.mastery.updated` 事件** | §15.3 #6:派生数据事件豁免 Outbox,允许直接 Kafka producer | ✅ v2 已对齐:§3 标注"豁免 Outbox",阶段 2 §5.2 设计直接 producer 链路 | | 2 | **data-ana / ai 是否需要实现 gRPC server** | §4.2 gRPC 启用阶段矩阵:P4 content + data-ana 启用 | ✅ v2 已对齐:§1 标注"gRPC=50055 P4 启用",阶段 2 §1 分层图含 grpc.aio Server | | 3 | **CDC 直连 vs Outbox 领域事件双通道** | §15.3 #6 + ADR-008:维持 CDC 为主通道;events.proto 作为业务语义补充,待 P4 后期评估是否双消费 | ✅ v2 已对齐:§3 双通道说明 + 标注"领域事件为备通道" | | 4 | **data-ana DataScope 过滤实现位置** | §15.3 #5: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 管理位置** | §15.3 #7:采纳 `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 提请) | §15.3 #4:补登,见 004 §7.2 | ✅ v2 已对齐:阶段 2 §5.1 列出消费此 topic | | 7 | **iam GetEffectiveDataScope proto 新增**(v1 阶段 2 §8.3 #2 提请) | §15.3 #5:P4 补全 | ✅ v2 已对齐:§3 列出 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)