Files
Edu/infra/init-sql/02-all-services-schema.sql

664 lines
26 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================
-- 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;
-- 1.11 TOTP 2FA 密钥表RFC 6238
CREATE TABLE IF NOT EXISTS `iam_user_totp` (
`id` CHAR(36) NOT NULL,
`user_id` CHAR(36) NOT NULL,
`secret` VARCHAR(128) NOT NULL,
`status` ENUM('pending','active') NOT NULL DEFAULT 'pending',
`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_user_totp_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 1.12 TOTP 备份码表10 个一次性使用)
CREATE TABLE IF NOT EXISTS `iam_totp_backup_codes` (
`id` CHAR(36) NOT NULL,
`user_id` CHAR(36) NOT NULL,
`code_hash` VARCHAR(255) NOT NULL,
`used_at` TIMESTAMP NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_iam_totp_backup_codes_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;
-- 5.7 公告主表(广播公告,一条对应一个目标受众)
CREATE TABLE IF NOT EXISTS `msg_announcements` (
`id` VARCHAR(32) NOT NULL,
`title` VARCHAR(255) NOT NULL,
`content` TEXT NOT NULL,
`status` VARCHAR(32) NOT NULL DEFAULT 'draft',
`is_pinned` BOOLEAN NOT NULL DEFAULT FALSE,
`author_id` VARCHAR(32) NOT NULL,
`target_audience` VARCHAR(32) NOT NULL DEFAULT 'all',
`metadata` JSON NULL,
`published_at` TIMESTAMP NULL,
`archived_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`),
INDEX `idx_msg_announcements_status` (`status`),
INDEX `idx_msg_announcements_audience` (`target_audience`),
INDEX `idx_msg_announcements_pinned` (`is_pinned`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 5.8 公告已读表(每用户已读跟踪,幂等)
CREATE TABLE IF NOT EXISTS `msg_announcement_reads` (
`id` VARCHAR(32) NOT NULL,
`announcement_id` VARCHAR(32) NOT NULL,
`user_id` VARCHAR(32) NOT NULL,
`read_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_announcement_user` (`announcement_id`, `user_id`),
INDEX `idx_msg_announcement_reads_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;