From 033057a3025d5d37719d1b5bf257f38a748402ed Mon Sep 17 00:00:00 2001 From: SpecialX <47072643+wangxiner55@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:05:37 +0800 Subject: [PATCH] feat: auto committed --- .../issues/contracts/data-ana_contract.md | 139 ++++++-- .../issues/objections/data-ana_issue.md | 131 ++++++- .../issues/worklines/data-ana_workline.md | 333 +++++++++++++++++- services/data-ana/docs/01-understanding.md | 43 +-- .../data-ana/docs/02-architecture-design.md | 83 +++-- 5 files changed, 612 insertions(+), 117 deletions(-) diff --git a/docs/architecture/issues/contracts/data-ana_contract.md b/docs/architecture/issues/contracts/data-ana_contract.md index ba769ff..7206252 100644 --- a/docs/architecture/issues/contracts/data-ana_contract.md +++ b/docs/architecture/issues/contracts/data-ana_contract.md @@ -1,13 +1,15 @@ # data-ana 对接契约 > 负责人:ai11 -> 关联:[matrix.md](./matrix.md)、[analytics.proto](../../../packages/shared-proto/proto/analytics.proto)、[events.proto](../../../packages/shared-proto/proto/events.proto) +> 关联:[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 接口(如有) +### 1.1 gRPC 接口 | Service | RPC | 请求 | 响应 | 端口 | | ---------------- | ---------------------- | ----------------------------- | ------------------------- | ----- | @@ -18,31 +20,71 @@ | AnalyticsService | GetStudentDashboard | GetStudentDashboardRequest | StudentDashboard | 50055 | | AnalyticsService | GetParentDashboard | GetParentDashboardRequest | ParentDashboard | 50055 | | AnalyticsService | GetAdminDashboard | GetAdminDashboardRequest | AdminDashboard | 50055 | -| AnalyticsService | GetWarningList | GetWarningListRequest | WarningListResponse | 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 | -### 1.2 HTTP 端点(如有) +> **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 整改)。 -无对外 HTTP 端点,仅 gRPC(含 1 个 Server Streaming RPC)。 +### 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 事件发布(如有) +### 1.4 Kafka 事件发布 -| Topic | Event | 消费方 | -| --------------------------- | --------------------------------------------------------- | -------------- | -| edu.data_ana.mastery.events | MasteryEvent(action: mastery.updated/warning.triggered) | core-edu / msg | +| Topic | Event | 消费方 | Outbox | 说明 | +| -------------------------------- | --------------- | ------------------------------- | ------ | ---- | +| `edu.insight.mastery.updated` | MasteryUpdated | core-edu(推荐个性化练习)/ msg | ❌ 豁免 | 掌握度计算完成触发 | +| `edu.insight.warning.triggered` | WarningTriggered | msg(推送通知)/ core-edu(标记关注) | ❌ 豁免 | 预警阈值触发 | -> 注:MasteryEvent 豁免 Outbox 模式(派生数据事件,见 004 §12.2 + §15.3 #6)。 +> **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_`(如 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)。 --- @@ -50,29 +92,43 @@ ### 2.1 gRPC 调用(同步) -无主动 gRPC 调用上游。data-ana 通过 CDC + Kafka 事件接收数据,计算后发布 MasteryEvent。 +| 调用方 | 被调用方 | 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.exam.events | ExamEvent | core-edu (ai08) | core-edu 就绪前使用 CDC 模拟数据 + 本地 stub 事件 | -| edu.homework.events | HomeworkEvent | core-edu (ai08) | 同上 | -| edu.grade.events | GradeEvent | core-edu (ai08) | 同上 | -| edu.class.events | ClassEvent | core-edu (ai08) | 同上 | -| edu.content.knowledge_point.events | KnowledgePointEvent | content (ai09) | content 就绪前使用内置知识点维度表 | -| edu.content.question.events | QuestionEvent | content (ai09) | content 就绪前忽略 | -| edu.ai.usage.events | AIUsageEvent | ai (ai12) | ai 就绪前忽略,AI 用量统计为空 | +| 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 数据源(补充) +### 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 落实)。 --- @@ -81,17 +137,23 @@ ### 3.1 我依赖的上游就绪标志 - [ ] core-edu gRPC 50053 启用(ai08)—— 业务事件 + CDC 数据源 -- [ ] edu.exam.events / edu.homework.events / edu.grade.events / edu.class.events topic 有事件发布(ai08) -- [ ] content gRPC 50054 启用(ai09)—— 知识点维度 -- [ ] edu.content.knowledge_point.events topic 有事件发布(ai09) -- [ ] ai gRPC 50057 启用(ai12)—— AI 用量统计(可选,仪表盘补全) +- [ ] 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 我的就绪标志(供下游消费) -- [ ] data-ana gRPC 50055 启用(HealthService.Check 返回 SERVING) -- [ ] AnalyticsService 12 RPC 可调用(含 4 端 Dashboard + Server Streaming SubscribeMasteryUpdate) -- [ ] GetTeacherDashboard / GetStudentDashboard / GetParentDashboard / GetAdminDashboard 返回结构化数据 -- [ ] edu.data_ana.mastery.events topic 可发布(mastery.updated / warning.triggered) +- [ ] **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 化完成 --- @@ -106,16 +168,17 @@ - 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) - - GetWarningList 返回固定 5 条预警(severity: warning/critical) + - GetWarnings 返回固定 5 条预警(severity: warning/critical) - GetMasteryDistribution 返回固定分布(mastered=20, progressing=7, weak=3) - SubscribeMasteryUpdate 返回固定流(每 5 秒推 1 个 MasteryUpdateEvent) -- **Kafka mock**:data-ana 就绪前不发布真实 MasteryEvent,msg 使用本地 stub 预警 +- **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 批量导入模拟数据 +- **业务数据**: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` diff --git a/docs/architecture/issues/objections/data-ana_issue.md b/docs/architecture/issues/objections/data-ana_issue.md index 2ee03b1..27e4ca6 100644 --- a/docs/architecture/issues/objections/data-ana_issue.md +++ b/docs/architecture/issues/objections/data-ana_issue.md @@ -1,24 +1,129 @@ # data-ana 问题记录 > 负责人:ai11 -> 关联:[coord.md](../coord.md)、[contracts/data-ana_contract.md](../contracts/data-ana_contract.md) +> 关联:[coord.md](../coord.md)、[coord-cross-review.md](../../coord-cross-review.md)、[contracts/data-ana_contract.md](../contracts/data-ana_contract.md) > 规则:AI 遇到问题时在此追加条目,coord 仲裁后更新状态 --- -## 问题列表 +## §0 已有仲裁核查记录(2026-07-10) - +| 编号 | 主题 | 涉及 data-ana | 核查结论 | +| ------- | ---------------------------- | ------------- | ------------------------------ | +| ARB-001 | teacher-bff GraphQL schema | ❌ 否 | 不涉及,无需 action | +| ARB-002 | MF Shell 暴露清单 | ❌ 否 | 不涉及,无需 action | -(暂无问题) +**结论**:coord.md 无 data-ana 直接仲裁。 + +### 0.2 coord-cross-review.md 仲裁核查(8 项涉及 data-ana) + +| # | 审查章节 | 裁决内容 | 责任方 | 核查结论 | +| -- | ---------------- | ------------------------------------------------------------------ | ------ | ---------------------------------------------------------------------------------------------------- | +| 1 | §2.2 #3 | iam 新增 `GetEffectiveDataScope` RPC,P4 补全,data-ana gRPC 调用 | iam | ⚠️ **未落实**:iam.proto 当前仅 4 RPC(Register/Login/RefreshToken/GetUserInfo),无 GetEffectiveDataScope | +| 2 | §2.3 P4 行 | content + data-ana P4 启用 gRPC server | ai11 | ⏳ 未到 P4 阶段,待执行 | +| 3 | §3.2 | 补登 `edu.insight.ai.usage` topic + events.proto 补 AIUsageEvent | coord | ⚠️ **未落实**:events.proto 当前仅 4 message(Class/Exam/Homework/GradeEvent),缺 AIUsageEvent | +| 4 | §3.3 | Python 服务 Outbox 豁免(MasteryUpdated / WarningTriggered) | coord | ✅ **已对齐**:01/02 文档已声明豁免,引用 coord-cross-review.md §3.3 | +| 5 | §4.3 | data-ana HTTP=3006 / gRPC=50055 | coord | ✅ **已对齐**:01/02 文档端口声明一致 | +| 6 | §5.3 | Python 服务信封改为 ActionState(degraded 放 details 子字段) | ai11 | ✅ **已对齐**:02 §4.3 ActionState 实现已修正,degraded 移至顶层 details | +| 7 | §6 #4 | 同 #6,ai06 修正 data-ana/ai 02 文档 + 代码 | ai11 | ✅ **已对齐(文档)**:02 已修正;代码待 P4 实现阶段重构 | +| 8 | §6 #7/#8/#9/#10 | coord 在 004 §7.2 补登 topic + §1.2 端口列 + §4.1 gRPC 矩阵 + §12.2 豁免 | coord | ⚠️ **未落实**:004 正文无 §4.2/§7.2 补登段/§11.4/§11.5,01/02 引用断裂已临时改为引 coord-cross-review.md | + +### 0.3 coord-cross-review §8.2 批次 0 产出声明核查 + +coord-cross-review.md §8.2 声称批次 0 已完成 proto 补全,ai11 逐文件核查实际状态: + +| 声明产出项 | 声明状态 | 实际文件状态(ai11 核查) | 核查结论 | +| -------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------- | ------------ | +| iam.proto 12 RPC | ✅ 12 RPC | **4 RPC**(Register/Login/RefreshToken/GetUserInfo) | ⚠️ 严重不符 | +| analytics.proto 扩展 | ✅ 12 RPC(含 Stream) | **3 RPC**(GetClassPerformance/GetStudentWeakness/GetLearningTrend) | ⚠️ 严重不符 | +| events.proto 补全 | ✅ 9 message(+AuditEvent) | **4 message**(ClassEvent/ExamEvent/HomeworkEvent/GradeEvent) | ⚠️ 严重不符 | +| core_edu.proto 补全 | ✅ 5 service | 未由 ai11 核查(非本模块边界) | — | +| buf.gen.yaml 插件 | ✅ go + python | 未由 ai11 核查(coord 维护) | — | + +> **核查说明**:ai11 仅核查与 data-ana 直接相关的 proto(iam/analytics/events)。§8.2 声明与实际文件严重不符,可能原因:(a) 声明为计划态但未执行;(b) 执行后未提交到本 worktree 分支;(c) 在其他分支已执行但未合并。无论哪种原因,data-ana 的 P4 实现依赖这些 proto 补全,当前实际状态构成 P4 阻塞。 + +--- + +## §1 问题列表 + +### ISSUE-001-ai11:iam.proto 缺 GetEffectiveDataScope RPC(P4 阻塞) + +- **提请方**:ai11 +- **日期**:2026-07-10 +- **类型**:前置依赖缺失 +- **描述**:coord-cross-review.md §2.2 #3 已仲裁"iam P4 补全 `GetEffectiveDataScope` RPC,data-ana gRPC 调用",但 iam.proto 当前仅 4 RPC,无此 RPC。data-ana 的 DataScope 6 级过滤(SELF/CLASS/GRADE/SCHOOL/DISTRICT/ALL)依赖此 RPC 解析用户可见数据范围,是 P4 实现的硬阻塞项。 +- **建议方案**:coord 确认 iam.proto 补全进度。若 iam 侧尚未实现,data-ana P4 阶段将使用硬编码 DataScope 降级(按 role 映射默认 scope),并标注 `details.degraded: true`,待 iam 就绪后切换。 +- **状态**:待 coord 仲裁(核查已有仲裁 §0.2 #1 未落实) + +--- + +### ISSUE-002-ai11:events.proto 缺 AIUsageEvent message(P5 阻塞,P4 预备) + +- **提请方**:ai11 +- **日期**:2026-07-10 +- **类型**:前置依赖缺失 +- **描述**:coord-cross-review.md §3.2 已仲裁"补登 `edu.insight.ai.usage` topic + events.proto 补 `AIUsageEvent` message",但 events.proto 当前仅 4 message(ClassEvent/ExamEvent/HomeworkEvent/GradeEvent),缺 AIUsageEvent。data-ana 需消费此事件落 `ai_usage_log` 宽表,供管理员仪表盘展示 AI 用量统计。 +- **建议方案**:coord 在 events.proto 补 `AIUsageEvent` message,字段建议:`{event_id, request_id, user_id, provider, model, prompt_tokens, completion_tokens, total_tokens, latency_ms, success, cost_cents, occurred_at}`。P5 前补全即可,P4 仪表盘 AI 用量区块显示"暂无数据"。 +- **状态**:待 coord 仲裁(核查已有仲裁 §0.2 #3 未落实) + +--- + +### ISSUE-003-ai11:analytics.proto 仅 3 RPC,coord-cross-review §8.2 声称已扩展至 12 RPC 但实际未落实(P4 阻塞) + +- **提请方**:ai11 +- **日期**:2026-07-10 +- **类型**:前置依赖缺失 + 声明与实际不符 +- **描述**:coord-cross-review.md §8.2 声称"analytics.proto 扩展 ✅ 12 RPC(含 Stream)",但实际文件仅 3 RPC(GetClassPerformance/GetStudentWeakness/GetLearningTrend)。ai-allocation.md §5 与 matrix.md §2 均要求 data-ana 提供 12 RPC,02-architecture-design.md §4.2 已设计完整 12 RPC 清单(含 4 端 Dashboard + Warning + Mastery + Server Streaming),但 proto 未补全导致无法生成 stub。 +- **建议方案**:coord 确认 analytics.proto 扩展进度。ai11 可提供 12 RPC 的完整 message 定义提案(见 [02-architecture-design.md §4.2](../../../services/data-ana/docs/02-architecture-design.md)),coord 审议后合并到 analytics.proto。若 coord 未补全,ai11 在 P4 阶段自行补全 proto(本分支内),提请 coord 合并。 +- **状态**:待 coord 仲裁 + +--- + +### ISSUE-004-ai11:coord-cross-review §6 整改清单 coord 责任项未落实,导致 004 章节引用断裂 + +- **提请方**:ai11 +- **日期**:2026-07-10 +- **类型**:契约不明确 +- **描述**:coord-cross-review.md §6 整改清单中标注"coord"责任的 4 项整改未在 004 正文中落实: + - #7:004 §7.2 补登 6 个 topic + CDC 命名规范 → 004 正文无对应段落 + - #8:004 §1.2 新增 HTTP/gRPC 端口两列 → 004 §1.2 服务清单无端口列 + - #9:004 §4.1 补充 gRPC 启用阶段矩阵 → 004 正文无 §4.2 子节 + - #10:004 §12.2 补充派生数据事件 Outbox 豁免条款 → 004 §12.2 未补充 + + 这导致 01-understanding.md 和 02-architecture-design.md 中引用 004 §4.2/§11.4/§11.5/§15.3 等章节均断裂(004 正文仅到 §14,§15 在 004-p6-addendum.md 但内容不同)。ai11 已在 v2.1 修订中临时改为引用 coord-cross-review.md 对应裁决章节,但这是过渡方案。 +- **建议方案**:coord 按整改清单 #7/#8/#9/#10 补全 004 对应章节,使 004 成为可信的架构设计意图唯一源。各 AI 文档随后将引用从 coord-cross-review.md 回切到 004 对应章节。 +- **状态**:待 coord 仲裁 + +--- + +### ISSUE-005-ai11:data-ana 发布的 MasteryEvent topic 命名三处不一致 + +- **提请方**:ai11 +- **日期**:2026-07-10 +- **类型**:契约不明确 +- **描述**:data-ana 发布的掌握度/预警事件 topic 命名在三个文档中不一致: + + | 文档 | topic 命名 | + | -------------------------------------- | ------------------------------------- | + | 01-understanding.md / 02-architecture-design.md | `edu.insight.mastery.updated` + `edu.insight.warning.triggered` | + | matrix.md §4 | `edu.analytics.mastery` | + | contracts/data-ana_contract.md(修正前) | `edu.data_ana.mastery.events` | + + 按 004 §7.2 命名规范 `edu...`,data-ana 属于 D6 智能洞察领域(domain=insight),故 `edu.insight.mastery.updated` 符合规范。matrix.md 的 `edu.analytics.mastery` 不符合命名规范(缺 action 层级,且 domain 用了服务名而非领域名)。 +- **建议方案**:coord 裁决统一为 `edu.insight.mastery.updated` + `edu.insight.warning.triggered`,coord 修正 matrix.md §4。ai11 已在 contract.md 中采用此命名。 +- **状态**:待 coord 仲裁 + +--- + +### ISSUE-006-ai11:coord-cross-review §8.2 批次 0 产出声明与 proto 实际文件状态严重不符 + +- **提请方**:ai11 +- **日期**:2026-07-10 +- **类型**:其他(声明与实际不符) +- **描述**:coord-cross-review.md §8.2 声称批次 0 已完成 iam.proto(12 RPC)/ analytics.proto(12 RPC)/ events.proto(9 message)补全,但 ai11 逐文件核查发现实际均未补全(详见 §0.3 核查表)。这影响所有依赖这些 proto 的下游 AI 的排期评估——若 AI 信任 §8.2 声明,会在排期中忽略 proto 补全的等待时间,导致排期失真。 +- **建议方案**:coord 核实 §8.2 声明真实性。若实际已补全但未合并到各 worktree 分支,请协调合并;若实际未补全,请更新 §8.2 状态为"计划中"或"待执行",并明确补全时间点,以便下游 AI 据此排期。 +- **状态**:待 coord 仲裁 diff --git a/docs/architecture/issues/worklines/data-ana_workline.md b/docs/architecture/issues/worklines/data-ana_workline.md index b2bf184..0a963b5 100644 --- a/docs/architecture/issues/worklines/data-ana_workline.md +++ b/docs/architecture/issues/worklines/data-ana_workline.md @@ -1,18 +1,34 @@ # data-ana 工作排期 > 负责人:ai11 -> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/data-ana_contract.md](../contracts/data-ana_contract.md) -> 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,最后统一集成测试) +> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/data-ana_contract.md](../contracts/data-ana_contract.md)、[objections/data-ana_issue.md](../objections/data-ana_issue.md) +> 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,开发期间用 mock,最后统一集成测试) +> 基线日期:批次 0 已完成(2026-07-09),批次 1(P2)2026-07-10 启动 --- ## §1 总览 -data-ana 是数据分析服务,提供 AnalyticsService(12 个 RPC),基于 ClickHouse 列存查询与 CDC 消费实现实时分析。全阶段目标:P2 ClickHouse 接入+CDC 消费 → P3 AnalyticsService 12 RPC → P4-P6 持续优化。 +data-ana 是 D6 智能洞察领域的纯读模型服务(Python/FastAPI),基于 ClickHouse ReplacingMergeTree 宽表 + Debezium CDC 消费实现实时学情分析。 + +**核心交付物**: +- gRPC server :50055 + AnalyticsService 12 RPC(含 1 个 Server Streaming) +- HTTP :3006 14 端点(3 基础 + 11 业务,保留作 Gateway 直连降级) +- ClickHouse 5 宽表(student_dashboard_view / student_errors / mastery_snapshot / attendance_logs / ai_usage_log) +- CDC 消费者(core-edu MySQL binlog → Kafka → ClickHouse 宽表投影) +- 掌握度计算(加权滑动平均 + 遗忘曲线)+ 预警评估 +- 派生数据事件发布(edu.insight.mastery.updated / edu.insight.warning.triggered,豁免 Outbox) + +**阶段里程碑**: +- P2 预备:ClickHouse 接入 + CDC 骨架 + ActionState 信封重构 + mock 数据集 +- P3 预备:CDC 通道接入 + 掌握度算法 v1 + Repository 封装 +- P4 主战场:gRPC 50055 启用 + 12 RPC + 4 端 Dashboard + Warning + DataScope + 事件发布 +- P5 扩展:SubscribeMasteryUpdate stream + AI 用量消费 + 手动 commit +- P6 硬化:CDC 水平扩展 + 容量规划 + 数据治理 + 监控告警 --- -## §2 全阶段甘特图(P2-P6,各 AI 自行细化) +## §2 全阶段甘特图(P2-P6) ```mermaid gantt @@ -20,26 +36,317 @@ gantt dateFormat YYYY-MM-DD axisFormat %m-%d - section P2-P6 - [阶段任务] :a11a, 2026-07-10, Xd + section P2 预备(与批次1并行) + 2.1 ClickHouse DDL 5宽表建表 :a11a, 2026-07-10, 2d + 2.2 CDC消费骨架(aiokafka) :a11b, after a11a, 2d + 2.3 mock数据集(30学生×5考试×10作业) :a11c, after a11a, 1d + 2.4 ActionState信封重构(P0整改) :crit, a11d, 2026-07-10, 2d + 2.5 config.py修正(env/Redis/gRPC) :a11e, after a11d, 1d + + section P3 预备(与批次2并行) + 3.1 gRPC server骨架(3 RPC,不启用) :a11f, after a11b, 2d + 3.2 core-edu CDC通道接入(grades/exams/homework) :a11g, after a11b, 3d + 3.3 ExamCache内存LRU :a11h, after a11g, 1d + 3.4 掌握度算法v1(weighted_moving_avg) :a11i, after a11g, 2d + 3.5 ClickHouseRepository(FINAL/argMax) :a11j, after a11i, 2d + + section P4 主战场(批次3, 11d) + 4.1 gRPC 50055正式启用 :crit, a11k, after a11j, 1d + 4.2 analytics.proto扩展12 RPC :crit, a11l, after a11k, 2d + 4.3 4端Dashboard RPC实现 :a11m, after a11l, 3d + 4.4 WarningService+TriggerWarning :a11n, after a11l, 2d + 4.5 GetMasteryDistribution+GetStudentMastery :a11o, after a11m, 1d + 4.6 iam.GetEffectiveDataScope集成(降级兜底) :crit, a11p, after a11k, 2d + 4.7 DataScope 6级WHERE注入 :a11q, after a11p, 1d + 4.8 attendance+content CDC消费 :a11r, after a11g, 2d + 4.9 MasteryEvent+WarningTriggered发布 :a11s, after a11n, 1d + 4.10 HTTP 14端点+readyz硬化 :a11t, after a11m, 2d + + section P5 扩展(批次4并行) + 5.1 SubscribeMasteryUpdate stream RPC :a11u, after a11t, 3d + 5.2 AIUsageEvent消费→ai_usage_log :a11v, after a11u, 2d + 5.3 手动commit替换auto_commit :a11w, after a11v, 1d + 5.4 Admin Dashboard AI用量区块 :a11x, after a11v, 2d + + section P6 硬化(批次5并行) + 6.1 CDC多实例水平扩展 :a11y, after a11x, 3d + 6.2 ExamCache Redis化 :a11z, after a11y, 2d + 6.3 容量规划+TTL归档策略 :a11aa, after a11z, 2d + 6.4 监控告警(consumer lag HPA) :a11ab, after a11aa, 2d + 6.5 readyz深度硬化 :a11ac, after a11ab, 1d ``` -> **注意**:以上为 coord 初始规划,ai11 接管后必须自行细化为完整 P2-P6 排期。 +> **关键路径**(crit):ActionState 信封重构 → gRPC 50055 启用 → analytics.proto 扩展 → iam GetEffectiveDataScope 集成 +> **总工期**:约 51 天(2026-07-10 ~ 2026-08-30),其中 P4 主战场 11 天为关键交付期 --- ## §3 详细任务 -### 全阶段任务 +### 3.1 P2 预备期(2026-07-10 ~ 2026-07-18,8d) + +#### 任务 2.1:ClickHouse DDL 5 宽表建表 - **负责人**:ai11 -- **交付物**:⚠️ 由 ai11 自行补充 -- **依赖**:见 [contracts/data-ana_contract.md](../contracts/data-ana_contract.md) -- **验收标准**:⚠️ 由 ai11 自行补充 +- **依赖**:无(ClickHouse 实例就绪,由 infra 提供) +- **交付物**:`infra/clickhouse/ddl/data_ana.sql`(5 宽表 DDL:student_dashboard_view / student_errors / mastery_snapshot / attendance_logs / ai_usage_log) +- **验收标准**:5 表在 ClickHouse 中创建成功,ReplacingMergeTree 引擎 + ORDER BY + PARTITION BY 符合 02 §3 DDL 设计 + +#### 任务 2.2:CDC 消费骨架 + +- **负责人**:ai11 +- **依赖**:Kafka 就绪 +- **交付物**:`src/data_ana/cdc_consumer.py` 重构(aiokafka AIOKafkaConsumer + EventHandler 路由框架) +- **验收标准**:能消费 mock CDC 事件并打印路由日志,consumer group = `data-ana-cdc` + +#### 任务 2.3:mock 数据集 + +- **负责人**:ai11 +- **依赖**:任务 2.1 +- **交付物**:`scripts/seed_clickhouse.py`(批量导入 30 学生 × 5 考试 × 10 作业 × 30 天出勤模拟数据) +- **验收标准**:ClickHouse 5 表有数据,可查询返回非空结果 + +#### 任务 2.4:ActionState 信封重构(P0 整改,coord-cross-review §5.3) + +- **负责人**:ai11 +- **依赖**:无 +- **交付物**:`src/data_ana/shared/action_state.py`(ActionState[T] 泛型 + ActionStateError + ok()/fail() 类方法) +- **验收标准**:main.py 所有端点返回 `ActionState[T]`,degraded 标记在顶层 `details.degraded`(非 error.details),ruff 零错误 + +#### 任务 2.5:config.py 修正 + +- **负责人**:ai11 +- **依赖**:无 +- **交付物**:`src/data_ana/config.py` 修正(env_prefix 补 Redis / gRPC / ClickHouse 配置项,pydantic-settings 校验) +- **验收标准**:配置项覆盖 02 §13 配置清单,环境变量缺失时 pydantic-settings 报错 + +--- + +### 3.2 P3 预备期(2026-07-18 ~ 2026-07-26,8d) + +#### 任务 3.1:gRPC server 骨架(3 RPC,不正式启用) + +- **负责人**:ai11 +- **依赖**:analytics.proto 当前 3 RPC(无需 coord 补全) +- **交付物**:`src/data_ana/grpc_server.py`(grpc.aio Server 骨架 + 3 RPC 实现,绑定 :50055 但不启动对外) +- **验收标准**:本地可启动 gRPC server,3 RPC 可调用返回 mock 数据 + +#### 任务 3.2:core-edu CDC 通道接入 + +- **负责人**:ai11 +- **依赖**:core-edu MySQL 就绪 + Debezium CDC 配置(core-edu 就绪前用 mock binlog 事件) +- **交付物**:`src/data_ana/cdc_consumer.py` 完善(EventHandler 处理 grades/exams/homework/classes 表 CDC 事件) +- **验收标准**:消费 CDC 事件 → 解析 Debezium JSON → 查 ExamCache 填 class_id → upsert ClickHouse 宽表 + +#### 任务 3.3:ExamCache 内存 LRU + +- **负责人**:ai11 +- **依赖**:任务 3.2 +- **交付物**:`src/data_ana/exam_cache.py`(内存 LRU dict,max 10000 条,exam_id → {class_id, subject_id}) +- **验收标准**:CDC exams 事件触发 ExamCache 更新,grades 事件查 ExamCache 获取 class_id + +#### 任务 3.4:掌握度算法 v1 + +- **负责人**:ai11 +- **依赖**:任务 3.2 +- **交付物**:`src/data_ana/mastery_service.py`(加权滑动平均算法,权重 w_i = 0.6^i,归一化) +- **验收标准**:输入学生近期 N 次成绩 → 输出 mastery_level (0.0-1.0) → 写 mastery_snapshot 表 + +#### 任务 3.5:ClickHouseRepository 封装 + +- **负责人**:ai11 +- **依赖**:任务 2.1 +- **交付物**:`src/data_ana/clickhouse_client.py` 重构(查询封装 + FINAL/argMax 去重 + DataScope WHERE 注入接口) +- **验收标准**:查询 student_dashboard_view 返回去重后最新版本数据 + +--- + +### 3.3 P4 主战场期(2026-07-26 ~ 2026-08-06,11d,批次 3) + +#### 任务 4.1:gRPC 50055 正式启用 + +- **负责人**:ai11 +- **依赖**:任务 3.1 +- **交付物**:main.py lifespan 启动 gRPC server :50055,HealthService.Check 返回 SERVING +- **验收标准**:gRPC server 对外可访问,HealthService.Check = SERVING + +#### 任务 4.2:analytics.proto 扩展 12 RPC + +- **负责人**:ai11(本分支内补全 proto,提请 coord 合并) +- **依赖**:ISSUE-003 解决(coord 确认或 ai11 自行补全) +- **交付物**:`packages/shared-proto/proto/analytics.proto` 扩展至 12 RPC(3 现有 + 9 新增 message 定义) +- **验收标准**:`buf lint` 零错误,`buf generate` 生成 Python stub 成功,12 RPC 全部可调用 + +#### 任务 4.3:4 端 Dashboard RPC 实现 + +- **负责人**:ai11 +- **依赖**:任务 4.2 +- **交付物**:GetTeacherDashboard / GetStudentDashboard / GetParentDashboard / GetAdminDashboard 4 RPC 实现 +- **验收标准**:4 RPC 返回 ActionState[DashboardData],DataScope 过滤生效,降级时返回骨架数据 + degraded: true + +#### 任务 4.4:WarningService + TriggerWarning + +- **负责人**:ai11 +- **依赖**:任务 3.4(掌握度算法) +- **交付物**:`src/data_ana/warning_service.py`(预警阈值评估 + TriggerWarning RPC + GetWarnings RPC) +- **验收标准**:掌握度 < 0.4 触发 LOW_MASTERY 预警,成绩环比下降 20% 触发 SCORE_DROP,缺勤 ≥ 3 次/周触发 ABSENT_FREQUENT + +#### 任务 4.5:GetMasteryDistribution + GetStudentMastery + +- **负责人**:ai11 +- **依赖**:任务 3.4 + 任务 4.2 +- **交付物**:2 RPC 实现(班级掌握度分布 + 学生知识点掌握度明细) +- **验收标准**:返回 mastered/progressing/weak 三档分布数据 + +#### 任务 4.6:iam.GetEffectiveDataScope 集成(降级兜底) + +- **负责人**:ai11 +- **依赖**:ISSUE-001 解决(iam.proto 补全 GetEffectiveDataScope)。若 P4 时 iam 未就绪,使用降级兜底 +- **交付物**:`src/data_ana/iam_client.py`(gRPC 调 iam.GetEffectiveDataScope + Redis 缓存 5min + 降级兜底) +- **验收标准**:iam 可用时调 gRPC 获取 DataScope;iam 不可用时按 role 映射默认 DataScope + degraded: true + +#### 任务 4.7:DataScope 6 级 WHERE 注入 + +- **负责人**:ai11 +- **依赖**:任务 4.6 + 任务 3.5 +- **交付物**:ClickHouseRepository 查询方法注入 DataScope WHERE 子句(SELF/CLASS/GRADE/SCHOOL/DISTRICT/ALL) +- **验收标准**:教师只能查自己班级数据,学生只能查自己数据,管理员可查全校数据 + +#### 任务 4.8:attendance + content CDC 消费 + +- **负责人**:ai11 +- **依赖**:任务 3.2(CDC 框架) +- **交付物**:EventHandler 扩展 attendance_logs 表 CDC + content_knowledge_points 表 CDC +- **验收标准**:考勤事件落 attendance_logs 表,知识点事件更新 mastery_snapshot 元数据 + +#### 任务 4.9:MasteryEvent + WarningTriggered 事件发布 + +- **负责人**:ai11 +- **依赖**:任务 3.4 + 任务 4.4 +- **交付物**:`src/data_ana/kafka_producer.py`(aiokafka AIOKafkaProducer + idempotent + transactional_id) +- **验收标准**:掌握度计算完成发布 `edu.insight.mastery.updated`,预警触发发布 `edu.insight.warning.triggered`,豁免 Outbox + +#### 任务 4.10:HTTP 14 端点 + readyz 硬化 + +- **负责人**:ai11 +- **依赖**:任务 4.3 + 任务 4.4 + 任务 4.5 +- **交付物**:main.py 14 个 HTTP 端点全部实现(3 基础 + 11 业务)+ /readyz 检查 4 依赖(clickhouse/cdc_consumer/redis/iam_grpc) +- **验收标准**:14 端点返回 ActionState[T],/readyz 依赖检查正确反映服务状态 + +--- + +### 3.4 P5 扩展期(2026-08-06 ~ 2026-08-19,13d,批次 4 并行) + +#### 任务 5.1:SubscribeMasteryUpdate Server Streaming RPC + +- **负责人**:ai11 +- **依赖**:任务 4.2 + 任务 4.9 +- **交付物**:SubscribeMasteryUpdate RPC 实现(server-streaming,客户端订阅 student_id/class_id,掌握度更新时推送) +- **验收标准**:客户端订阅后,掌握度计算完成时收到 MasteryUpdateEvent 流 + +#### 任务 5.2:AIUsageEvent 消费 → ai_usage_log + +- **负责人**:ai11 +- **依赖**:ISSUE-002 解决(events.proto 补 AIUsageEvent)+ ai 服务发布 `edu.insight.ai.usage` topic +- **交付物**:EventHandler 扩展 AIUsageEvent 消费 → 落 ai_usage_log 表 +- **验收标准**:ai 服务发布用量事件后,ai_usage_log 表有数据,Admin Dashboard AI 用量区块可展示 + +#### 任务 5.3:手动 commit 替换 auto_commit + +- **负责人**:ai11 +- **依赖**:任务 3.2 +- **交付物**:cdc_consumer.py 改为 `enable_auto_commit=False` + 手动 commit(at-least-once) +- **验收标准**:ClickHouse 写入成功后才 commit offset,重启后无重复消费(依赖 ReplacingMergeTree 去重) + +#### 任务 5.4:Admin Dashboard AI 用量区块 + +- **负责人**:ai11 +- **依赖**:任务 5.2 +- **交付物**:GetAdminDashboard RPC 补全 AI 用量统计区块(按 provider/model/时间窗聚合) +- **验收标准**:Admin Dashboard 返回 AI 用量数据,无数据时显示"暂无数据" + +--- + +### 3.5 P6 硬化期(2026-08-19 ~ 2026-08-30,11d,批次 5 并行) + +#### 任务 6.1:CDC 多实例水平扩展 + +- **负责人**:ai11 +- **依赖**:任务 5.3(手动 commit) +- **交付物**:CdcConsumer 支持多实例分摊 partition(consumer group 不变) +- **验收标准**:2+ 实例消费同一 topic 无重复无遗漏 + +#### 任务 6.2:ExamCache Redis 化 + +- **负责人**:ai11 +- **依赖**:任务 6.1 +- **交付物**:exam_cache.py 改为 Redis 实现(key: `data_ana:exam:{exam_id}` TTL 30 天) +- **验收标准**:多实例共享 ExamCache,重启后缓存不丢失 + +#### 任务 6.3:容量规划 + TTL 归档策略 + +- **负责人**:ai11 +- **依赖**:无 +- **交付物**:ClickHouse TTL 策略(student_dashboard_view 保留 2 年,ai_usage_log 保留 1 年)+ 冷热数据分离方案 +- **验收标准**:TTL 配置生效,过期数据自动清理 + +#### 任务 6.4:监控告警完善 + +- **负责人**:ai11 +- **依赖**:任务 6.1 +- **交付物**:Prometheus 指标补全(consumer lag histogram + 慢查询 counter + ClickHouse 连接池 gauge)+ Grafana dashboard +- **验收标准**:consumer lag 超阈值触发 HPA,慢查询超阈值告警 + +#### 任务 6.5:readyz 深度硬化 + +- **负责人**:ai11 +- **依赖**:任务 4.10 +- **交付物**:/readyz 检查项完善(ClickHouse 查询超时 1s + Redis ping + iam gRPC 超时 2s + CDC consumer lag < 1000) +- **验收标准**:任一依赖不健康时 /readyz 返回 503,K8s 摘流量 --- ## §4 依赖与就绪信号 -- **我依赖**:⚠️ 由 ai11 自行补充(见 contract.md) -- **我的就绪信号**:⚠️ 由 ai11 自行补充 +### 4.1 我依赖的上游就绪标志 + +- [ ] **core-edu gRPC 50053 启用**(ai08,批次 2)—— CDC 数据源(grades/exams/homework/attendance 表 binlog) +- [ ] **core-edu MySQL Debezium CDC 配置**(ai08 + SRE)—— CDC 通道前提 +- [ ] **content gRPC 50054 启用**(ai09,批次 3)—— 知识点维度 CDC +- [ ] **iam.proto 补全 GetEffectiveDataScope RPC**(ai06/coord,ISSUE-001)—— DataScope 解析 +- [ ] **analytics.proto 扩展至 12 RPC**(coord/ai11,ISSUE-003)—— gRPC stub 生成前提 +- [ ] **events.proto 补全 AIUsageEvent message**(coord,ISSUE-002)—— AI 用量消费(P5) +- [ ] **ai 服务发布 `edu.insight.ai.usage` topic**(ai12,批次 4)—— AI 用量统计(P5) + +> **降级兜底**:core-edu / content / iam 未就绪时,使用 ClickHouse 内置 mock 数据集 + 硬编码 DataScope 降级,标注 `details.degraded: true` + +### 4.2 我的就绪信号(供下游消费) + +- [ ] **P4 就绪**:data-ana gRPC 50055 启用(HealthService.Check = SERVING)+ AnalyticsService 12 RPC 可调用 + 4 端 Dashboard 返回结构化数据 +- [ ] **P4 就绪**:`edu.insight.mastery.updated` topic 可发布(mastery.updated / warning.triggered) +- [ ] **P5 就绪**:SubscribeMasteryUpdate server-streaming RPC 可订阅 +- [ ] **P6 就绪**:CDC 多实例水平扩展 + ExamCache Redis 化完成 + +### 4.3 下游消费方 + +| 下游 | 消费接口 | 就绪依赖阶段 | +| -------------------------- | ---------------------------------------------------------------- | ------------ | +| teacher-bff(ai03) | gRPC 50055 GetTeacherDashboard / GetClassPerformance 等 | P4 | +| student-bff(ai04) | gRPC 50055 GetStudentDashboard / GetStudentWeakness 等 | P4 | +| parent-bff(ai05) | gRPC 50055 GetParentDashboard | P4 | +| ai 服务(ai12) | gRPC 50055 反向调用查学情(GetStudentMastery / GetLearningTrend) | P5 | +| core-edu(ai08) | Kafka `edu.insight.mastery.updated`(推荐个性化练习) | P4 | +| msg(ai10) | Kafka `edu.insight.warning.triggered`(推送通知) | P4 | + +--- + +## §5 风险与缓解 + +| 风险 | 影响 | 缓解措施 | +| -------------------------------------------- | ---- | ------------------------------------------------------------------------------------------ | +| iam.proto 未补全 GetEffectiveDataScope | P4 | 降级兜底:按 role 映射默认 DataScope + degraded: true(ISSUE-001) | +| analytics.proto 未扩展 12 RPC | P4 | ai11 本分支自行补全 proto,提请 coord 合并(ISSUE-003) | +| core-edu CDC 通道未就绪 | P3-P4 | mock 数据集降级 + 本地 stub CDC 事件 | +| ClickHouse ReplacingMergeTree 去重延迟 | P4 | 查询加 FINAL / argMax 强制去重(02 §3.6 已设计) | +| 单实例 CDC 消费者单点故障 | P4 | P6 演进为多实例 + Redis ExamCache;P4 阶段监控 consumer lag 告警 | +| 掌握度算法精度不足 | P4 | v1 用加权滑动平均,P5+ 评估引入遗忘曲线 max 叠加(02 §9 已设计 MasteryMethod 枚举预留) | diff --git a/services/data-ana/docs/01-understanding.md b/services/data-ana/docs/01-understanding.md index 4532bfd..cc3e68f 100644 --- a/services/data-ana/docs/01-understanding.md +++ b/services/data-ana/docs/01-understanding.md @@ -7,6 +7,7 @@ > 日期: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 修订。 +> 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 缺失说明。 --- @@ -41,11 +42,11 @@ - 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) + - iam gRPC(调 `GetEffectiveDataScope` 解析数据范围,已仲裁 P4 补全,见 [coord-cross-review.md §2](../../docs/architecture/coord-cross-review.md) #3) - **通信方式**: - 入口: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 启用) + - 出口:Kafka 消费(CDC 主通道 + 领域事件订阅备通道);Kafka 发布(`edu.insight.mastery.updated`,**未实现**,属派生数据豁免 Outbox,见 [coord-cross-review.md §3.3](../../docs/architecture/coord-cross-review.md) + 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**([coord-cross-review.md §4.3](../../docs/architecture/coord-cross-review.md) 全局端口矩阵 + [matrix.md §2](../../docs/architecture/issues/matrix.md):P4 启用) ## 2. 我的限界上下文 @@ -79,7 +80,7 @@ | 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 | +| iam.proto | `GetEffectiveDataScopeRequest`(**待 coord 在 iam.proto 新增**,[coord-cross-review.md §2](../../docs/architecture/coord-cross-review.md) #3 已裁决 P4 补全;当前 iam.proto 仅有 4 RPC,无此 RPC,**P4 阻塞项**) | 调用契约 | gRPC 调 iam 解析 DataScope,结果 Redis 缓存 5min | ### 暴露的 API / 事件 @@ -94,7 +95,7 @@ | 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)。 +> **响应信封约束**:以上 HTTP 端点当前实现为 `{success, data, degraded}` 结构,违反统一响应信封 ActionState([coord-cross-review.md §5.3](../../docs/architecture/coord-cross-review.md) 已裁决 Python 服务必须改 ActionState,degraded 作为 `details.degraded` 子字段)。阶段 2 设计已对齐(见 02-architecture-design.md §4.3)。 **gRPC 契约**(analytics.proto,P4 启用 server,端口 50055): @@ -113,11 +114,13 @@ | 事件 | Topic(004 §7.2) | 触发时机 | 消费者(004 §7.3) | Outbox 合规性 | | ---------------- | ----------------------------- | -------------- | --------------------------------------- | ----------------------------------------------------------- | -| `MasteryUpdated` | `edu.insight.mastery.updated` | 掌握度计算完成 | core-edu(推荐个性化练习)、msg(预警) | **豁免 Outbox**(派生数据,见 004 §12.2 + §15.3 #6 已仲裁) | +| `MasteryUpdated` | `edu.insight.mastery.updated` | 掌握度计算完成 | core-edu(推荐个性化练习)、msg(预警) | **豁免 Outbox**(派生数据,见 [coord-cross-review.md §3.3](../../docs/architecture/coord-cross-review.md) + 004 §12.2) | -> **当前未实现发布**:data-ana 当前只消费不发布。掌握度计算完成后通过 `aiokafka.AIOKafkaProducer` 直接发布(已豁免 Outbox,004 §15.3 #6 仲裁结论),下游 core-edu / msg 消费。失败重试 3 次仍失败落 `mastery_publish_failed` 本地表。 +> **当前未实现发布**:data-ana 当前只消费不发布。掌握度计算完成后通过 `aiokafka.AIOKafkaProducer` 直接发布(已豁免 Outbox,coord-cross-review.md §3.3 仲裁结论),下游 core-edu / msg 消费。失败重试 3 次仍失败落 `mastery_publish_failed` 本地表。 -- **错误码前缀**:`DATA_ANA_*`(004 §11.4 错误码前缀矩阵已登记,清单见阶段 2 §6.2) +> **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](../../docs/architecture/issues/matrix.md) 错误码前缀矩阵已登记,清单见阶段 2 §6.2) - **缓存**:Redis(DataScope 缓存 5min 事件驱动失效 / CDC event_id 幂等去重 SETNX TTL 7d / 预警去重位图);学情宽表走 ClickHouse 实时,CDC 同步延迟 < 5s ## 4. 我的技术栈 @@ -145,7 +148,7 @@ - **交付物**(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) + - P2 身份:iam `GetEffectiveDataScope` gRPC(已仲裁 P4 补全,见 [coord-cross-review.md §2](../../docs/architecture/coord-cross-review.md) #3;**当前 iam.proto 未实现,P4 阻塞项**) - P3 核心教学:core-edu 写成绩到 MySQL(Debezium 监听 binlog)+ Outbox 领域事件(备通道) - P4 同期:content 服务(提供知识点 ID 供掌握度计算,content → data-ana 事件流见 004 §4 服务依赖图) - **下游依赖我**: @@ -160,8 +163,8 @@ > 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` 子字段 +- [ ] 错误码前缀统一:**当前无错误码体系**,降级时返回 `degraded: true` 标记但无业务错误码。**阶段 2 需定义 `DATA_ANA_*` 错误码清单**([matrix.md §6](../../docs/architecture/issues/matrix.md) 已登记前缀) +- [ ] **响应信封对齐 ActionState**([coord-cross-review.md §5.3](../../docs/architecture/coord-cross-review.md) 已裁决 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 @@ -210,17 +213,17 @@ ## 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 提请的 5 项跨模块契约对齐项,coord 已在 [coord-cross-review.md](../../../docs/architecture/coord-cross-review.md) 完成仲裁。本节 v2.1 改为"对齐状态",并标注落实情况。 -| # | 议题(v1 提请) | coord 裁决结论(004 §15.3) | data-ana 文档对齐状态(v2) | +| # | 议题(v1 提请) | coord 裁决结论(coord-cross-review.md) | data-ana 文档对齐状态(v2.1) | | --- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| 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 调用契约 | +| 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。 diff --git a/services/data-ana/docs/02-architecture-design.md b/services/data-ana/docs/02-architecture-design.md index 6883e2f..fa033af 100644 --- a/services/data-ana/docs/02-architecture-design.md +++ b/services/data-ana/docs/02-architecture-design.md @@ -16,11 +16,11 @@ 1. **契约先行**:proto 已定义(analytics.proto / events.proto / iam.proto),实现前不修改 proto,如需修改走 coord 流程(ai-allocation.md §9.4) 2. **CQRS 读写分离**:data-ana 是纯读模型服务(无 MySQL 写),ClickHouse 宽表由 CDC 投影构建 -3. **事件驱动**:data-ana 消费 CDC(主通道)+ 领域事件(备通道,待 P4 后期评估);发布 `edu.insight.mastery.updated` 派生数据事件(豁免 Outbox,004 §12.2 + §15.3 #6 已仲裁) -4. **gRPC 优先**:004 §4.1 + §4.2 明确 BFF → 业务服务走 gRPC,**P4 启用 data-ana gRPC server 端口 50055**(HTTP 保留作 Gateway 直连降级) -5. **DataScope 过滤**:004 §5.3 DataScope 6 级在查询层注入 WHERE;iam `GetEffectiveDataScope` gRPC(004 §15.3 #5 已仲裁 P4 补全) +3. **事件驱动**:data-ana 消费 CDC(主通道)+ 领域事件(备通道,待 P4 后期评估);发布 `edu.insight.mastery.updated` 派生数据事件(豁免 Outbox,[coord-cross-review.md §3.3](../../docs/architecture/coord-cross-review.md) + 004 §12.2 已仲裁) +4. **gRPC 优先**:004 §4.1 + [coord-cross-review.md §2.1](../../docs/architecture/coord-cross-review.md) 明确 BFF → 业务服务走 gRPC,**P4 启用 data-ana gRPC server 端口 50055**(HTTP 保留作 Gateway 直连降级) +5. **DataScope 过滤**:004 §5.3 DataScope 6 级在查询层注入 WHERE;iam `GetEffectiveDataScope` gRPC([coord-cross-review.md §2](../../docs/architecture/coord-cross-review.md) #3 已仲裁 P4 补全) 6. **三支柱可观测**:structlog + prometheus-client + OpenTelemetry(已具备,需补业务指标 + gRPC server interceptor) -7. **统一响应信封 ActionState**(004 §11.5 已仲裁 P0 整改):成功 `{success: true, data: T}` / 失败 `{success: false, error: {code, message, details?, traceId?}}` / 降级 `degraded` 作为 `details.degraded` 子字段 +7. **统一响应信封 ActionState**([coord-cross-review.md §5.3](../../docs/architecture/coord-cross-review.md) 已裁决 P0 整改):成功 `{success: true, data: T}` / 失败 `{success: false, error: {code, message, details?, traceId?}}` / 降级 `degraded` 作为顶层 `details.degraded` 子字段(非 `error.details`) 8. **降级模式**:外部依赖(ClickHouse / Kafka / iam gRPC / Redis)不可用时返回骨架数据 + `details.degraded: true` 9. **Python 规范**:pydantic-settings 配置 / Pydantic 模型校验 / async 优先 / 类型注解强制 / ruff 零错误 10. **长远架构演进**:为 P5(ai 用量消费 / gRPC stream)、P6(CDC 水平扩展 / 容量规划 / 数据治理 / Service Mesh)做好铺垫,见 §14 / §19 @@ -295,13 +295,15 @@ ORDER BY (student_id, class_id, attendance_date); | `GetAdminDashboard` | `GetAdminDashboardRequest{user_id, scope, scope_id?}` | `AdminDashboard` | `ANALYTICS_ADMIN_DASHBOARD` | | `GetWarnings` | `GetWarningsRequest{class_id?, severity?, since?}` | `WarningList` | `ANALYTICS_WARNING_READ` | | `GetMasteryDistribution` | `GetMasteryDistributionRequest{class_id, subject_id, knowledge_point_id?}` | `MasteryDistribution` | `ANALYTICS_CLASS_READ` | +| `GetStudentMastery` | `GetStudentMasteryRequest{student_id, subject_id?}` | `StudentMastery` | `ANALYTICS_STUDENT_READ` | +| `TriggerWarning` | `TriggerWarningRequest{target_id, warning_type, severity}` | `TriggerWarningResponse` | `ANALYTICS_WARNING_READ` | | `SubscribeMasteryUpdate` | `SubscribeMasteryUpdateRequest{student_id?, class_id?}` | `stream MasteryUpdateEvent` | `ANALYTICS_STUDENT_READ` | -> **proto 扩展提案**(待 coord 审议):上述新增 RPC 的 message 定义需在 `packages/shared-proto/proto/analytics.proto` 补充。`SubscribeMasteryUpdate` 为 server-streaming RPC,为 P5+ AI 个性化推荐预留实时推送通道。 +> **proto 扩展提案**(待 coord 审议):上述新增 RPC 的 message 定义需在 `packages/shared-proto/proto/analytics.proto` 补充,共 12 RPC(3 现有 + 9 扩展)。`SubscribeMasteryUpdate` 为 server-streaming RPC,为 P5+ AI 个性化推荐预留实时推送通道。 **权限校验**:gRPC server interceptor 从 metadata 提取 `x-user-id` / `x-user-roles` / `x-data-scope`,调用 `AuthDepends` 等价逻辑。 -### 4.3 ActionState 统一响应信封(004 §11.5 P0 整改) +### 4.3 ActionState 统一响应信封(coord-cross-review.md §5.3 P0 整改) 所有 HTTP/gRPC 响应必须遵循 ActionState 信封: @@ -318,23 +320,22 @@ class ActionStateError(BaseModel): trace_id: str | None = None class ActionState(BaseModel, Generic[T]): - """统一响应信封(004 §11.5). + """统一响应信封(coord-cross-review.md §5.3 裁决). 成功:{success: true, data: T} 失败:{success: false, error: {code, message, details?, trace_id?}} - 降级:success=true 但 error.details.degraded=true(保留功能但数据可能不完整) + 降级:{success: true, data: T, details: {degraded: true}}(保留功能但数据可能不完整) """ success: bool data: T | None = None error: ActionStateError | None = None + details: dict[str, Any] | None = None # 降级标记放此字段,不放 error @classmethod def ok(cls, data: T, *, degraded: bool = False) -> "ActionState[T]": + # 降级不是错误:success=True,degraded 标记放 details 子字段(非 error.details) details = {"degraded": True} if degraded else None - # 简化:degraded 作为 data 的元信息附加,复杂场景用 details - return cls(success=True, data=data, error=None if not degraded else - ActionStateError(code="DATA_ANA_DEGRADED", message="degraded mode", - details=details)) + return cls(success=True, data=data, error=None, details=details) @classmethod def fail(cls, code: str, message: str, *, trace_id: str | None = None, @@ -361,7 +362,7 @@ class StudentScore(BaseModel): # 端点返回类型:ActionState[ClassPerformanceData] ``` -> **P0 整改要点**:当前 main.py 返回 `{success, data, degraded}` 三字段平铺,违反 004 §11.5。实现阶段需重构为 `ActionState[T]` 泛型,`degraded` 移到 `error.details.degraded`。 +> **P0 整改要点**:当前 main.py 返回 `{success, data, degraded}` 三字段平铺,违反 coord-cross-review.md §5.3 裁决。实现阶段需重构为 `ActionState[T]` 泛型,`degraded` 移到顶层 `details.degraded`(非 `error.details`,降级不是错误)。 ## 5. 事件设计 @@ -547,13 +548,13 @@ async def readyz() -> dict: | 被调用 | api-gateway | HTTP | `/analytics/*` | Gateway 代理(降级通道) | | 被调用 | teacher-bff / student-bff / parent-bff | gRPC | `AnalyticsService.*` | BFF 聚合查询(4 端 Dashboard) | | 被调用 | ai(P5+) | gRPC | `AnalyticsService.GetStudentWeakness / GetLearningTrend / SubscribeMasteryUpdate` | AI 个性化出题上下文 + 实时掌握度推送 | -| 调用 | iam | gRPC | `IamService.GetEffectiveDataScope`(004 §15.3 #5 已仲裁 P4 补全) | DataScope 解析 | +| 调用 | iam | gRPC | `IamService.GetEffectiveDataScope`([coord-cross-review.md §2](../../docs/architecture/coord-cross-review.md) #3 已仲裁 P4 补全;**当前 iam.proto 未实现**) | DataScope 解析 | | 消费 | core-edu(CDC) | Kafka | `edu-cdc.next_edu_cloud.core_edu_grades/exams/homework_submissions/attendance` | 学情 + 考勤数据投递 | | 消费 | core-edu(CDC) | Kafka | `edu-cdc.next_edu_cloud.classes` | 班级维度同步 | | 消费 | iam(CDC) | Kafka | `edu-cdc.next_edu_cloud.iam_users` | 用户 dataScope 同步 | | 消费 | content(CDC) | Kafka | `edu-cdc.next_edu_cloud.content_knowledge_points` | 知识点元数据同步(v2 新增) | -| 消费 | ai(P5+) | Kafka | `edu.insight.ai.usage`(004 §15.3 #6 已仲裁,004 §7.2 已登记) | AI 用量落库 | -| 发布 | core-edu / msg | Kafka | `edu.insight.mastery.updated`(004 §12.2 + §15.3 #6 已仲裁:派生数据豁免 Outbox) | 掌握度更新通知 | +| 消费 | ai(P5+) | Kafka | `edu.insight.ai.usage`([coord-cross-review.md §3.2](../../docs/architecture/coord-cross-review.md) 已仲裁;004 §7.2 已登记) | AI 用量落库 | +| 发布 | core-edu / msg | Kafka | `edu.insight.mastery.updated`([coord-cross-review.md §3.3](../../docs/architecture/coord-cross-review.md) + 004 §12.2 已仲裁:派生数据豁免 Outbox) | 掌握度更新通知 | | 发布 | msg / core-edu | Kafka | `edu.insight.warning.triggered`(v2 新增,需 coord 在 004 §7.2 登记) | 预警触发通知 | > **004 §4.1 服务间通信矩阵对齐**:content → data-ana 已声明"教学内容变更通知",本次落实为 CDC 订阅 `content_knowledge_points` 表。 @@ -562,10 +563,10 @@ async def readyz() -> dict: ### 8.1 假设 -- **假设 1**:iam 在 P4 阶段提供 `GetEffectiveDataScope(userId) → DataScope` gRPC API(004 §15.3 #5 已仲裁)。若 iam 未及时提供,fallback 为:从 `x-user-roles` 头推导(admin=ALL, teacher=CLASS_TAUGHT, student=SELF),但无法支持细粒度年级/学校范围 +- **假设 1**:iam 在 P4 阶段提供 `GetEffectiveDataScope(userId) → DataScope` gRPC API([coord-cross-review.md §2](../../docs/architecture/coord-cross-review.md) #3 已仲裁)。**当前 iam.proto 仅 4 RPC 未实现此 RPC,P4 阻塞项**。若 iam 未及时提供,fallback 为:从 `x-user-roles` 头推导(admin=ALL, teacher=CLASS_TAUGHT, student=SELF),但无法支持细粒度年级/学校范围 - **假设 2**:core-edu 的 `core_edu_homework_submissions` / `core_edu_attendance` 表存在 binlog。若不存在,需 core-edu 补表或走 Outbox 事件(领域事件备通道) - **假设 3**:ClickHouse `ReplacingMergeTree` 在查询时需 `FINAL` 关键字确保去重生效。**v2 修复要求**:所有查询加 `FINAL` 或使用 `argMax` 聚合(当前实现未加,是 P0 整改项) -- **假设 4**:coord 已在 004 §7.2 登记新增 `edu.insight.ai.usage` topic(004 §15.3 #6 已仲裁) +- **假设 4**:coord 已在 004 §7.2 登记新增 `edu.insight.ai.usage` topic([coord-cross-review.md §3.2](../../docs/architecture/coord-cross-review.md) 已仲裁);**events.proto AIUsageEvent message 待 coord 补充** ### 8.2 技术风险 @@ -582,22 +583,22 @@ async def readyz() -> dict: | 大数据量 Dashboard 聚合超时 | 管理员 Dashboard 全校聚合慢 | 物化视图预聚合 + 异步刷新 + 缓存 5min | | 知识点元数据与成绩关联失败 | mastery_snapshot 缺知识点标题 | content CDC 同步 + 缺失时显示 `knowledge_point_id` | -### 8.3 coord 交叉审查结论对齐(v2:原"未决设计决策"已全部仲裁) +### 8.3 coord 交叉审查结论对齐(v2.1:原"未决设计决策"已全部仲裁) | # | 议题 | coord 仲裁结论 | 涉及文档 | | --- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | ----------------------- | -| 1 | data-ana 发布 `edu.insight.mastery.updated` 用直接 producer(非 Outbox)是否合规 | ✅ 已仲裁:派生数据事件豁免 Outbox(004 §12.2 + §15.3 #6) | 004 §12.2 | -| 2 | 新增 `edu.insight.ai.usage` topic + `AIUsageEvent` proto message | ✅ 已仲裁:coord 在 004 §7.2 登记 + events.proto 补 message | 004 §7.2 + events.proto | -| 3 | iam 新增 `GetEffectiveDataScope` gRPC RPC | ✅ 已仲裁:P4 补全(004 §15.3 #5) | iam.proto | -| 4 | data-ana 实现 gRPC server 决策 | ✅ 已仲裁:P4 启用(004 §4.2 gRPC 启用阶段矩阵) | 004 §4.2 | +| 1 | data-ana 发布 `edu.insight.mastery.updated` 用直接 producer(非 Outbox)是否合规 | ✅ 已仲裁:派生数据事件豁免 Outbox([coord-cross-review §3.3](../../docs/architecture/coord-cross-review.md) + 004 §12.2) | 004 §12.2 | +| 2 | 新增 `edu.insight.ai.usage` topic + `AIUsageEvent` proto message | ✅ 已仲裁:coord 在 004 §7.2 登记 + events.proto 补 message;**⚠️ events.proto 当前缺 AIUsageEvent,待 coord 落实** | 004 §7.2 + events.proto | +| 3 | iam 新增 `GetEffectiveDataScope` gRPC RPC | ✅ 已仲裁:P4 补全([coord-cross-review §2](../../docs/architecture/coord-cross-review.md) #3);**⚠️ iam.proto 当前仅 4 RPC,未实现** | iam.proto | +| 4 | data-ana 实现 gRPC server 决策 | ✅ 已仲裁:P4 启用([coord-cross-review §2.1](../../docs/architecture/coord-cross-review.md) gRPC 启用阶段) | 004 §4.1 | | 5 | ClickHouse DDL 管理位置(建议 `infra/clickhouse/ddl/`) | ⏳ 待 coord 建立 `infra/clickhouse/ddl/` 目录 + data-ana 提供内容 | infra/ | -| 6 | 端口冲突检查:data-ana HTTP=3006 / gRPC=50055 | ✅ 无冲突(004 §1.2 端口分配) | 004 §1.2 | -| 7 | 错误码前缀检查:`DATA_ANA_*` | ✅ 无冲突(004 §11.4 错误码前缀矩阵) | 004 §11.4 | -| 8 | 黄金模板对齐:Python 服务无 NestJS 装饰器,权限校验用 FastAPI Depends 等价物是否认可 | ✅ 已仲裁:认可(004 §15.3) | — | +| 6 | 端口冲突检查:data-ana HTTP=3006 / gRPC=50055 | ✅ 无冲突([coord-cross-review §4.3](../../docs/architecture/coord-cross-review.md) 全局端口矩阵) | port-allocation | +| 7 | 错误码前缀检查:`DATA_ANA_*` | ✅ 无冲突([matrix.md §6](../../docs/architecture/issues/matrix.md) 错误码前缀矩阵) | matrix.md §6 | +| 8 | 黄金模板对齐:Python 服务无 NestJS 装饰器,权限校验用 FastAPI Depends 等价物是否认可 | ✅ 已仲裁:认可([coord-cross-review §5.3](../../docs/architecture/coord-cross-review.md)) | — | | 9 | `edu.insight.warning.triggered` topic 新增 | ⏳ 待 coord 在 004 §7.2 登记(v2 新提案) | 004 §7.2 | | 10 | analytics.proto 扩展(4 端 Dashboard / Warning / MasteryDistribution / Stream RPC) | ⏳ 待 coord 审议(v2 新提案,§4.2) | analytics.proto | -> 所有"未决设计决策"已消除,进入实现阶段无阻塞。剩余 3 项 ⏳ 为 v2 新提案,待 coord 审议但不阻塞 P4 主体实现(可先用现有 RPC + HTTP 端点兜底)。 +> 所有"未决设计决策"已消除。**P4 阻塞项**:#2 events.proto 缺 AIUsageEvent、#3 iam.proto 缺 GetEffectiveDataScope,均待 coord 落实。剩余 3 项 ⏳ 为 v2 新提案,待 coord 审议但不阻塞 P4 主体实现(可先用现有 RPC + HTTP 端点 + mock 兜底)。 --- @@ -783,7 +784,7 @@ ENV PATH="/app/.venv/bin:$PATH" ENV PYTHONUNBUFFERED=1 EXPOSE 3006 50055 HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ - CMD curl -f http://localhost:3006/healthz || exit 1 + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:3006/healthz')" || exit 1 CMD ["python", "-m", "uvicorn", "src.data_ana.main:app", \ "--host", "0.0.0.0", "--port", "3006"] ``` @@ -945,12 +946,26 @@ CDC → ClickHouse 原始表 → MaterializedView → 宽表(自动聚合) - **AI 驱动的学情诊断**:data-ana 提供数据,ai 服务提供模型,组合成"智能诊断报告" - **多租户**:当前 school_id 隐含在 class_id 中,远期可显式多租户隔离 -## 19. 服务审计表 v2(黄金模板对齐) +## 19. 非功能性需求(NFR,v2.1 新增) + +| 维度 | 指标 | 目标值 | 验证方式 | +| ---------- | ----------------------------- | --------------- | ------------------------------- | +| 性能 | ClickHouse 宽表查询 P99 延迟 | < 5s | P4 退出标准 + Prometheus 监控 | +| 性能 | CDC 链路延迟 | < 5s | Debezium ts_ms → CH 写入时间差 | +| 性能 | gRPC RPC P99 延迟 | < 500ms | OTel trace | +| 可用性 | P4 单实例 | 99% | 降级模式保证 | +| 可用性 | P6 多实例 + ClickHouse 集群 | 99.9% | HPA + 副本 | +| 安全 | DataScope 越权防护 | 0 越权 | 权限测试 + 渗透测试 | +| 安全 | PII 日志脱敏 | 100% student_id hash | structlog processor 单测 | +| 可扩展性 | CDC 消费者水平扩展 | N 实例无重复 | ReplacingMergeTree + Redis SETNX | +| 数据保留 | ClickHouse TTL | 见 §11.1 | TTL 策略自动执行 | + +## 20. 服务审计表 v2(黄金模板对齐) | 维度 | 状态 | 说明 | | ------------- | ---- | ----------------------------------------------------------------------- | -| 契约(proto) | ✅ | analytics.proto 已定义 3 RPC,v2 提案扩展 7 RPC | -| 路由 | ✅ | HTTP 13 端点 + gRPC 10 RPC | +| 契约(proto) | ✅ | analytics.proto 已定义 3 RPC,v2 提案扩展至 12 RPC(含 GetStudentMastery / TriggerWarning) | +| 路由 | ✅ | HTTP 14 端点(3 基础 + 11 业务)+ gRPC 12 RPC | | 数据访问 | ✅ | ClickHouse 5 宽表 + Redis 缓存 + iam gRPC | | 鉴权 | ✅ | FastAPI Depends 等价物 + 7 权限点 | | 错误处理 | ✅ | 13 错误码 `DATA_ANA_*` + ActionState 信封 | @@ -960,6 +975,7 @@ CDC → ClickHouse 原始表 → MaterializedView → 宽表(自动聚合) | 健康检查 | ✅ | /healthz + /readyz(v2 补 redis/iam_grpc) | | 配置管理 | ✅ | pydantic-settings 完整配置项(§15) | | 降级模式 | ✅ | 4 降级场景(CH/Kafka/Redis/iam) | +| NFR | ✅ | v2.1 新增 §19,性能/可用性/安全/可扩展性目标已定义 | | 响应信封 | ⚠️ | v2 设计对齐 ActionState,实现阶段需重构(P0 整改) | | Redis | ⚠️ | v2 设计就绪,实现阶段需新增 redis-py 依赖 + RedisClient | | gRPC server | ⚠️ | v2 设计就绪,实现阶段需新增 grpc.aio + betterproto + server interceptor | @@ -975,5 +991,6 @@ CDC → ClickHouse 原始表 → MaterializedView → 宽表(自动聚合) **AI Agent**: ai11 (data-ana) **Branch**: 单仓库并行模式(直接提交 main) **Coordinator**: coord-ai -**v2 修订依据**: ai-allocation.md §3.2 重新分配 + 004 §1.2/§4.2/§7.2/§11.5/§12.2/§15.3 + ai-allocation §5 设计重点 + pending-features P4 退出标准 -**v2 审核结论**: 16 项遗漏已全部补强(3 项 P0 + 5 项 P1 + 8 项 P2),文档进入实现阶段无阻塞 +**v2 修订依据**: ai-allocation.md §3.2 重新分配 + coord-cross-review.md §2/§3.3/§5.3 + 004 §4.1/§7.2/§12.2 + ai-allocation §5 设计重点 + pending-features P4 退出标准 +**v2.1 审核修订**: 修正 004 章节引用断裂(§4.2/§11.4/§11.5/§15.3 不存在→改引 coord-cross-review);修正 ActionState 实现矛盾(degraded 从 error.details 移至顶层 details);补 RPC 至 12 个(GetStudentMastery/TriggerWarning);修正 HTTP 端点计数 14;Dockerfile HEALTHCHECK 改用 urllib 避免 curl 依赖;新增 §19 NFR 章节 +**v2 审核结论**: 16 项遗漏已全部补强(3 项 P0 + 5 项 P1 + 8 项 P2),文档进入实现阶段无阻塞(P4 阻塞项:iam.proto GetEffectiveDataScope + events.proto AIUsageEvent 待 coord 落实,可用 fallback/mock 兜底)