DROP SCHEMA IF EXISTS course CASCADE;
CREATE SCHEMA IF NOT EXISTS course;

DROP TABLE IF EXISTS course.cl_course CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_course (
    course_id         VARCHAR(64) PRIMARY KEY,
    title             VARCHAR(256) NOT NULL,
    subject_code      VARCHAR(32) NOT NULL,
    grade_code        VARCHAR(32) NOT NULL,
    difficulty_level  VARCHAR(16),
    status            VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
    adcode            VARCHAR(12) NOT NULL,
    tenant_id         VARCHAR(64) NOT NULL,
    tenant_path       VARCHAR(255) NOT NULL,
    dept_id           VARCHAR(64),
    dept_path         VARCHAR(255),
    created_by        VARCHAR(64),
    created_at        TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE course.cl_course IS '课程主表';
COMMENT ON COLUMN course.cl_course.course_id IS '课程ID';
COMMENT ON COLUMN course.cl_course.title IS '课程标题';
COMMENT ON COLUMN course.cl_course.subject_code IS '学科编码';
COMMENT ON COLUMN course.cl_course.grade_code IS '年级编码';
COMMENT ON COLUMN course.cl_course.difficulty_level IS '难度等级';
COMMENT ON COLUMN course.cl_course.status IS '状态（DRAFT/PUBLISHED/ARCHIVED）';
COMMENT ON COLUMN course.cl_course.adcode IS '行政区划编码';
COMMENT ON COLUMN course.cl_course.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_course.tenant_path IS '租户路径';
COMMENT ON COLUMN course.cl_course.dept_id IS '部门ID';
COMMENT ON COLUMN course.cl_course.dept_path IS '部门路径';
COMMENT ON COLUMN course.cl_course.created_by IS '创建人ID';
COMMENT ON COLUMN course.cl_course.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_course_chapter CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_course_chapter (
    chapter_id        VARCHAR(64) PRIMARY KEY,
    course_id         VARCHAR(64) NOT NULL,
    chapter_no        INTEGER NOT NULL,
    chapter_title     VARCHAR(256) NOT NULL,
    adcode            VARCHAR(12) NOT NULL,
    tenant_id         VARCHAR(64) NOT NULL,
    tenant_path       VARCHAR(255) NOT NULL,
    created_at        TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_cl_course_chapter_course
        FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id)
);
COMMENT ON TABLE course.cl_course_chapter IS '课程章节表';
COMMENT ON COLUMN course.cl_course_chapter.chapter_id IS '章节ID';
COMMENT ON COLUMN course.cl_course_chapter.course_id IS '课程ID';
COMMENT ON COLUMN course.cl_course_chapter.chapter_no IS '章节序号';
COMMENT ON COLUMN course.cl_course_chapter.chapter_title IS '章节标题';
COMMENT ON COLUMN course.cl_course_chapter.adcode IS '行政区划编码';
COMMENT ON COLUMN course.cl_course_chapter.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_course_chapter.tenant_path IS '租户路径';
COMMENT ON COLUMN course.cl_course_chapter.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_course_node CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_course_node (
    node_id             VARCHAR(64) PRIMARY KEY,
    chapter_id          VARCHAR(64) NOT NULL,
    node_no             INTEGER NOT NULL,
    node_title          VARCHAR(256) NOT NULL,
    node_type           VARCHAR(32) NOT NULL DEFAULT 'LESSON',
    class_type          VARCHAR(32),
    duration_sec        INTEGER,
    adcode              VARCHAR(12) NOT NULL,
    tenant_id           VARCHAR(64) NOT NULL,
    tenant_path         VARCHAR(255) NOT NULL,
    created_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT chk_cl_course_node_type
        CHECK (node_type IN ('LESSON', 'IN_CLASS_ACTIVITY', 'AFTER_CLASS_TASK', 'MATERIAL', 'OTHER')),
    CONSTRAINT fk_cl_course_node_chapter
        FOREIGN KEY (chapter_id) REFERENCES course.cl_course_chapter(chapter_id)
);
COMMENT ON TABLE course.cl_course_node IS '课程学习节点表';
COMMENT ON COLUMN course.cl_course_node.node_id IS '学习节点ID';
COMMENT ON COLUMN course.cl_course_node.chapter_id IS '章节ID';
COMMENT ON COLUMN course.cl_course_node.node_no IS '节点序号';
COMMENT ON COLUMN course.cl_course_node.node_title IS '节点标题';
COMMENT ON COLUMN course.cl_course_node.node_type IS '节点类型（LESSON/IN_CLASS_ACTIVITY/AFTER_CLASS_TASK/MATERIAL/OTHER）';
COMMENT ON COLUMN course.cl_course_node.class_type IS '课堂类型（如讲授/讨论/测验）';
COMMENT ON COLUMN course.cl_course_node.duration_sec IS '时长（秒）';
COMMENT ON COLUMN course.cl_course_node.adcode IS '行政区划编码';
COMMENT ON COLUMN course.cl_course_node.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_course_node.tenant_path IS '租户路径';
COMMENT ON COLUMN course.cl_course_node.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_knowledge_point CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_knowledge_point (
    kp_id               VARCHAR(64) PRIMARY KEY,
    kp_code             VARCHAR(64) NOT NULL,
    kp_name             VARCHAR(256) NOT NULL,
    kp_alias            VARCHAR(256),
    kp_type             VARCHAR(32) NOT NULL DEFAULT 'ATOMIC',
    parent_kp_id        VARCHAR(64),
    kp_path             VARCHAR(512),
    kp_desc             TEXT,
    subject_code        VARCHAR(32) NOT NULL,
    grade_code          VARCHAR(32) NOT NULL,
    difficulty_level    VARCHAR(16),
    importance_level    NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
    graph_entity_id     VARCHAR(64),
    source_db           VARCHAR(64) NOT NULL DEFAULT 'postgresql',
    source_table        VARCHAR(128) NOT NULL DEFAULT 'course.cl_knowledge_point',
    source_pk           VARCHAR(128),
    metadata_json       JSONB NOT NULL DEFAULT '{}'::JSONB,
    status              VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
    adcode              VARCHAR(12) NOT NULL,
    tenant_id           VARCHAR(64) NOT NULL,
    tenant_path         VARCHAR(255) NOT NULL,
    dept_id             VARCHAR(64),
    dept_path           VARCHAR(255),
    created_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_cl_knowledge_point_tenant_code
        UNIQUE (tenant_id, kp_code),
    CONSTRAINT uq_cl_knowledge_point_tenant_graph_entity
        UNIQUE (tenant_id, graph_entity_id),
    CONSTRAINT chk_cl_knowledge_point_type
        CHECK (kp_type IN ('DOMAIN', 'TOPIC', 'ATOMIC')),
    CONSTRAINT chk_cl_knowledge_point_importance
        CHECK (importance_level > 0 AND importance_level <= 1),
    CONSTRAINT chk_cl_knowledge_point_metadata_json
        CHECK (jsonb_typeof(metadata_json) = 'object'),
    CONSTRAINT fk_cl_knowledge_point_parent
        FOREIGN KEY (parent_kp_id) REFERENCES course.cl_knowledge_point(kp_id) ON DELETE SET NULL
);
COMMENT ON TABLE course.cl_knowledge_point IS '知识点表';
COMMENT ON COLUMN course.cl_knowledge_point.kp_id IS '知识点ID';
COMMENT ON COLUMN course.cl_knowledge_point.kp_code IS '知识点编码';
COMMENT ON COLUMN course.cl_knowledge_point.kp_name IS '知识点名称';
COMMENT ON COLUMN course.cl_knowledge_point.kp_alias IS '知识点别名';
COMMENT ON COLUMN course.cl_knowledge_point.kp_type IS '知识点类型（DOMAIN/TOPIC/ATOMIC）';
COMMENT ON COLUMN course.cl_knowledge_point.parent_kp_id IS '父知识点ID';
COMMENT ON COLUMN course.cl_knowledge_point.kp_path IS '知识点树路径';
COMMENT ON COLUMN course.cl_knowledge_point.kp_desc IS '知识点描述';
COMMENT ON COLUMN course.cl_knowledge_point.subject_code IS '学科编码';
COMMENT ON COLUMN course.cl_knowledge_point.grade_code IS '年级编码';
COMMENT ON COLUMN course.cl_knowledge_point.difficulty_level IS '难度等级';
COMMENT ON COLUMN course.cl_knowledge_point.importance_level IS '重要性权重（0,1]';
COMMENT ON COLUMN course.cl_knowledge_point.graph_entity_id IS '图谱实体ID（Nebula/Neo4j 映射）';
COMMENT ON COLUMN course.cl_knowledge_point.source_db IS '来源数据库';
COMMENT ON COLUMN course.cl_knowledge_point.source_table IS '来源表';
COMMENT ON COLUMN course.cl_knowledge_point.source_pk IS '来源主键';
COMMENT ON COLUMN course.cl_knowledge_point.metadata_json IS '扩展元数据JSON';
COMMENT ON COLUMN course.cl_knowledge_point.status IS '状态（ACTIVE/DISABLED）';
COMMENT ON COLUMN course.cl_knowledge_point.adcode IS '行政区划编码';
COMMENT ON COLUMN course.cl_knowledge_point.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_knowledge_point.tenant_path IS '租户路径';
COMMENT ON COLUMN course.cl_knowledge_point.dept_id IS '部门ID';
COMMENT ON COLUMN course.cl_knowledge_point.dept_path IS '部门路径';
COMMENT ON COLUMN course.cl_knowledge_point.created_at IS '创建时间';
COMMENT ON COLUMN course.cl_knowledge_point.updated_at IS '更新时间';

DROP TABLE IF EXISTS course.cl_chapter_kp_rel CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_chapter_kp_rel (
    chapter_id           VARCHAR(64) NOT NULL,
    kp_id                VARCHAR(64) NOT NULL,
    relation_type        VARCHAR(32) NOT NULL DEFAULT 'TEACHES',
    weight               NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
    is_core              BOOLEAN NOT NULL DEFAULT FALSE,
    tenant_id            VARCHAR(64) NOT NULL,
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (chapter_id, kp_id),
    CONSTRAINT chk_cl_chapter_kp_rel_type
        CHECK (relation_type IN ('TEACHES', 'REVIEWS', 'EXTENDS')),
    CONSTRAINT chk_cl_chapter_kp_rel_weight
        CHECK (weight > 0 AND weight <= 1),
    CONSTRAINT fk_cl_chapter_kp_rel_chapter
        FOREIGN KEY (chapter_id) REFERENCES course.cl_course_chapter(chapter_id),
    CONSTRAINT fk_cl_chapter_kp_rel_kp
        FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
);
COMMENT ON TABLE course.cl_chapter_kp_rel IS '章节-知识点关联表';
COMMENT ON COLUMN course.cl_chapter_kp_rel.chapter_id IS '章节ID';
COMMENT ON COLUMN course.cl_chapter_kp_rel.kp_id IS '知识点ID';
COMMENT ON COLUMN course.cl_chapter_kp_rel.relation_type IS '关系类型（TEACHES/REVIEWS/EXTENDS）';
COMMENT ON COLUMN course.cl_chapter_kp_rel.weight IS '关联权重（0,1]';
COMMENT ON COLUMN course.cl_chapter_kp_rel.is_core IS '是否核心知识点';
COMMENT ON COLUMN course.cl_chapter_kp_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_chapter_kp_rel.created_at IS '创建时间';
COMMENT ON COLUMN course.cl_chapter_kp_rel.updated_at IS '更新时间';

DROP TABLE IF EXISTS course.cl_student_kp_mastery CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_student_kp_mastery (
    mastery_id           VARCHAR(64) PRIMARY KEY,
    student_id           VARCHAR(64) NOT NULL,
    kp_id                VARCHAR(64) NOT NULL,
    mastery_score        NUMERIC(6,4) NOT NULL DEFAULT 0,
    mastery_level        VARCHAR(16) NOT NULL DEFAULT 'UNKNOWN',
    mastery_status       VARCHAR(16) NOT NULL DEFAULT 'LEARNING',
    evidence_json        JSONB NOT NULL DEFAULT '{}'::JSONB,
    last_source_type     VARCHAR(32),
    last_source_id       VARCHAR(64),
    last_assessed_at     TIMESTAMP,
    adcode               VARCHAR(12) NOT NULL,
    tenant_id            VARCHAR(64) NOT NULL,
    tenant_path          VARCHAR(255) NOT NULL,
    dept_id              VARCHAR(64),
    dept_path            VARCHAR(255),
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_cl_student_kp_mastery_student_kp
        UNIQUE (student_id, kp_id),
    CONSTRAINT chk_cl_student_kp_mastery_score
        CHECK (mastery_score >= 0 AND mastery_score <= 1),
    CONSTRAINT chk_cl_student_kp_mastery_level
        CHECK (mastery_level IN ('UNKNOWN', 'LOW', 'MEDIUM', 'HIGH', 'MASTERED')),
    CONSTRAINT chk_cl_student_kp_mastery_status
        CHECK (mastery_status IN ('LEARNING', 'STABLE', 'FORGOTTEN')),
    CONSTRAINT chk_cl_student_kp_mastery_evidence_json
        CHECK (jsonb_typeof(evidence_json) = 'object'),
    CONSTRAINT fk_cl_student_kp_mastery_student
        FOREIGN KEY (student_id) REFERENCES upms.tb_sys_user(user_id),
    CONSTRAINT fk_cl_student_kp_mastery_kp
        FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
);
COMMENT ON TABLE course.cl_student_kp_mastery IS '学生知识点掌握度表';
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_id IS '掌握度记录ID';
COMMENT ON COLUMN course.cl_student_kp_mastery.student_id IS '学生ID';
COMMENT ON COLUMN course.cl_student_kp_mastery.kp_id IS '知识点ID';
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_score IS '掌握度分值（0-1）';
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_level IS '掌握等级';
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_status IS '掌握状态（LEARNING/STABLE/FORGOTTEN）';
COMMENT ON COLUMN course.cl_student_kp_mastery.evidence_json IS '证据数据JSON（错题、批改、学习行为等）';
COMMENT ON COLUMN course.cl_student_kp_mastery.last_source_type IS '最近更新来源类型';
COMMENT ON COLUMN course.cl_student_kp_mastery.last_source_id IS '最近更新来源ID';
COMMENT ON COLUMN course.cl_student_kp_mastery.last_assessed_at IS '最近评估时间';
COMMENT ON COLUMN course.cl_student_kp_mastery.adcode IS '行政区划编码';
COMMENT ON COLUMN course.cl_student_kp_mastery.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_student_kp_mastery.tenant_path IS '租户路径';
COMMENT ON COLUMN course.cl_student_kp_mastery.dept_id IS '部门ID';
COMMENT ON COLUMN course.cl_student_kp_mastery.dept_path IS '部门路径';
COMMENT ON COLUMN course.cl_student_kp_mastery.created_at IS '创建时间';
COMMENT ON COLUMN course.cl_student_kp_mastery.updated_at IS '更新时间';

DROP TABLE IF EXISTS course.cl_kp_material_rel CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_kp_material_rel (
    rel_id               VARCHAR(64) PRIMARY KEY,
    kp_id                VARCHAR(64) NOT NULL,
    material_type        VARCHAR(32) NOT NULL,
    material_ref_id      VARCHAR(64) NOT NULL,
    material_uri         VARCHAR(512),
    weight               NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
    source_table         VARCHAR(128),
    source_pk            VARCHAR(128),
    tenant_id            VARCHAR(64) NOT NULL,
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT chk_cl_kp_material_rel_type
        CHECK (material_type IN ('VECTOR_DOCUMENT', 'VECTOR_CHUNK', 'COURSE_RESOURCE', 'EXTERNAL_URI')),
    CONSTRAINT chk_cl_kp_material_rel_weight
        CHECK (weight > 0 AND weight <= 1),
    CONSTRAINT fk_cl_kp_material_rel_kp
        FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
);
COMMENT ON TABLE course.cl_kp_material_rel IS '知识点-学习资料关联表';
COMMENT ON COLUMN course.cl_kp_material_rel.rel_id IS '关联ID';
COMMENT ON COLUMN course.cl_kp_material_rel.kp_id IS '知识点ID';
COMMENT ON COLUMN course.cl_kp_material_rel.material_type IS '资料类型（VECTOR_DOCUMENT/VECTOR_CHUNK/COURSE_RESOURCE/EXTERNAL_URI）';
COMMENT ON COLUMN course.cl_kp_material_rel.material_ref_id IS '资料对象ID';
COMMENT ON COLUMN course.cl_kp_material_rel.material_uri IS '资料URI';
COMMENT ON COLUMN course.cl_kp_material_rel.weight IS '关联权重（0,1]';
COMMENT ON COLUMN course.cl_kp_material_rel.source_table IS '来源表';
COMMENT ON COLUMN course.cl_kp_material_rel.source_pk IS '来源主键';
COMMENT ON COLUMN course.cl_kp_material_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_kp_material_rel.created_at IS '创建时间';
COMMENT ON COLUMN course.cl_kp_material_rel.updated_at IS '更新时间';

DROP TABLE IF EXISTS course.cl_course_knowledge_rel CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_course_knowledge_rel (
    course_id         VARCHAR(64) NOT NULL,
    kp_id             VARCHAR(64) NOT NULL,
    weight            NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
    tenant_id         VARCHAR(64) NOT NULL,
    created_at        TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (course_id, kp_id),
    CONSTRAINT chk_cl_course_knowledge_rel_weight
        CHECK (weight > 0 AND weight <= 1),
    CONSTRAINT fk_cl_course_knowledge_rel_course
        FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id),
    CONSTRAINT fk_cl_course_knowledge_rel_kp
        FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
);
COMMENT ON TABLE course.cl_course_knowledge_rel IS '课程-知识点关联表';
COMMENT ON COLUMN course.cl_course_knowledge_rel.course_id IS '课程ID';
COMMENT ON COLUMN course.cl_course_knowledge_rel.kp_id IS '知识点ID';
COMMENT ON COLUMN course.cl_course_knowledge_rel.weight IS '关联权重（0,1]）';
COMMENT ON COLUMN course.cl_course_knowledge_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_course_knowledge_rel.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_course_tag CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_course_tag (
    tag_id             VARCHAR(64) PRIMARY KEY,
    tag_name           VARCHAR(128) NOT NULL,
    tag_type           VARCHAR(32) NOT NULL,
    tenant_id          VARCHAR(64) NOT NULL,
    created_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE course.cl_course_tag IS '课程标签表';
COMMENT ON COLUMN course.cl_course_tag.tag_id IS '标签ID';
COMMENT ON COLUMN course.cl_course_tag.tag_name IS '标签名称';
COMMENT ON COLUMN course.cl_course_tag.tag_type IS '标签类型';
COMMENT ON COLUMN course.cl_course_tag.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_course_tag.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_course_tag_rel CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_course_tag_rel (
    course_id          VARCHAR(64) NOT NULL,
    tag_id             VARCHAR(64) NOT NULL,
    tenant_id          VARCHAR(64) NOT NULL,
    created_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (course_id, tag_id),
    CONSTRAINT fk_cl_course_tag_rel_course
        FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id),
    CONSTRAINT fk_cl_course_tag_rel_tag
        FOREIGN KEY (tag_id) REFERENCES course.cl_course_tag(tag_id)
);
COMMENT ON TABLE course.cl_course_tag_rel IS '课程-标签关联表';
COMMENT ON COLUMN course.cl_course_tag_rel.course_id IS '课程ID';
COMMENT ON COLUMN course.cl_course_tag_rel.tag_id IS '标签ID';
COMMENT ON COLUMN course.cl_course_tag_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_course_tag_rel.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_node_resource CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_node_resource (
    resource_id          VARCHAR(64) PRIMARY KEY,
    node_id              VARCHAR(64) NOT NULL,
    resource_type        VARCHAR(32) NOT NULL,
    file_id              VARCHAR(64),
    resource_url         VARCHAR(512),
    resource_title       VARCHAR(256),
    tenant_id            VARCHAR(64) NOT NULL,
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT chk_cl_node_resource_type
        CHECK (resource_type IN ('PDF', 'VIDEO', 'DOC', 'IMAGE', 'LINK', 'OTHER')),
    CONSTRAINT chk_cl_node_resource_ref
        CHECK (file_id IS NOT NULL OR resource_url IS NOT NULL),
    CONSTRAINT fk_cl_node_resource_node
        FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id),
    CONSTRAINT fk_cl_node_resource_file
        FOREIGN KEY (file_id) REFERENCES upms.tb_sys_file(file_id)
);
COMMENT ON TABLE course.cl_node_resource IS '学习节点资源表';
COMMENT ON COLUMN course.cl_node_resource.resource_id IS '资源ID';
COMMENT ON COLUMN course.cl_node_resource.node_id IS '学习节点ID';
COMMENT ON COLUMN course.cl_node_resource.resource_type IS '资源类型（PDF/VIDEO/DOC/IMAGE/LINK/OTHER）';
COMMENT ON COLUMN course.cl_node_resource.file_id IS '资源文件ID';
COMMENT ON COLUMN course.cl_node_resource.resource_url IS '资源地址';
COMMENT ON COLUMN course.cl_node_resource.resource_title IS '资源标题';
COMMENT ON COLUMN course.cl_node_resource.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_node_resource.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_node_kp_rel CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_node_kp_rel (
    node_id               VARCHAR(64) NOT NULL,
    kp_id                 VARCHAR(64) NOT NULL,
    relation_type         VARCHAR(32) NOT NULL DEFAULT 'TEACHES',
    weight                NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
    tenant_id             VARCHAR(64) NOT NULL,
    created_at            TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (node_id, kp_id),
    CONSTRAINT chk_cl_node_kp_rel_type
        CHECK (relation_type IN ('TEACHES', 'PRACTICES', 'REVIEWS')),
    CONSTRAINT chk_cl_node_kp_rel_weight
        CHECK (weight > 0 AND weight <= 1),
    CONSTRAINT fk_cl_node_kp_rel_node
        FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id),
    CONSTRAINT fk_cl_node_kp_rel_kp
        FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
);
COMMENT ON TABLE course.cl_node_kp_rel IS '学习节点-知识点关联表';
COMMENT ON COLUMN course.cl_node_kp_rel.node_id IS '学习节点ID';
COMMENT ON COLUMN course.cl_node_kp_rel.kp_id IS '知识点ID';
COMMENT ON COLUMN course.cl_node_kp_rel.relation_type IS '关系类型（TEACHES/PRACTICES/REVIEWS）';
COMMENT ON COLUMN course.cl_node_kp_rel.weight IS '关联权重（0,1]';
COMMENT ON COLUMN course.cl_node_kp_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_node_kp_rel.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_node_homework_rel CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_node_homework_rel (
    node_id               VARCHAR(64) NOT NULL,
    assignment_id         VARCHAR(64) NOT NULL,
    relation_type         VARCHAR(32) NOT NULL DEFAULT 'AFTER_CLASS',
    tenant_id             VARCHAR(64) NOT NULL,
    created_at            TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (node_id, assignment_id),
    CONSTRAINT chk_cl_node_homework_rel_type
        CHECK (relation_type IN ('IN_CLASS', 'AFTER_CLASS')),
    CONSTRAINT fk_cl_node_homework_rel_node
        FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id)
);
COMMENT ON TABLE course.cl_node_homework_rel IS '学习节点-作业关联表';
COMMENT ON COLUMN course.cl_node_homework_rel.node_id IS '学习节点ID';
COMMENT ON COLUMN course.cl_node_homework_rel.assignment_id IS '作业ID（question.hw_assignment.assignment_id）';
COMMENT ON COLUMN course.cl_node_homework_rel.relation_type IS '关系类型（IN_CLASS/AFTER_CLASS）';
COMMENT ON COLUMN course.cl_node_homework_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_node_homework_rel.created_at IS '创建时间';

DROP TABLE IF EXISTS course.cl_learning_session CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_learning_session (
    session_id          VARCHAR(64) PRIMARY KEY,
    user_id             VARCHAR(64) NOT NULL,
    course_id           VARCHAR(64) NOT NULL,
    status              VARCHAR(32) NOT NULL DEFAULT 'STARTED',
    started_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    ended_at            TIMESTAMP,
    adcode              VARCHAR(12) NOT NULL,
    tenant_id           VARCHAR(64) NOT NULL,
    tenant_path         VARCHAR(255) NOT NULL,
    dept_id             VARCHAR(64),
    dept_path           VARCHAR(255),
    CONSTRAINT fk_cl_learning_session_user
        FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
    CONSTRAINT fk_cl_learning_session_course
        FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id)
);
COMMENT ON TABLE course.cl_learning_session IS '学习会话表';
COMMENT ON COLUMN course.cl_learning_session.session_id IS '会话ID';
COMMENT ON COLUMN course.cl_learning_session.user_id IS '学员ID';
COMMENT ON COLUMN course.cl_learning_session.course_id IS '课程ID';
COMMENT ON COLUMN course.cl_learning_session.status IS '会话状态（STARTED/PAUSED/COMPLETED）';
COMMENT ON COLUMN course.cl_learning_session.started_at IS '开始时间';
COMMENT ON COLUMN course.cl_learning_session.ended_at IS '结束时间';
COMMENT ON COLUMN course.cl_learning_session.adcode IS '行政区划编码';
COMMENT ON COLUMN course.cl_learning_session.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_learning_session.tenant_path IS '租户路径';
COMMENT ON COLUMN course.cl_learning_session.dept_id IS '部门ID';
COMMENT ON COLUMN course.cl_learning_session.dept_path IS '部门路径';

DROP TABLE IF EXISTS course.cl_learning_progress CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_learning_progress (
    progress_id          VARCHAR(64) PRIMARY KEY,
    session_id           VARCHAR(64) NOT NULL,
    node_id              VARCHAR(64) NOT NULL,
    progress_pct         NUMERIC(5,2) NOT NULL DEFAULT 0,
    last_position_sec    INTEGER NOT NULL DEFAULT 0,
    mastery_level        VARCHAR(16),
    tenant_id            VARCHAR(64) NOT NULL,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_cl_learning_progress_session
        FOREIGN KEY (session_id) REFERENCES course.cl_learning_session(session_id),
    CONSTRAINT fk_cl_learning_progress_node
        FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id)
);
COMMENT ON TABLE course.cl_learning_progress IS '学习进度表';
COMMENT ON COLUMN course.cl_learning_progress.progress_id IS '进度ID';
COMMENT ON COLUMN course.cl_learning_progress.session_id IS '学习会话ID';
COMMENT ON COLUMN course.cl_learning_progress.node_id IS '学习节点ID';
COMMENT ON COLUMN course.cl_learning_progress.progress_pct IS '进度百分比';
COMMENT ON COLUMN course.cl_learning_progress.last_position_sec IS '最后学习位置（秒）';
COMMENT ON COLUMN course.cl_learning_progress.mastery_level IS '掌握等级';
COMMENT ON COLUMN course.cl_learning_progress.tenant_id IS '租户ID';
COMMENT ON COLUMN course.cl_learning_progress.updated_at IS '更新时间';

DROP TABLE IF EXISTS course.cl_learning_event CASCADE;
CREATE TABLE IF NOT EXISTS course.cl_learning_event (
    event_id            VARCHAR(64) PRIMARY KEY,
    session_id          VARCHAR(64) NOT NULL,
    event_type          VARCHAR(32) NOT NULL,
    event_time          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    payload_json        JSONB,
    tenant_id           VARCHAR(64) NOT NULL,
    CONSTRAINT fk_cl_learning_event_session
        FOREIGN KEY (session_id) REFERENCES course.cl_learning_session(session_id)
);
COMMENT ON TABLE course.cl_learning_event IS '学习行为事件表';
COMMENT ON COLUMN course.cl_learning_event.event_id IS '事件ID';
COMMENT ON COLUMN course.cl_learning_event.session_id IS '会话ID';
COMMENT ON COLUMN course.cl_learning_event.event_type IS '事件类型（start/pause/seek/finish）';
COMMENT ON COLUMN course.cl_learning_event.event_time IS '事件时间';
COMMENT ON COLUMN course.cl_learning_event.payload_json IS '事件扩展信息';
COMMENT ON COLUMN course.cl_learning_event.tenant_id IS '租户ID';

CREATE INDEX IF NOT EXISTS idx_cl_course_tenant_subject_grade
    ON course.cl_course(tenant_id, subject_code, grade_code);
CREATE INDEX IF NOT EXISTS idx_cl_course_chapter_course_no
    ON course.cl_course_chapter(course_id, chapter_no);
CREATE INDEX IF NOT EXISTS idx_cl_course_node_chapter_no
    ON course.cl_course_node(chapter_id, node_no);
CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_subject_grade
    ON course.cl_knowledge_point(tenant_id, subject_code, grade_code);
CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_parent
    ON course.cl_knowledge_point(tenant_id, parent_kp_id);
CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_graph_entity
    ON course.cl_knowledge_point(tenant_id, graph_entity_id);
CREATE INDEX IF NOT EXISTS idx_cl_chapter_kp_rel_chapter
    ON course.cl_chapter_kp_rel(tenant_id, chapter_id, relation_type);
CREATE INDEX IF NOT EXISTS idx_cl_chapter_kp_rel_kp
    ON course.cl_chapter_kp_rel(tenant_id, kp_id, relation_type);
CREATE INDEX IF NOT EXISTS idx_cl_student_kp_mastery_student
    ON course.cl_student_kp_mastery(tenant_id, student_id, mastery_score DESC);
CREATE INDEX IF NOT EXISTS idx_cl_student_kp_mastery_kp
    ON course.cl_student_kp_mastery(tenant_id, kp_id, mastery_score DESC);
CREATE INDEX IF NOT EXISTS idx_cl_kp_material_rel_kp
    ON course.cl_kp_material_rel(tenant_id, kp_id, material_type);
CREATE INDEX IF NOT EXISTS idx_cl_node_resource_node
    ON course.cl_node_resource(node_id, resource_type);
CREATE INDEX IF NOT EXISTS idx_cl_node_kp_rel_node
    ON course.cl_node_kp_rel(tenant_id, node_id, relation_type);
CREATE INDEX IF NOT EXISTS idx_cl_node_kp_rel_kp
    ON course.cl_node_kp_rel(tenant_id, kp_id, relation_type);
CREATE INDEX IF NOT EXISTS idx_cl_node_homework_rel_node
    ON course.cl_node_homework_rel(tenant_id, node_id, relation_type);
CREATE INDEX IF NOT EXISTS idx_cl_learning_session_user_course
    ON course.cl_learning_session(tenant_id, user_id, course_id);
CREATE INDEX IF NOT EXISTS idx_cl_learning_progress_session_node
    ON course.cl_learning_progress(session_id, node_id);
CREATE INDEX IF NOT EXISTS idx_cl_learning_event_session_time
    ON course.cl_learning_event(session_id, event_time DESC);
