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<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> metadata = 18; // 额外上下文（subject/grade/difficulty 等）
}
