Files
Edu/infra/init-sql/02-all-services-schema.sql
SpecialX 61d824924a fix: 修复集成测试中发现的全部 bug — 15 服务端到端验证通过
修复涵盖 6 大类问题:

1. api-gateway
   - 路径前缀剥离 /api 而非 /api/v1,保留下游 /v1/ controller 前缀
   - JWKS URL 默认值修复
   - publicPaths 白名单对齐 /v1/iam/*

2. iam
   - iam.module.ts exports 补充 PermissionCacheService 和 IamRepository
   - main.ts resolveProtoPath() 多路径探测 proto 文件

3. core-edu
   - app.module.ts AuthMiddleware 全局注册

4. BFF 层 GraphQL 端点(teacher-bff / parent-bff / student-bff)
   - teacher-bff: mock dataScope OWN→SELF 对齐 GraphQL enum;WHATWG Request header .get() 提取
   - parent-bff: handleNodeRequestAndResponse 不存在 → 直接 yoga(req,res);WHATWG Request header .get() 提取
   - student-bff: auth.resolver 移除 ActionState 信封返回扁平对象;WHATWG Request header .get() 提取

5. ai
   - Kafka 事务降级 + 10s 超时
   - gRPC 拦截器降级
   - dev mode 禁用事务模式

6. 前端 + 共享包
   - teacher-portal: MF 插件条件实例化 + transpilePackages + extensionAlias
   - ui-components: error-boundary.tsx 添加 use client
   - ui-tokens: tailwind-theme.css 移除 @layer base
   - shared-ts: 导出从源码改为 dist 编译产物;OutboxModule global:true

7. infra
   - .gitignore 补充 keys/ *.pem *.key secrets/ 排除规则
   - infra/init-sql/02-all-services-schema.sql 36 张表 DDL

验证结果:
- TS typecheck: 19 个 workspace 项目全部通过
- Go vet + Ruff: 通过
- 15 服务全部启动成功
- 3 个 BFF GraphQL 端点 + 4 个前端页面全部 200
- Gateway → iam → core-edu 端到端链路验证通过

AI identity: trae-main(集成测试修复会话)
2026-07-11 01:41:46 +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(32) 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(32) 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;