syntax = "proto3"; 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.). // // Event routing (TOPIC_MAP in outbox.publisher.ts): // 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 // EventMetadata 事件元数据(trace_id + 请求来源等). message EventMetadata { string trace_id = 1; string source = 2; string version = 3; } message ClassEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string class_id = 5; string name = 6; string action = 7; EventMetadata metadata = 8; } message ExamEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string exam_id = 5; string class_id = 6; string subject_id = 7; string title = 8; string action = 9; EventMetadata metadata = 10; } message HomeworkEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string homework_id = 5; string class_id = 6; string subject_id = 7; string title = 8; string action = 9; EventMetadata metadata = 10; } message GradeEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string grade_id = 5; string student_id = 6; string score = 7; string total_score = 8; string action = 9; EventMetadata metadata = 10; } message AttendanceEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string attendance_id = 5; string schedule_id = 6; string student_id = 7; string status = 8; EventMetadata metadata = 9; } // IAM 用户事件(edu.iam.user.events topic) // action: created / updated / disabled / role_changed message UserEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string user_id = 5; string email = 6; string name = 7; repeated string roles = 8; string data_scope = 9; string action = 10; map metadata = 11; } // IAM 角色事件(edu.iam.role.events topic) // action: created / updated / deleted message RoleEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string role_id = 5; string role_name = 6; string action = 7; map metadata = 8; } // IAM 审计事件(edu.iam.audit.created topic,统一审计 topic) // action: create / update / delete / login / logout / permission_change message AuditEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string actor_user_id = 5; string action = 6; string resource_type = 7; string resource_id = 8; string before_state = 9; string after_state = 10; string ip = 11; string user_agent = 12; string trace_id = 13; map metadata = 14; } message TextbookEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string textbook_id = 5; string title = 6; string subject_id = 7; string grade_id = 8; string version = 9; string action = 10; map metadata = 11; } message ChapterEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string chapter_id = 5; string textbook_id = 6; string title = 7; int32 order = 8; string action = 9; map metadata = 10; } message KnowledgePointEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string kp_id = 5; string chapter_id = 6; string title = 7; int32 difficulty = 8; string action = 9; string prerequisite_id = 10; map metadata = 11; } message QuestionEvent { string event_id = 1; string aggregate_id = 2; string event_type = 3; int64 occurred_at = 4; string question_id = 5; string kp_id = 6; string type = 7; int32 difficulty = 8; string status = 9; string source = 10; string created_by = 11; string action = 12; map metadata = 13; } // 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 metadata = 13; } // AIUsageEvent AI 用量计费事件(ai 服务发布,data-ana 消费落 ClickHouse) // 派生数据,豁免 Outbox(004 §12.2);topic: edu.ai.usage(matrix.md §4 + ISSUE-02 裁决) message AIUsageEvent { string event_id = 1; // UUID,幂等去重 string aggregate_id = 2; // workflow_id 或 request_id string event_type = 3; // 固定 "AIUsageRecorded" int64 occurred_at = 4; // Unix 毫秒时间戳 string user_id = 5; string school_id = 6; // 用于多租户配额 string request_id = 7; // 链路追踪 ID string provider = 8; // openai/anthropic/baichuan/local_ollama string model = 9; // gpt-4o-mini/claude-3-haiku/... string operation = 10; // chat/generate_question/optimize_expression/lesson_preparation uint32 prompt_tokens = 11; uint32 completion_tokens = 12; uint32 total_tokens = 13; uint32 latency_ms = 14; bool success = 15; bool degraded = 16; // 是否降级(LLM 不可用时) uint32 cost_cents = 17; // 计费(分) map metadata = 18; // 额外上下文(subject/grade/difficulty 等) }