Files
Edu/docs/architecture/issues/contracts/data-ana_contract.md

185 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
> 修订v22026-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 RPCGetClassPerformance / 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<ClassPerformanceData>` |
| GET | `/analytics/student/{student_id}/weakness` | `ANALYTICS_STUDENT_READ` | `ActionState<StudentWeaknessData>` |
| GET | `/analytics/student/{student_id}/errorbook` | `ANALYTICS_STUDENT_READ` | `ActionState<StudentErrorBookData>` |
| GET | `/analytics/student/{student_id}/trend` | `ANALYTICS_STUDENT_READ` | `ActionState<LearningTrendData>` |
| GET | `/analytics/student/{student_id}/attendance` | `ANALYTICS_STUDENT_READ` | `ActionState<AttendanceData>` |
| GET | `/analytics/dashboard/teacher/{user_id}` | `ANALYTICS_TEACHER_DASHBOARD` | `ActionState<TeacherDashboardData>` |
| GET | `/analytics/dashboard/student/{user_id}` | `ANALYTICS_STUDENT_DASHBOARD` | `ActionState<StudentDashboardData>` |
| GET | `/analytics/dashboard/parent/{user_id}` | `ANALYTICS_PARENT_DASHBOARD` | `ActionState<ParentDashboardData>` |
| GET | `/analytics/dashboard/admin/{user_id}` | `ANALYTICS_ADMIN_DASHBOARD` | `ActionState<AdminDashboardData>` |
| GET | `/analytics/warnings` | `ANALYTICS_WARNING_READ` | `ActionState<WarningListData>` |
| GET | `/analytics/mastery/distribution` | `ANALYTICS_CLASS_READ` | `ActionState<MasteryDistributionData>` |
> 完整端点设计见 [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.<domain>.<aggregate>.<action>`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 缓存 5minkey: `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.<aggregate>.<action>` 风格。core-edu 代码实际发布 `edu.exam.events` 等,待 core-edu 整改后切换。
>
> **AIUsageEvent 缺失**events.proto 当前缺 AIUsageEvent messageISSUE-002P5 前需 coord 补全。
### 2.3 HTTP 调用(如有)
无。data-ana 不通过 HTTP 调用上游服务。
### 2.4 CDC 数据源
| 数据源 | 用途 | mock 策略 |
| ----------------------------------------------------- | ------------------------------- | --------------------------------------------------------------------------- |
| core-edu MySQLexams/homework/grades/attendance 表) | Debezium CDC → Kafka 同步读模型 | core-edu 就绪前使用 ClickHouse 内置模拟数据集30 学生 × 5 考试 × 10 作业) |
| content MySQLknowledge_points 表) | Debezium CDC → 知识点元数据同步 | content 就绪前使用内置固定知识点表(数学 50 个知识点) |
| iam MySQLusers 表) | Debezium CDC → 用户 dataScope 同步 | iam 就绪前使用硬编码 DataScope 降级 |
> **CDC topic 命名**`edu-cdc.next_edu_cloud.<table>`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 RPCai06/coordISSUE-001—— P4 阻塞项
- [ ] analytics.proto 扩展至 12 RPCcoord/ai11ISSUE-003—— gRPC stub 生成前提
- [ ] events.proto 补全 AIUsageEvent messagecoordISSUE-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 / WarningTriggeredmsg 使用本地 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`