Files
Edu/infra/init-sql/02-all-services-schema.sql
SpecialX a6b0c54fba fix: 修复登录路由 + 端口冲突 + Prometheus 配置 + outbox 表结构 + 补充监控基础设施
1. teacher-portal 登录 JSON 解析错误修复
   - 根因:next.config.js rewrites /api/auth/* → gateway /api/auth/*,
     但 gateway 只在 /api/v1 路由组下注册代理,/api/auth/* 返回 404 纯文本
   - 修复:rewrites 映射 /api/auth/* → /api/v1/iam/*(对齐 iam controller @Controller("v1/iam"))

2. msg / data-ana 端口冲突修复
   - 根因:msg env.ts PORT 默认 3006,与 data-ana(config.py http_port=3006)冲突
   - 修复:msg PORT 默认 3006→3007(对齐端口分配表 msg=3007, data-ana=3006)

3. Prometheus classes-service 3001 DOWN 修复
   - 根因:classes 已合并入 core-edu(P3 裁决 C1),但 prometheus.yml 仍有 classes-service scrape 配置
   - 修复:从 prometheus.yml 删除 classes-service job

4. iam outbox 表 aggregate_id 列长度修复
   - 根因:iam_outbox.aggregate_id VARCHAR(32),但 UUID 是 36 字符,导致 "Data too long" 错误
   - 修复:DDL 中 VARCHAR(32) → VARCHAR(36);ALTER TABLE 修复现有数据库

5. 补充未搭建的监控基础设施
   - docker-compose.yml 新增 Alertmanager(9093)/ Loki(3100)/ Promtail(observability profile)
   - prometheus.yml alertmanager target 更新为 edu-alertmanager:9093

验证:
- TS typecheck 19 项目全部通过
- 登录链路 teacher-portal → gateway → iam 验证通过
- Prometheus targets 不再有 classes-service
- 3 个新基础设施容器(alertmanager/loki/promtail)启动成功

AI identity: trae-main(基础设施修复会话)
2026-07-11 09:22:09 +08:00

610 lines
24 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;
-- ============================================================
-- 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;