-- Muse Content 模块初始 Schema(PostgreSQL 16) -- 影响范围:作品、章节、Block、来源归因、导入导出任务。 -- 说明:业务表不使用数据库外键,引用完整性由应用层在权限、租户和 owner 校验后保证。 CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.update_time = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TABLE muse_content_work ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, owner_user_id BIGINT NOT NULL, title VARCHAR(200) NOT NULL, description TEXT, genre VARCHAR(50), cover_image_url TEXT, summary TEXT, status VARCHAR(20) NOT NULL DEFAULT 'writing', work_schema_id BIGINT, import_status VARCHAR(20), parse_status VARCHAR(20), word_count INT NOT NULL DEFAULT 0, chapter_count INT NOT NULL DEFAULT 0, command_id VARCHAR(120), revision INT NOT NULL DEFAULT 1, creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0 ); CREATE INDEX idx_muse_content_work_owner ON muse_content_work(tenant_id, owner_user_id, update_time); CREATE INDEX idx_muse_content_work_status ON muse_content_work(tenant_id, status); CREATE UNIQUE INDEX uk_muse_content_work_command ON muse_content_work(tenant_id, command_id) WHERE command_id IS NOT NULL; CREATE TRIGGER trg_muse_content_work_updated_at BEFORE UPDATE ON muse_content_work FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TABLE muse_content_chapter ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, work_id BIGINT NOT NULL, title VARCHAR(200) NOT NULL, order_no INT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'draft', goal_snapshot JSONB, outline_snapshot JSONB, parse_review_status VARCHAR(20), command_id VARCHAR(120), revision INT NOT NULL DEFAULT 1, creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0, CONSTRAINT uk_muse_content_chapter_work_order UNIQUE (tenant_id, work_id, order_no) ); CREATE INDEX idx_muse_content_chapter_work ON muse_content_chapter(tenant_id, work_id); CREATE UNIQUE INDEX uk_muse_content_chapter_command ON muse_content_chapter(tenant_id, command_id) WHERE command_id IS NOT NULL; CREATE TRIGGER trg_muse_content_chapter_updated_at BEFORE UPDATE ON muse_content_chapter FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TABLE muse_content_block ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, work_id BIGINT NOT NULL, chapter_id BIGINT NOT NULL, order_no INT NOT NULL, block_type VARCHAR(30) NOT NULL DEFAULT 'scene', title VARCHAR(500), content_doc JSONB, content_text TEXT, revision INT NOT NULL DEFAULT 1, word_count INT NOT NULL DEFAULT 0, command_id VARCHAR(120), creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0, CONSTRAINT uk_muse_content_block_chapter_order UNIQUE (tenant_id, chapter_id, order_no) ); CREATE INDEX idx_muse_content_block_work ON muse_content_block(tenant_id, work_id); CREATE INDEX idx_muse_content_block_chapter ON muse_content_block(tenant_id, chapter_id); CREATE UNIQUE INDEX uk_muse_content_block_command ON muse_content_block(tenant_id, command_id) WHERE command_id IS NOT NULL; CREATE TRIGGER trg_muse_content_block_updated_at BEFORE UPDATE ON muse_content_block FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TABLE muse_content_block_source_attribution ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, work_id BIGINT NOT NULL, block_id BIGINT NOT NULL, revision INT NOT NULL, source_type VARCHAR(50) NOT NULL, source_object_id VARCHAR(100), source_version INT, lineage_payload JSONB, authorization_snapshot_id BIGINT, source_status VARCHAR(30), license_restriction_snapshot JSONB, creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0, CONSTRAINT uk_muse_content_block_src_revision UNIQUE (tenant_id, block_id, revision) ); CREATE INDEX idx_muse_content_block_src_block ON muse_content_block_source_attribution(tenant_id, block_id); CREATE TRIGGER trg_muse_content_block_src_updated_at BEFORE UPDATE ON muse_content_block_source_attribution FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TABLE muse_content_import_task ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, work_id BIGINT NOT NULL, owner_user_id BIGINT NOT NULL, source_type VARCHAR(50) NOT NULL, source_snapshot JSONB, status VARCHAR(30) NOT NULL DEFAULT 'queued', error_code VARCHAR(80), error_message TEXT, command_id VARCHAR(120) NOT NULL, creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0, CONSTRAINT uk_muse_content_import_command UNIQUE (tenant_id, command_id) ); CREATE INDEX idx_muse_content_import_work ON muse_content_import_task(tenant_id, work_id, status); CREATE TRIGGER trg_muse_content_import_updated_at BEFORE UPDATE ON muse_content_import_task FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TABLE muse_content_export_task ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, work_id BIGINT NOT NULL, owner_user_id BIGINT NOT NULL, export_format VARCHAR(30) NOT NULL, status VARCHAR(30) NOT NULL DEFAULT 'queued', credential_id VARCHAR(120), package_ref TEXT, error_code VARCHAR(80), error_message TEXT, command_id VARCHAR(120) NOT NULL, creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0, CONSTRAINT uk_muse_content_export_command UNIQUE (tenant_id, command_id) ); CREATE INDEX idx_muse_content_export_work ON muse_content_export_task(tenant_id, work_id, status); CREATE TRIGGER trg_muse_content_export_updated_at BEFORE UPDATE ON muse_content_export_task FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TABLE muse_content_command_log ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, command_id VARCHAR(120) NOT NULL, command_type VARCHAR(80) NOT NULL, owner_user_id BIGINT NOT NULL, target_type VARCHAR(50), target_id BIGINT, request_hash VARCHAR(128), result_snapshot JSONB, creator VARCHAR(64) NOT NULL DEFAULT '', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updater VARCHAR(64) NOT NULL DEFAULT '', update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted BOOLEAN NOT NULL DEFAULT FALSE, tenant_id BIGINT NOT NULL DEFAULT 0, CONSTRAINT uk_muse_content_command UNIQUE (tenant_id, command_id) ); CREATE INDEX idx_muse_content_command_owner ON muse_content_command_log(tenant_id, owner_user_id, create_time); CREATE TRIGGER trg_muse_content_command_updated_at BEFORE UPDATE ON muse_content_command_log FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();