feat(data-ana): 完整实现 data-ana 数据分析服务
包含 CDC consumer、analytics/mastery/warning service、grpc server、repository、ClickHouse DDL 等
This commit is contained in:
@@ -2,24 +2,113 @@ syntax = "proto3";
|
||||
|
||||
package next_edu_cloud.analytics.v1;
|
||||
|
||||
// AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
// P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
// 所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
service AnalyticsService {
|
||||
// 班级成绩分析(平均分/及格率/参考人数).
|
||||
rpc GetClassPerformance(GetClassPerformanceRequest) returns (ClassPerformance);
|
||||
// 学生薄弱知识点(mastery_level < 0.6).
|
||||
rpc GetStudentWeakness(GetStudentWeaknessRequest) returns (StudentWeakness);
|
||||
// 学习趋势(历史成绩曲线).
|
||||
rpc GetLearningTrend(GetLearningTrendRequest) returns (LearningTrend);
|
||||
// 教师仪表盘聚合(班级概览 + 待办 + 预警).
|
||||
rpc GetTeacherDashboard(GetTeacherDashboardRequest) returns (TeacherDashboard);
|
||||
// 学生仪表盘(个人学情 + 排名 + 薄弱点).
|
||||
rpc GetStudentDashboard(GetStudentDashboardRequest) returns (StudentDashboard);
|
||||
// 家长仪表盘(孩子学情概览).
|
||||
rpc GetParentDashboard(GetParentDashboardRequest) returns (ParentDashboard);
|
||||
// 管理员仪表盘(全校统计 + AI 用量).
|
||||
rpc GetAdminDashboard(GetAdminDashboardRequest) returns (AdminDashboard);
|
||||
// 预警列表查询(按班级/严重度/时间过滤).
|
||||
rpc GetWarnings(GetWarningsRequest) returns (WarningList);
|
||||
// 手动触发预警(管理员/教师主动标记关注).
|
||||
rpc TriggerWarning(TriggerWarningRequest) returns (TriggerWarningResponse);
|
||||
// 班级掌握度分布(mastered/progressing/weak 三档).
|
||||
rpc GetMasteryDistribution(GetMasteryDistributionRequest) returns (MasteryDistribution);
|
||||
// 学生知识点掌握度明细.
|
||||
rpc GetStudentMastery(GetStudentMasteryRequest) returns (StudentMastery);
|
||||
// 订阅掌握度更新(server-streaming,P5+ AI 个性化推荐实时推送通道).
|
||||
rpc SubscribeMasteryUpdate(SubscribeMasteryUpdateRequest) returns (stream MasteryUpdateEvent);
|
||||
}
|
||||
|
||||
// ===== 请求消息 =====
|
||||
|
||||
message GetClassPerformanceRequest {
|
||||
string class_id = 1;
|
||||
string subject_id = 2;
|
||||
int64 start_date = 3;
|
||||
int64 start_date = 3; // Unix timestamp(秒)
|
||||
int64 end_date = 4;
|
||||
}
|
||||
|
||||
message GetStudentWeaknessRequest {
|
||||
string student_id = 1;
|
||||
string subject_id = 2;
|
||||
}
|
||||
|
||||
message GetLearningTrendRequest {
|
||||
string student_id = 1;
|
||||
int64 start_date = 2;
|
||||
int64 end_date = 3;
|
||||
string subject_id = 4;
|
||||
}
|
||||
|
||||
message GetTeacherDashboardRequest {
|
||||
string user_id = 1;
|
||||
string class_id = 2; // 可选,不传则返回教师全部班级
|
||||
}
|
||||
|
||||
message GetStudentDashboardRequest {
|
||||
string user_id = 1;
|
||||
}
|
||||
|
||||
message GetParentDashboardRequest {
|
||||
string user_id = 1;
|
||||
string student_id = 2; // 家长查看指定孩子
|
||||
}
|
||||
|
||||
message GetAdminDashboardRequest {
|
||||
string user_id = 1;
|
||||
string scope = 2; // ALL / SCHOOL / DISTRICT
|
||||
string scope_id = 3; // 具体范围 ID
|
||||
}
|
||||
|
||||
message GetWarningsRequest {
|
||||
string class_id = 1;
|
||||
string severity = 2; // INFO / WARN / CRITICAL
|
||||
int64 since = 3; // Unix timestamp(秒)
|
||||
}
|
||||
|
||||
message TriggerWarningRequest {
|
||||
string target_id = 1; // 学生 ID
|
||||
string warning_type = 2; // LOW_MASTERY / SCORE_DROP / ABSENT_FREQUENT
|
||||
string severity = 3; // INFO / WARN / CRITICAL
|
||||
}
|
||||
|
||||
message GetMasteryDistributionRequest {
|
||||
string class_id = 1;
|
||||
string subject_id = 2;
|
||||
string knowledge_point_id = 3; // 可选
|
||||
}
|
||||
|
||||
message GetStudentMasteryRequest {
|
||||
string student_id = 1;
|
||||
string subject_id = 2; // 可选
|
||||
}
|
||||
|
||||
message SubscribeMasteryUpdateRequest {
|
||||
string student_id = 1; // 可选,订阅指定学生
|
||||
string class_id = 2; // 可选,订阅指定班级全部学生
|
||||
}
|
||||
|
||||
// ===== 响应消息 =====
|
||||
|
||||
message ClassPerformance {
|
||||
string class_id = 1;
|
||||
double average_score = 2;
|
||||
double pass_rate = 3;
|
||||
repeated StudentScore scores = 4;
|
||||
int32 total_students = 4;
|
||||
repeated StudentScore scores = 5;
|
||||
}
|
||||
|
||||
message StudentScore {
|
||||
@@ -28,11 +117,6 @@ message StudentScore {
|
||||
string grade = 3;
|
||||
}
|
||||
|
||||
message GetStudentWeaknessRequest {
|
||||
string student_id = 1;
|
||||
string subject_id = 2;
|
||||
}
|
||||
|
||||
message StudentWeakness {
|
||||
string student_id = 1;
|
||||
repeated WeakPoint weak_points = 2;
|
||||
@@ -42,12 +126,7 @@ message WeakPoint {
|
||||
string knowledge_point_id = 1;
|
||||
string title = 2;
|
||||
double mastery = 3;
|
||||
}
|
||||
|
||||
message GetLearningTrendRequest {
|
||||
string student_id = 1;
|
||||
int64 start_date = 2;
|
||||
int64 end_date = 3;
|
||||
int32 error_count = 4;
|
||||
}
|
||||
|
||||
message LearningTrend {
|
||||
@@ -59,3 +138,125 @@ message TrendPoint {
|
||||
int64 date = 1;
|
||||
double score = 2;
|
||||
}
|
||||
|
||||
message TeacherDashboard {
|
||||
string user_id = 1;
|
||||
int32 total_classes = 2;
|
||||
int32 total_students = 3;
|
||||
double class_avg_score = 4;
|
||||
int32 pending_homework_count = 5;
|
||||
repeated ClassSummary classes = 6;
|
||||
repeated StudentSummary top_students = 7;
|
||||
repeated WarningInfo recent_warnings = 8;
|
||||
}
|
||||
|
||||
message ClassSummary {
|
||||
string class_id = 1;
|
||||
string class_name = 2;
|
||||
int32 student_count = 3;
|
||||
double average_score = 4;
|
||||
}
|
||||
|
||||
message StudentSummary {
|
||||
string student_id = 1;
|
||||
string student_name = 2;
|
||||
double score = 3;
|
||||
int32 rank_in_class = 4;
|
||||
}
|
||||
|
||||
message StudentDashboard {
|
||||
string user_id = 1;
|
||||
double avg_score = 2;
|
||||
int32 class_rank = 3;
|
||||
int32 total_students = 4;
|
||||
repeated WeakPoint weak_points = 5;
|
||||
repeated TrendPoint recent_trends = 6;
|
||||
int32 pending_homework = 7;
|
||||
}
|
||||
|
||||
message ParentDashboard {
|
||||
string user_id = 1;
|
||||
string student_id = 2;
|
||||
double child_avg_score = 3;
|
||||
int32 child_class_rank = 4;
|
||||
int32 total_class_students = 5;
|
||||
repeated WeakPoint child_weak_points = 6;
|
||||
repeated WarningInfo child_warnings = 7;
|
||||
}
|
||||
|
||||
message AdminDashboard {
|
||||
string user_id = 1;
|
||||
int32 total_teachers = 2;
|
||||
int32 total_students = 3;
|
||||
int32 total_classes = 4;
|
||||
double school_avg_score = 5;
|
||||
repeated WarningInfo recent_warnings = 6;
|
||||
AIUsageSummary ai_usage = 7;
|
||||
}
|
||||
|
||||
message AIUsageSummary {
|
||||
int64 total_requests = 1;
|
||||
int64 total_tokens = 2;
|
||||
int64 total_cost_cents = 3;
|
||||
repeated AIUsageByProvider by_provider = 4;
|
||||
}
|
||||
|
||||
message AIUsageByProvider {
|
||||
string provider = 1;
|
||||
int64 request_count = 2;
|
||||
int64 total_tokens = 3;
|
||||
int64 cost_cents = 4;
|
||||
}
|
||||
|
||||
message WarningList {
|
||||
repeated WarningInfo warnings = 1;
|
||||
int32 total = 2;
|
||||
}
|
||||
|
||||
message WarningInfo {
|
||||
string warning_id = 1;
|
||||
string warning_type = 2; // LOW_MASTERY / CRITICAL_LOW / SCORE_DROP / ABSENT_FREQUENT / TREND_DECLINE
|
||||
string target_id = 3; // 学生 ID
|
||||
string target_name = 4;
|
||||
double threshold = 5;
|
||||
double current_value = 6;
|
||||
string severity = 7; // INFO / WARN / CRITICAL
|
||||
int64 occurred_at = 8; // Unix timestamp(秒)
|
||||
}
|
||||
|
||||
message TriggerWarningResponse {
|
||||
string warning_id = 1;
|
||||
bool triggered = 2;
|
||||
}
|
||||
|
||||
message MasteryDistribution {
|
||||
string class_id = 1;
|
||||
int32 mastered_count = 2; // mastery >= 0.8
|
||||
int32 progressing_count = 3; // 0.4 <= mastery < 0.8
|
||||
int32 weak_count = 4; // mastery < 0.4
|
||||
int32 total_students = 5;
|
||||
}
|
||||
|
||||
message StudentMastery {
|
||||
string student_id = 1;
|
||||
repeated KnowledgePointMastery knowledge_points = 2;
|
||||
double overall_mastery = 3;
|
||||
}
|
||||
|
||||
message KnowledgePointMastery {
|
||||
string knowledge_point_id = 1;
|
||||
string title = 2;
|
||||
string subject_id = 3;
|
||||
double mastery_level = 4; // 0.0-1.0
|
||||
string mastery_label = 5; // mastered / progressing / weak
|
||||
int64 calculated_at = 6; // Unix timestamp(秒)
|
||||
}
|
||||
|
||||
message MasteryUpdateEvent {
|
||||
string event_id = 1;
|
||||
string student_id = 2;
|
||||
string knowledge_point_id = 3;
|
||||
double mastery_level = 4;
|
||||
double previous_level = 5;
|
||||
int64 calculated_at = 6; // Unix timestamp(秒)
|
||||
}
|
||||
|
||||
@@ -4,13 +4,17 @@ package next_edu_cloud.events.v1;
|
||||
|
||||
// Cross-service event contracts published by CoreEdu via the transactional
|
||||
// outbox pattern and consumed by downstream services (notifications, analytics,
|
||||
// audit, etc.). Topics follow the convention edu.{domain}.events.
|
||||
// audit, etc.).
|
||||
//
|
||||
// Event routing (TOPIC_MAP in outbox.publisher.ts):
|
||||
// edu.exam.events <- exam.created / exam.updated / exam.deleted
|
||||
// edu.homework.events <- homework.assigned / homework.submitted / homework.graded
|
||||
// edu.grade.events <- grade.recorded / grade.updated
|
||||
// edu.class.events <- class.transferred
|
||||
// edu.teaching.exam.published <- exam.published
|
||||
// edu.teaching.homework.assigned <- homework.assigned / homework.submitted / homework.graded
|
||||
// edu.teaching.grade.recorded <- grade.recorded / grade.updated
|
||||
// edu.teaching.class.transferred <- class.transferred
|
||||
//
|
||||
// Derived data events (Outbox exempt, see 004 §12.2):
|
||||
// edu.insight.mastery.updated <- mastery.updated / warning.triggered (action field distinguishes)
|
||||
// edu.insight.ai.usage <- ai.usage.recorded
|
||||
|
||||
message ClassEvent {
|
||||
string event_id = 1;
|
||||
@@ -58,3 +62,40 @@ message GradeEvent {
|
||||
string action = 8;
|
||||
map<string, string> metadata = 9;
|
||||
}
|
||||
|
||||
// MasteryEvent 掌握度/预警派生数据事件(Outbox 豁免,直接 Kafka producer 发布).
|
||||
// action 字段区分:mastery.updated(掌握度更新)/ warning.triggered(预警触发).
|
||||
// 两者复用同一 topic edu.insight.mastery.updated(总裁裁决 §2.11).
|
||||
message MasteryEvent {
|
||||
string event_id = 1;
|
||||
string action = 2; // mastery.updated / warning.triggered
|
||||
int64 occurred_at = 3;
|
||||
string student_id = 4;
|
||||
string knowledge_point_id = 5;
|
||||
double mastery_level = 6; // 0.0-1.0(mastery.updated 时有效)
|
||||
double previous_level = 7; // 上一次掌握度(mastery.updated 时有效)
|
||||
// warning.triggered 时以下字段有效
|
||||
string warning_type = 8; // LOW_MASTERY / CRITICAL_LOW / SCORE_DROP / ABSENT_FREQUENT / TREND_DECLINE
|
||||
string target_id = 9; // 预警目标(学生 ID)
|
||||
double threshold = 10; // 预警阈值
|
||||
double current_value = 11; // 当前值
|
||||
string severity = 12; // INFO / WARN / CRITICAL
|
||||
map<string, string> metadata = 13;
|
||||
}
|
||||
|
||||
// AIUsageEvent AI 用量计费事件(ai 服务发布,data-ana 消费落 ai_usage_log).
|
||||
message AIUsageEvent {
|
||||
string event_id = 1;
|
||||
string request_id = 2;
|
||||
string user_id = 3;
|
||||
string provider = 4; // openai / anthropic / baichuan / local
|
||||
string model = 5;
|
||||
uint32 prompt_tokens = 6;
|
||||
uint32 completion_tokens = 7;
|
||||
uint32 total_tokens = 8;
|
||||
uint32 latency_ms = 9;
|
||||
bool success = 10;
|
||||
uint32 cost_cents = 11; // 计费(分)
|
||||
int64 occurred_at = 12;
|
||||
map<string, string> metadata = 13;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ service IamService {
|
||||
rpc Login(LoginRequest) returns (AuthResponse);
|
||||
rpc RefreshToken(RefreshTokenRequest) returns (TokenPair);
|
||||
rpc GetUserInfo(GetUserInfoRequest) returns (UserInfo);
|
||||
// GetEffectiveDataScope 解析用户可见数据范围(DataScope 6 级).
|
||||
// data-ana gRPC 调用此 RPC 解析查询过滤范围(coord-cross-review §2 #3 裁决 P4 补全).
|
||||
rpc GetEffectiveDataScope(GetEffectiveDataScopeRequest) returns (EffectiveDataScope);
|
||||
}
|
||||
|
||||
message RegisterRequest {
|
||||
@@ -48,3 +51,17 @@ message UserInfo {
|
||||
repeated string roles = 4;
|
||||
repeated string permissions = 5;
|
||||
}
|
||||
|
||||
message GetEffectiveDataScopeRequest {
|
||||
string user_id = 1;
|
||||
}
|
||||
|
||||
// EffectiveDataScope 用户可见数据范围(6 级).
|
||||
// level: SELF / CLASS / GRADE / SCHOOL / DISTRICT / ALL
|
||||
// scope_ids: 具体可见的 class_id / grade_id 列表(SELF/ALL 时为空)
|
||||
message EffectiveDataScope {
|
||||
string user_id = 1;
|
||||
string level = 2; // SELF / CLASS / GRADE / SCHOOL / DISTRICT / ALL
|
||||
repeated string scope_ids = 3; // class_id 列表(CLASS 级)/ grade_id 列表(GRADE 级)
|
||||
string school_id = 4; // SCHOOL 级时的学校 ID
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user