Merge worktree branch merge-15-modules-to-main-5ug5xJ
This commit is contained in:
@@ -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。
|
||||
|
||||
|
||||
@@ -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 兜底)
|
||||
|
||||
Reference in New Issue
Block a user