# data-ana 对接契约 > 负责人:ai11 > 关联:[matrix.md](../matrix.md)、[coord-cross-review.md](../../coord-cross-review.md)、[analytics.proto](../../../packages/shared-proto/proto/analytics.proto)、[events.proto](../../../packages/shared-proto/proto/events.proto)、[iam.proto](../../../packages/shared-proto/proto/iam.proto) > 对齐文档:[01-understanding.md](../../../services/data-ana/docs/01-understanding.md)、[02-architecture-design.md](../../../services/data-ana/docs/02-architecture-design.md)、[objections/data-ana_issue.md](../objections/data-ana_issue.md)、[worklines/data-ana_workline.md](../worklines/data-ana_workline.md) > 修订:v2(2026-07-10 by ai11)—— 修正 topic 命名 / gRPC 调用声明 / HTTP 端点声明 / 引用断裂,对齐 01/02 v2.1 --- ## §1 我提供什么(对外接口) ### 1.1 gRPC 接口 | Service | RPC | 请求 | 响应 | 端口 | | ---------------- | ---------------------- | ----------------------------- | ------------------------- | ----- | | AnalyticsService | GetClassPerformance | GetClassPerformanceRequest | ClassPerformance | 50055 | | AnalyticsService | GetStudentWeakness | GetStudentWeaknessRequest | StudentWeakness | 50055 | | AnalyticsService | GetLearningTrend | GetLearningTrendRequest | LearningTrend | 50055 | | AnalyticsService | GetTeacherDashboard | GetTeacherDashboardRequest | TeacherDashboard | 50055 | | AnalyticsService | GetStudentDashboard | GetStudentDashboardRequest | StudentDashboard | 50055 | | AnalyticsService | GetParentDashboard | GetParentDashboardRequest | ParentDashboard | 50055 | | AnalyticsService | GetAdminDashboard | GetAdminDashboardRequest | AdminDashboard | 50055 | | AnalyticsService | GetWarnings | GetWarningsRequest | WarningList | 50055 | | AnalyticsService | TriggerWarning | TriggerWarningRequest | TriggerWarningResponse | 50055 | | AnalyticsService | GetMasteryDistribution | GetMasteryDistributionRequest | MasteryDistribution | 50055 | | AnalyticsService | GetStudentMastery | GetStudentMasteryRequest | StudentMastery | 50055 | | AnalyticsService | SubscribeMasteryUpdate | SubscribeMasteryUpdateRequest | stream MasteryUpdateEvent | 50055 | > **proto 状态**:analytics.proto 当前仅 3 RPC(GetClassPerformance / GetStudentWeakness / GetLearningTrend),扩展至 12 RPC 待 coord 补全或 ai11 在 P4 阶段自行补全(见 [ISSUE-003](../objections/data-ana_issue.md))。完整 message 定义见 [02-architecture-design.md §4.2](../../../services/data-ana/docs/02-architecture-design.md)。 > **gRPC 启用阶段**:P4 启用(coord-cross-review.md §2.3 裁决),P2-P3 仅 HTTP。 > **响应信封**:所有 RPC 返回 ActionState[T](coord-cross-review.md §5.3 P0 整改)。 ### 1.2 HTTP 端点 data-ana 保留 HTTP :3006 端点作 Gateway 直连降级(gRPC 不可用时 BFF 可走 HTTP)。共 14 端点(3 基础 + 11 业务): | method | path | 权限 | 响应 | | ------ | -------------------------------------------- | ----------------------------- | ----------------------------------- | | GET | `/healthz` | — | `{status, service}` | | GET | `/readyz` | — | `{status, ready, degraded, clickhouse, cdc_consumer, redis, iam_grpc}` | | GET | `/metrics` | — | Prometheus 格式 | | GET | `/analytics/class/{class_id}/performance` | `ANALYTICS_CLASS_READ` | `ActionState` | | GET | `/analytics/student/{student_id}/weakness` | `ANALYTICS_STUDENT_READ` | `ActionState` | | GET | `/analytics/student/{student_id}/errorbook` | `ANALYTICS_STUDENT_READ` | `ActionState` | | GET | `/analytics/student/{student_id}/trend` | `ANALYTICS_STUDENT_READ` | `ActionState` | | GET | `/analytics/student/{student_id}/attendance` | `ANALYTICS_STUDENT_READ` | `ActionState` | | GET | `/analytics/dashboard/teacher/{user_id}` | `ANALYTICS_TEACHER_DASHBOARD` | `ActionState` | | GET | `/analytics/dashboard/student/{user_id}` | `ANALYTICS_STUDENT_DASHBOARD` | `ActionState` | | GET | `/analytics/dashboard/parent/{user_id}` | `ANALYTICS_PARENT_DASHBOARD` | `ActionState` | | GET | `/analytics/dashboard/admin/{user_id}` | `ANALYTICS_ADMIN_DASHBOARD` | `ActionState` | | GET | `/analytics/warnings` | `ANALYTICS_WARNING_READ` | `ActionState` | | GET | `/analytics/mastery/distribution` | `ANALYTICS_CLASS_READ` | `ActionState` | > 完整端点设计见 [02-architecture-design.md §4.1](../../../services/data-ana/docs/02-architecture-design.md)。 ### 1.3 GraphQL schema(如 BFF) 不适用。data-ana 是业务服务,不提供 GraphQL。BFF 层(teacher-bff / student-bff / parent-bff)聚合 data-ana gRPC 后对外暴露 GraphQL。 ### 1.4 Kafka 事件发布 | Topic | Event | 消费方 | Outbox | 说明 | | -------------------------------- | --------------- | ------------------------------- | ------ | ---- | | `edu.insight.mastery.updated` | MasteryUpdated | core-edu(推荐个性化练习)/ msg | ❌ 豁免 | 掌握度计算完成触发 | | `edu.insight.warning.triggered` | WarningTriggered | msg(推送通知)/ core-edu(标记关注) | ❌ 豁免 | 预警阈值触发 | > **Outbox 豁免**:派生数据事件(非业务事务写),豁免 Outbox 约束([coord-cross-review.md §3.3](../../coord-cross-review.md) 已仲裁)。直接用 aiokafka AIOKafkaProducer 发布,`idempotent=true` + `transactional_id="data-ana-producer"`。 > > **topic 命名说明**:按 004 §7.2 命名规范 `edu...`,data-ana 属于 D6 智能洞察领域(domain=insight),故 `edu.insight.mastery.updated` 符合规范。matrix.md §4 中 `edu.analytics.mastery` 命名不符合规范(缺 action 层级,domain 用了服务名而非领域名),已提请 coord 统一(见 [ISSUE-005](../objections/data-ana_issue.md))。 ### 1.5 错误码前缀 `DATA_ANA_`(如 DATA_ANA_DASHBOARD_UNAVAILABLE、DATA_ANA_MASTERY_NOT_COMPUTED、DATA_ANA_CLICKHOUSE_UNAVAILABLE) > 来源:[matrix.md §6](../matrix.md) 错误码前缀矩阵。 ### 1.6 ClickHouse 宽表(供 coord 统一管理 DDL) | 宽表名 | 用途 | 引擎 | | ------------------------- | -------------------- | ----------------------------- | | student_dashboard_view | 学生学情宽表 | ReplacingMergeTree(last_updated) | | student_errors | 学生错题本 | ReplacingMergeTree(last_error_time) | | mastery_snapshot | 知识点掌握度历史快照 | MergeTree | | attendance_logs | 学生考勤记录 | ReplacingMergeTree(occurred_at) | | ai_usage_log | AI 用量计费记录 | ReplacingMergeTree(occurred_at) | > DDL 由 coord 统一管理在 `infra/clickhouse/ddl/`(待 coord 建立),data-ana 提供内容。完整 DDL 见 [02-architecture-design.md §3](../../../services/data-ana/docs/02-architecture-design.md)。 --- ## §2 我消费什么(依赖上游) ### 2.1 gRPC 调用(同步) | 调用方 | 被调用方 | RPC | 用途 | 端口 | 阶段 | 状态 | | -------- | -------- | ------------------------- | ---------------------------- | ----- | ---- | ---- | | data-ana | iam | GetEffectiveDataScope | DataScope 6 级过滤解析 | 50052 | P4 | ⚠️ iam.proto 当前未实现(ISSUE-001) | > **降级兜底**:iam GetEffectiveDataScope 未就绪时,data-ana 按 role 映射默认 DataScope(教师=CLASS,学生=SELF,管理员=SCHOOL),标注 `details.degraded: true`。结果 Redis 缓存 5min(key: `data_ana:datascope:{user_id}`)。 > > **裁决依据**:coord-cross-review.md §2.2 #3 已仲裁 iam P4 补全此 RPC。 ### 2.2 Kafka 事件订阅(异步) | Topic | Event | 发布方 | mock 策略 | | -------------------------------------- | ------------------- | --------------- | ------------------------------------------------- | | `edu.teaching.exam.published` | ExamEvent | core-edu (ai08) | core-edu 就绪前使用 CDC 模拟数据 + 本地 stub 事件 | | `edu.teaching.homework.assigned` | HomeworkEvent | core-edu (ai08) | 同上 | | `edu.teaching.grade.recorded` | GradeEvent | core-edu (ai08) | 同上 | | `edu.teaching.class.transferred` | ClassEvent | core-edu (ai08) | 同上 | | `edu.content.kp.events` | KnowledgePointEvent | content (ai09) | content 就绪前使用内置知识点维度表 | | `edu.content.question.events` | QuestionEvent | content (ai09) | content 就绪前忽略 | | `edu.insight.ai.usage` | AIUsageEvent | ai (ai12) | ai 就绪前忽略,AI 用量统计为空(P5) | > **topic 命名对齐**:core-edu 教学事件 topic 按 coord-cross-review.md §3.1 裁决统一为 `edu.teaching..` 风格。core-edu 代码实际发布 `edu.exam.events` 等,待 core-edu 整改后切换。 > > **AIUsageEvent 缺失**:events.proto 当前缺 AIUsageEvent message(ISSUE-002),P5 前需 coord 补全。 ### 2.3 HTTP 调用(如有) 无。data-ana 不通过 HTTP 调用上游服务。 ### 2.4 CDC 数据源 | 数据源 | 用途 | mock 策略 | | ----------------------------------------------------- | ------------------------------- | --------------------------------------------------------------------------- | | core-edu MySQL(exams/homework/grades/attendance 表) | Debezium CDC → Kafka 同步读模型 | core-edu 就绪前使用 ClickHouse 内置模拟数据集(30 学生 × 5 考试 × 10 作业) | | content MySQL(knowledge_points 表) | Debezium CDC → 知识点元数据同步 | content 就绪前使用内置固定知识点表(数学 50 个知识点) | | iam MySQL(users 表) | Debezium CDC → 用户 dataScope 同步 | iam 就绪前使用硬编码 DataScope 降级 | > **CDC topic 命名**:`edu-cdc.next_edu_cloud.`(coord-cross-review.md §3.2 裁决补登 CDC topic 命名规范段,待 coord 在 004 §7.2 落实)。 --- ## §3 就绪信号 ### 3.1 我依赖的上游就绪标志 - [ ] core-edu gRPC 50053 启用(ai08)—— 业务事件 + CDC 数据源 - [ ] core-edu MySQL Debezium CDC 配置(ai08 + SRE)—— CDC 通道前提 - [ ] `edu.teaching.exam.published` / `edu.teaching.homework.assigned` / `edu.teaching.grade.recorded` / `edu.teaching.class.transferred` topic 有事件发布(ai08) - [ ] content gRPC 50054 启用(ai09)—— 知识点维度 CDC - [ ] `edu.content.kp.events` topic 有事件发布(ai09) - [ ] iam.proto 补全 GetEffectiveDataScope RPC(ai06/coord,ISSUE-001)—— P4 阻塞项 - [ ] analytics.proto 扩展至 12 RPC(coord/ai11,ISSUE-003)—— gRPC stub 生成前提 - [ ] events.proto 补全 AIUsageEvent message(coord,ISSUE-002)—— P5 前补全 - [ ] ai gRPC 50057 启用(ai12)—— AI 用量统计(P5,可选) ### 3.2 我的就绪标志(供下游消费) - [ ] **P4 就绪**:data-ana gRPC 50055 启用(HealthService.Check 返回 SERVING) - [ ] **P4 就绪**:AnalyticsService 12 RPC 可调用(含 4 端 Dashboard + Warning + Mastery + Server Streaming SubscribeMasteryUpdate) - [ ] **P4 就绪**:GetTeacherDashboard / GetStudentDashboard / GetParentDashboard / GetAdminDashboard 返回结构化数据 - [ ] **P4 就绪**:`edu.insight.mastery.updated` topic 可发布(mastery.updated / warning.triggered) - [ ] **P5 就绪**:SubscribeMasteryUpdate server-streaming RPC 可订阅 - [ ] **P6 就绪**:CDC 多实例水平扩展 + ExamCache Redis 化完成 --- ## §4 Mock 策略 ### 4.1 我提供的 mock 在 data-ana 真实服务就绪前,为下游(teacher-bff / student-bff / parent-bff / admin-portal / msg)提供以下 mock: - **gRPC mock**:使用 grpc-mock 拦截 50055 端口 - GetTeacherDashboard 返回固定仪表盘(total_classes=3, class_avg_score=82.5, top_students 5 个, pending_homework_count=8) - GetStudentDashboard 返回固定仪表盘(avg_score=85.0, class_rank=5, weak_points 3 个) - GetParentDashboard 返回固定仪表盘(child_avg_score=85.0, child_class_rank=5) - GetAdminDashboard 返回固定仪表盘(total_teachers=50, total_students=1200, school_avg_score=80.0) - GetWarnings 返回固定 5 条预警(severity: warning/critical) - GetMasteryDistribution 返回固定分布(mastered=20, progressing=7, weak=3) - SubscribeMasteryUpdate 返回固定流(每 5 秒推 1 个 MasteryUpdateEvent) - **Kafka mock**:data-ana 就绪前不发布真实 MasteryUpdated / WarningTriggered,msg 使用本地 stub 预警 ### 4.2 我消费的 mock 在真实上游就绪前,data-ana 使用以下 mock: - **业务数据**:ClickHouse 内置模拟数据集(30 学生 × 5 考试 × 10 作业 × 30 天出勤),不依赖 core-edu CDC - **知识点维度**:内置固定知识点表(数学 50 个知识点),不依赖 content 事件 - **AI 用量**:AIUsageEvent 为空,仪表盘 AI 用量区块显示"暂无数据" - **CDC 通道**:core-edu 就绪前 Debezium 不启动,使用 ClickHouse 批量导入模拟数据 - **DataScope**:iam GetEffectiveDataScope 未就绪前,按 role 映射默认 DataScope 降级(教师=CLASS,学生=SELF,管理员=SCHOOL),标注 `details.degraded: true`