-- ============================================================
-- Edu 微服务 All-Services Schema (P2 阶段，单库 next_edu_cloud)
-- 由 Drizzle ORM schema 文件转换而来
-- 使用 CREATE TABLE IF NOT EXISTS，可重复执行
-- 字符集：utf8mb4 / utf8mb4_unicode_ci；引擎：InnoDB
-- ============================================================

-- ============================================================
-- 1. IAM 服务（services/iam/src/iam/iam.schema.ts）
-- ============================================================

-- 1.1 用户表
CREATE TABLE IF NOT EXISTS `iam_users` (
  `id` CHAR(36) NOT NULL,
  `email` VARCHAR(255) NOT NULL,
  `password_hash` VARCHAR(255) NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'active',
  `data_scope` ENUM('self','subject','class','grade','school','all') NOT NULL DEFAULT 'self',
  `password_changed_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_iam_users_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.2 角色表
CREATE TABLE IF NOT EXISTS `iam_roles` (
  `id` CHAR(36) NOT NULL,
  `name` VARCHAR(50) NOT NULL,
  `description` VARCHAR(255) NULL,
  `role_type` ENUM('system','organization','temporary') NOT NULL DEFAULT 'system',
  `level` INT NOT NULL DEFAULT 0,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_iam_roles_name` (`name`),
  INDEX `idx_iam_roles_type` (`role_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.3 用户-角色关联表
CREATE TABLE IF NOT EXISTS `iam_user_roles` (
  `user_id` CHAR(36) NOT NULL,
  `role_id` CHAR(36) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX `idx_iam_user_roles_pk` (`user_id`, `role_id`),
  INDEX `idx_iam_user_roles_role` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.4 权限表
CREATE TABLE IF NOT EXISTS `iam_permissions` (
  `id` CHAR(36) NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `resource` VARCHAR(50) NOT NULL,
  `action` VARCHAR(50) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_iam_permissions_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.5 角色-权限关联表
CREATE TABLE IF NOT EXISTS `iam_role_permissions` (
  `role_id` CHAR(36) NOT NULL,
  `permission_id` CHAR(36) NOT NULL,
  INDEX `idx_iam_role_permissions_pk` (`role_id`, `permission_id`),
  INDEX `idx_iam_role_permissions_perm` (`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.6 刷新令牌表
CREATE TABLE IF NOT EXISTS `iam_refresh_tokens` (
  `id` CHAR(36) NOT NULL,
  `user_id` CHAR(36) NOT NULL,
  `token_hash` VARCHAR(255) NOT NULL,
  `jti` VARCHAR(36) NULL,
  `expires_at` TIMESTAMP NOT NULL,
  `revoked_at` TIMESTAMP NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_iam_refresh_tokens_user` (`user_id`),
  INDEX `idx_iam_refresh_tokens_jti` (`jti`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.7 视口配置表（4 层模型）
CREATE TABLE IF NOT EXISTS `iam_role_viewports` (
  `id` CHAR(36) NOT NULL,
  `role_id` CHAR(36) NOT NULL,
  `viewport_key` VARCHAR(50) NOT NULL,
  `label` VARCHAR(100) NOT NULL,
  `route` VARCHAR(200) NOT NULL,
  `icon` VARCHAR(50) NULL,
  `sort_order` VARCHAR(10) NOT NULL DEFAULT '0',
  `required_permission` VARCHAR(100) NULL,
  `level` ENUM('admin','teacher','student','parent') NOT NULL DEFAULT 'teacher',
  `component_config` TEXT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_iam_role_viewports_role` (`role_id`),
  INDEX `idx_iam_role_viewports_level` (`level`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.8 学生-家长关系表
CREATE TABLE IF NOT EXISTS `iam_student_guardians` (
  `id` CHAR(36) NOT NULL,
  `student_id` CHAR(36) NOT NULL,
  `guardian_id` CHAR(36) NOT NULL,
  `relation` VARCHAR(20) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_student_guardian` (`student_id`, `guardian_id`),
  INDEX `idx_iam_student_guardians_guardian` (`guardian_id`),
  INDEX `idx_iam_student_guardians_student` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.9 审计日志表
CREATE TABLE IF NOT EXISTS `iam_user_audit_log` (
  `id` CHAR(36) NOT NULL,
  `actor_user_id` CHAR(36) NOT NULL,
  `action` VARCHAR(50) NOT NULL,
  `resource_type` VARCHAR(50) NOT NULL,
  `resource_id` VARCHAR(36) NOT NULL,
  `before_state` TEXT NULL,
  `after_state` TEXT NULL,
  `ip` VARCHAR(45) NULL,
  `user_agent` VARCHAR(255) NULL,
  `trace_id` VARCHAR(64) NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_iam_audit_actor` (`actor_user_id`),
  INDEX `idx_iam_audit_resource` (`resource_type`, `resource_id`),
  INDEX `idx_iam_audit_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 1.10 密码历史表
CREATE TABLE IF NOT EXISTS `iam_password_history` (
  `id` CHAR(36) NOT NULL,
  `user_id` CHAR(36) NOT NULL,
  `password_hash` VARCHAR(255) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_iam_password_history_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


-- ============================================================
-- 2. Classes 服务（services/classes/src/classes/classes.schema.ts）
-- 班级表（已在 01-init.sql 中创建，此处保留以保完整性，IF NOT EXISTS 安全）
-- ============================================================

CREATE TABLE IF NOT EXISTS `classes` (
  `id` CHAR(36) NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `grade_id` CHAR(36) NOT NULL,
  `head_teacher_id` CHAR(36) NULL,
  `description` TEXT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


-- ============================================================
-- 3. Core-EDU 服务（services/core-edu/src/**/*.schema.ts）
-- ============================================================

-- 3.1 教师关联表（IAM 事件消费幂等）
CREATE TABLE IF NOT EXISTS `core_edu_teacher_associations` (
  `id` CHAR(36) NOT NULL,
  `teacher_id` CHAR(36) NOT NULL,
  `class_id` CHAR(36) NOT NULL,
  `subject_id` CHAR(36) NULL,
  `school_id` CHAR(36) NOT NULL,
  `source` VARCHAR(20) NOT NULL DEFAULT 'iam_event',
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_teacher_class_subject` (`teacher_id`, `class_id`, `subject_id`),
  INDEX `idx_teacher_assoc_teacher_id` (`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.2 考试主表
CREATE TABLE IF NOT EXISTS `core_edu_exams` (
  `id` CHAR(36) NOT NULL,
  `class_id` CHAR(36) NOT NULL,
  `subject_id` CHAR(36) NOT NULL,
  `title` VARCHAR(200) NOT NULL,
  `description` TEXT NULL,
  `exam_date` DATETIME NOT NULL,
  `duration` INT NOT NULL,
  `total_score` DECIMAL(6,2) NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'draft',
  `status_changed_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status_changed_by` CHAR(36) NULL,
  `school_id` CHAR(36) NOT NULL,
  `created_by` CHAR(36) NOT NULL,
  `archived_at` DATETIME NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_exams_class_status` (`class_id`, `status`),
  INDEX `idx_exams_school_date` (`school_id`, `exam_date`),
  INDEX `idx_exams_created_by` (`created_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.3 考试题目关联表
CREATE TABLE IF NOT EXISTS `core_edu_exam_questions` (
  `id` CHAR(36) NOT NULL,
  `exam_id` CHAR(36) NOT NULL,
  `question_id` CHAR(36) NOT NULL,
  `order` INT NOT NULL,
  `score` DECIMAL(6,2) NOT NULL,
  `question_type` VARCHAR(30) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_exam_questions_exam_id` (`exam_id`),
  INDEX `idx_exam_questions_question_id` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.4 考试提交表
CREATE TABLE IF NOT EXISTS `core_edu_exam_submissions` (
  `id` CHAR(36) NOT NULL,
  `exam_id` CHAR(36) NOT NULL,
  `student_id` CHAR(36) NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'not_submitted',
  `submitted_at` DATETIME NULL,
  `graded_at` DATETIME NULL,
  `graded_by` CHAR(36) NULL,
  `total_score` DECIMAL(6,2) NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_exam_student` (`exam_id`, `student_id`),
  INDEX `idx_exam_submissions_exam_id` (`exam_id`),
  INDEX `idx_exam_submissions_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.5 作业主表
CREATE TABLE IF NOT EXISTS `core_edu_homework` (
  `id` CHAR(36) NOT NULL,
  `class_id` CHAR(36) NOT NULL,
  `subject_id` CHAR(36) NOT NULL,
  `title` VARCHAR(200) NOT NULL,
  `description` TEXT NULL,
  `due_date` DATETIME NOT NULL,
  `grace_period` INT NOT NULL DEFAULT 300,
  `status` VARCHAR(20) NOT NULL DEFAULT 'assigned',
  `school_id` CHAR(36) NOT NULL,
  `created_by` CHAR(36) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_homework_class_status` (`class_id`, `status`),
  INDEX `idx_homework_created_by` (`created_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.6 作业提交表
CREATE TABLE IF NOT EXISTS `core_edu_homework_submissions` (
  `id` CHAR(36) NOT NULL,
  `homework_id` CHAR(36) NOT NULL,
  `student_id` CHAR(36) NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'not_submitted',
  `submitted_at` DATETIME NULL,
  `graded_at` DATETIME NULL,
  `graded_by` CHAR(36) NULL,
  `total_score` DECIMAL(6,2) NULL,
  `feedback` TEXT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_hw_student` (`homework_id`, `student_id`),
  INDEX `idx_hw_submissions_homework_id` (`homework_id`),
  INDEX `idx_hw_submissions_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.7 作业答题表
CREATE TABLE IF NOT EXISTS `core_edu_homework_answers` (
  `id` CHAR(36) NOT NULL,
  `submission_id` CHAR(36) NOT NULL,
  `question_id` CHAR(36) NOT NULL,
  `answer` TEXT NULL,
  `score` DECIMAL(6,2) NULL,
  `teacher_comment` TEXT NULL,
  `is_correct` TINYINT(1) NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_hw_answers_submission_id` (`submission_id`),
  INDEX `idx_hw_answers_question_id` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.8 成绩主表
CREATE TABLE IF NOT EXISTS `core_edu_grades` (
  `id` CHAR(36) NOT NULL,
  `student_id` CHAR(36) NOT NULL,
  `exam_id` CHAR(36) NULL,
  `homework_id` CHAR(36) NULL,
  `score` DECIMAL(6,2) NOT NULL,
  `total_score` DECIMAL(6,2) NOT NULL,
  `feedback` TEXT NULL,
  `graded_by` CHAR(36) NOT NULL,
  `school_id` CHAR(36) NOT NULL,
  `idempotency_key` VARCHAR(128) NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_student_exam` (`student_id`, `exam_id`),
  UNIQUE KEY `uniq_student_hw` (`student_id`, `homework_id`),
  UNIQUE KEY `uniq_idempotency` (`idempotency_key`),
  INDEX `idx_grades_student_id` (`student_id`),
  INDEX `idx_grades_exam_id` (`exam_id`),
  INDEX `idx_grades_homework_id` (`homework_id`),
  INDEX `idx_grades_graded_by` (`graded_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.9 成绩公式表
CREATE TABLE IF NOT EXISTS `core_edu_grade_formulas` (
  `id` CHAR(36) NOT NULL,
  `scope` VARCHAR(20) NOT NULL,
  `scope_id` CHAR(36) NOT NULL,
  `formula_type` VARCHAR(20) NOT NULL,
  `weights` JSON NULL,
  `custom_expression` TEXT NULL,
  `effective_from` DATETIME NOT NULL,
  `effective_to` DATETIME NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_grade_formulas_scope` (`scope`, `scope_id`),
  INDEX `idx_grade_formulas_effective` (`effective_from`, `effective_to`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.10 考勤记录表
CREATE TABLE IF NOT EXISTS `core_edu_attendance` (
  `id` CHAR(36) NOT NULL,
  `schedule_id` CHAR(36) NOT NULL,
  `student_id` CHAR(36) NOT NULL,
  `status` VARCHAR(20) NOT NULL,
  `remark` TEXT NULL,
  `recorded_by` CHAR(36) NOT NULL,
  `school_id` CHAR(36) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_sched_student` (`schedule_id`, `student_id`),
  INDEX `idx_attendance_student_id` (`student_id`),
  INDEX `idx_attendance_schedule_id` (`schedule_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.11 课程表
CREATE TABLE IF NOT EXISTS `core_edu_courses` (
  `id` CHAR(36) NOT NULL,
  `class_id` CHAR(36) NOT NULL,
  `subject_id` CHAR(36) NOT NULL,
  `teacher_id` CHAR(36) NOT NULL,
  `school_id` CHAR(36) NOT NULL,
  `name` VARCHAR(200) NOT NULL,
  `start_date` DATE NOT NULL,
  `end_date` DATE NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_courses_class_id` (`class_id`),
  INDEX `idx_courses_teacher_id` (`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.12 课次表
CREATE TABLE IF NOT EXISTS `core_edu_lessons` (
  `id` CHAR(36) NOT NULL,
  `course_id` CHAR(36) NOT NULL,
  `title` VARCHAR(200) NOT NULL,
  `order` INT NOT NULL,
  `knowledge_point_ids` JSON NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_lessons_course_id` (`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.13 排课表
CREATE TABLE IF NOT EXISTS `core_edu_schedules` (
  `id` CHAR(36) NOT NULL,
  `course_id` CHAR(36) NOT NULL,
  `lesson_id` CHAR(36) NULL,
  `teacher_id` CHAR(36) NOT NULL,
  `class_id` CHAR(36) NOT NULL,
  `room_id` CHAR(36) NULL,
  `start_time` DATETIME NOT NULL,
  `end_time` DATETIME NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'scheduled',
  `school_id` CHAR(36) NOT NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_schedules_teacher_time` (`teacher_id`, `start_time`, `end_time`),
  INDEX `idx_schedules_class_time` (`class_id`, `start_time`, `end_time`),
  INDEX `idx_schedules_course_id` (`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 3.14 Core-EDU Outbox 表（事务性发件箱）
CREATE TABLE IF NOT EXISTS `core_edu_outbox` (
  `id` CHAR(36) NOT NULL,
  `event_id` CHAR(36) NOT NULL,
  `aggregate_id` CHAR(36) NOT NULL,
  `aggregate_type` VARCHAR(50) NOT NULL,
  `event_type` VARCHAR(100) NOT NULL,
  `occurred_at` DATETIME NOT NULL,
  `payload` TEXT NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'pending',
  `retry_count` BIGINT NOT NULL DEFAULT 0,
  `next_retry_at` DATETIME NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `processed_at` TIMESTAMP NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_event_id` (`event_id`),
  INDEX `idx_outbox_status_retry` (`status`, `next_retry_at`),
  INDEX `idx_outbox_aggregate` (`aggregate_type`, `aggregate_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


-- ============================================================
-- 4. Content 服务（services/content/src/**/*.schema.ts）
-- ============================================================

-- 4.1 教材表
CREATE TABLE IF NOT EXISTS `content_textbooks` (
  `id` VARCHAR(32) NOT NULL,
  `title` VARCHAR(255) NOT NULL,
  `subject_id` VARCHAR(32) NOT NULL,
  `grade_id` VARCHAR(32) NOT NULL,
  `version` VARCHAR(32) NOT NULL DEFAULT '1.0',
  `status` VARCHAR(32) NOT NULL DEFAULT 'draft',
  `tenant_id` VARCHAR(32) NULL,
  `metadata` JSON NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_textbooks_subject_grade` (`subject_id`, `grade_id`),
  INDEX `idx_textbooks_status` (`status`),
  INDEX `idx_textbooks_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 4.2 章节表
CREATE TABLE IF NOT EXISTS `content_chapters` (
  `id` VARCHAR(32) NOT NULL,
  `textbook_id` VARCHAR(32) NOT NULL,
  `title` VARCHAR(255) NOT NULL,
  `order_num` INT NOT NULL DEFAULT 0,
  `parent_id` VARCHAR(32) NULL,
  `status` VARCHAR(32) NOT NULL DEFAULT 'draft',
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_chapters_textbook_order` (`textbook_id`, `order_num`),
  INDEX `idx_chapters_parent` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 4.3 知识点表
CREATE TABLE IF NOT EXISTS `content_knowledge_points` (
  `id` VARCHAR(32) NOT NULL,
  `chapter_id` VARCHAR(32) NOT NULL,
  `title` VARCHAR(255) NOT NULL,
  `description` TEXT NULL,
  `difficulty` TINYINT NOT NULL DEFAULT 3,
  `metadata` JSON NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_kp_chapter` (`chapter_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 4.4 题目表
CREATE TABLE IF NOT EXISTS `content_questions` (
  `id` VARCHAR(32) NOT NULL,
  `knowledge_point_id` VARCHAR(32) NOT NULL,
  `type` VARCHAR(32) NOT NULL,
  `content` TEXT NOT NULL,
  `options` JSON NULL,
  `answer` TEXT NOT NULL,
  `explanation` TEXT NULL,
  `difficulty` TINYINT NOT NULL DEFAULT 3,
  `status` VARCHAR(32) NOT NULL DEFAULT 'draft',
  `source` VARCHAR(32) NOT NULL DEFAULT 'manual',
  `created_by` VARCHAR(32) NOT NULL,
  `metadata` JSON NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `idx_questions_kp` (`knowledge_point_id`),
  INDEX `idx_questions_type_difficulty` (`type`, `difficulty`),
  INDEX `idx_questions_status` (`status`),
  INDEX `idx_questions_source` (`source`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 4.5 Content Outbox 表
CREATE TABLE IF NOT EXISTS `content_outbox_events` (
  `id` VARCHAR(32) NOT NULL,
  `aggregate_type` VARCHAR(64) NOT NULL,
  `aggregate_id` VARCHAR(36) NOT NULL,
  `event_type` VARCHAR(100) NOT NULL,
  `topic` VARCHAR(128) NOT NULL,
  `payload` TEXT NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT 'pending',
  `retry_count` INT NOT NULL DEFAULT 0,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `published_at` TIMESTAMP NULL,
  `next_retry_at` TIMESTAMP NULL,
  `last_error` TEXT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_outbox_status_retry` (`status`, `next_retry_at`),
  INDEX `idx_outbox_aggregate` (`aggregate_type`, `aggregate_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


-- ============================================================
-- 5. MSG 服务（services/msg/src/**/*.schema.ts）
-- ============================================================

-- 5.1 通知主表
CREATE TABLE IF NOT EXISTS `msg_notifications` (
  `id` VARCHAR(32) NOT NULL,
  `user_id` VARCHAR(32) NOT NULL,
  `type` VARCHAR(32) NOT NULL,
  `title` VARCHAR(255) NOT NULL,
  `content` TEXT NOT NULL,
  `channel` VARCHAR(32) NOT NULL,
  `is_read` TINYINT(1) NOT NULL DEFAULT 0,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` VARCHAR(32) NOT NULL DEFAULT 'pending',
  `metadata` JSON NULL,
  `related_entity_type` VARCHAR(64) NULL,
  `related_entity_id` VARCHAR(32) NULL,
  `group_id` VARCHAR(32) NULL,
  `sender_id` VARCHAR(32) NULL,
  `template_id` VARCHAR(32) NULL,
  `event_id` VARCHAR(64) NULL,
  `read_at` TIMESTAMP NULL,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 5.2 用户偏好表
CREATE TABLE IF NOT EXISTS `msg_notification_preferences` (
  `id` VARCHAR(32) NOT NULL,
  `user_id` VARCHAR(32) NOT NULL,
  `type` VARCHAR(32) NOT NULL,
  `channels` JSON NOT NULL,
  `frequency_limit` INT NULL,
  `quiet_hours_start` VARCHAR(8) NULL,
  `quiet_hours_end` VARCHAR(8) NULL,
  `quiet_hours_timezone` VARCHAR(64) NULL DEFAULT 'Asia/Shanghai',
  `enabled` TINYINT(1) NOT NULL DEFAULT 1,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 5.3 通知模板表
CREATE TABLE IF NOT EXISTS `msg_notification_templates` (
  `id` VARCHAR(32) NOT NULL,
  `code` VARCHAR(64) NOT NULL,
  `type` VARCHAR(32) NOT NULL,
  `title_template` VARCHAR(255) NOT NULL,
  `content_template` TEXT NOT NULL,
  `default_channels` JSON NOT NULL,
  `variables` JSON NOT NULL,
  `locale` VARCHAR(16) NOT NULL DEFAULT 'zh-CN',
  `status` VARCHAR(32) NOT NULL DEFAULT 'draft',
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 5.4 投递记录表
CREATE TABLE IF NOT EXISTS `msg_notification_deliveries` (
  `id` VARCHAR(32) NOT NULL,
  `notification_id` VARCHAR(32) NOT NULL,
  `channel` VARCHAR(32) NOT NULL,
  `status` VARCHAR(32) NOT NULL DEFAULT 'pending',
  `external_id` VARCHAR(128) NULL,
  `attempt_count` INT NOT NULL DEFAULT 0,
  `max_retry` INT NOT NULL DEFAULT 3,
  `last_error` TEXT NULL,
  `next_retry_at` TIMESTAMP NULL,
  `delivered_at` TIMESTAMP NULL,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 5.5 MSG Outbox 表
CREATE TABLE IF NOT EXISTS `msg_outbox_events` (
  `event_id` VARCHAR(64) NOT NULL,
  `aggregate_type` VARCHAR(64) NOT NULL,
  `aggregate_id` VARCHAR(36) NOT NULL,
  `event_type` VARCHAR(64) NOT NULL,
  `topic` VARCHAR(128) NOT NULL,
  `payload` JSON NOT NULL,
  `status` VARCHAR(16) NOT NULL DEFAULT 'pending',
  `retry_count` INT NOT NULL DEFAULT 0,
  `max_retry_count` INT NOT NULL DEFAULT 5,
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `published_at` TIMESTAMP NULL,
  `next_retry_at` TIMESTAMP NULL,
  `last_error` TEXT NULL,
  `metadata` JSON NULL,
  PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 5.6 已处理事件表（消费幂等）
CREATE TABLE IF NOT EXISTS `processed_events` (
  `event_id` VARCHAR(64) NOT NULL,
  `topic` VARCHAR(128) NOT NULL,
  `processed_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
