Merge worktree branch merge-15-modules-to-main-5ug5xJ

This commit is contained in:
SpecialX
2026-07-10 15:28:20 +08:00
parent 60d7173545
commit df62ffc176
51 changed files with 11559 additions and 1908 deletions

View File

@@ -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` 派生数据事件(豁免 Outbox004 §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 级在查询层注入 WHEREiam `GetEffectiveDataScope` gRPC004 §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 级在查询层注入 WHEREiam `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. **长远架构演进**:为 P5ai 用量消费 / gRPC stream、P6CDC 水平扩展 / 容量规划 / 数据治理 / 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 RPC3 现有 + 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=Truedegraded 标记放 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 |
| 被调用 | aiP5+ | 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-eduCDC | Kafka | `edu-cdc.next_edu_cloud.core_edu_grades/exams/homework_submissions/attendance` | 学情 + 考勤数据投递 |
| 消费 | core-eduCDC | Kafka | `edu-cdc.next_edu_cloud.classes` | 班级维度同步 |
| 消费 | iamCDC | Kafka | `edu-cdc.next_edu_cloud.iam_users` | 用户 dataScope 同步 |
| 消费 | contentCDC | Kafka | `edu-cdc.next_edu_cloud.content_knowledge_points` | 知识点元数据同步v2 新增) |
| 消费 | aiP5+ | 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 | 掌握度更新通知 |
| 消费 | aiP5+ | 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 API004 §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 未实现此 RPCP4 阻塞项**。若 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` topic004 §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是否合规 | ✅ 已仲裁:派生数据事件豁免 Outbox004 §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. 非功能性需求NFRv2.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 RPCv2 提案扩展 7 RPC |
| 路由 | ✅ | HTTP 13 端点 + gRPC 10 RPC |
| 契约proto | ✅ | analytics.proto 已定义 3 RPCv2 提案扩展至 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 + /readyzv2 补 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 端点计数 14Dockerfile HEALTHCHECK 改用 urllib 避免 curl 依赖;新增 §19 NFR 章节
**v2 审核结论**: 16 项遗漏已全部补强3 项 P0 + 5 项 P1 + 8 项 P2文档进入实现阶段无阻塞P4 阻塞项iam.proto GetEffectiveDataScope + events.proto AIUsageEvent 待 coord 落实,可用 fallback/mock 兜底)