oh-my-muse/muse-cloud/sql/muse/V12__extend_ai_real_api_schema.sql
zizi 4f38bf0da1 feat(p1r): 实现 AI 真实 API dedicated gate
将 P1R-4 AI 41 个 operation 推进到 dedicated / needs_verification,退役 AI contract fallback,并补齐 runtime、SSE、job、audit、source、coverage 与 PostgreSQL/Flyway 门禁。

保留 completedOperations=0;真实 New-API chat、Security owner、Knowledge/RAGFlow、Market 和统一 events 仍留在后续验收。
2026-06-01 00:37:29 +08:00

559 lines
23 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.

-- P1R-4 AI Real API 扩展 Schema。
-- 说明:本迁移只追加 AI owner 自有事实New-API、Security、Content、Meta、Knowledge、Market 主流程不在此处伪造。
CREATE TABLE muse_ai_command (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
command_id VARCHAR(128) NOT NULL,
operation_id VARCHAR(128) NOT NULL,
actor_user_id BIGINT NOT NULL,
owner_user_id BIGINT NOT NULL,
target_type VARCHAR(64) NOT NULL,
target_id BIGINT,
target_key VARCHAR(160) NOT NULL,
request_hash CHAR(64) NOT NULL,
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_ai_command UNIQUE (tenant_id, command_id)
);
CREATE INDEX idx_muse_ai_command_target
ON muse_ai_command(tenant_id, target_type, target_key);
CREATE TRIGGER trg_muse_ai_command_updated_at
BEFORE UPDATE ON muse_ai_command
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
ALTER TABLE muse_ai_generation
ADD COLUMN IF NOT EXISTS command_id VARCHAR(128),
ADD COLUMN IF NOT EXISTS request_hash CHAR(64),
ADD COLUMN IF NOT EXISTS job_id VARCHAR(128),
ADD COLUMN IF NOT EXISTS correlation_id VARCHAR(200),
ADD COLUMN IF NOT EXISTS source_snapshot_id VARCHAR(128),
ADD COLUMN IF NOT EXISTS runtime_permission_envelope_id VARCHAR(128),
ADD COLUMN IF NOT EXISTS owner_user_id BIGINT,
ADD COLUMN IF NOT EXISTS runtime_status VARCHAR(32),
ADD COLUMN IF NOT EXISTS runtime_summary JSONB,
ADD COLUMN IF NOT EXISTS source_summary JSONB,
ADD COLUMN IF NOT EXISTS runtime_permission_summary JSONB;
CREATE UNIQUE INDEX uk_muse_ai_generation_command
ON muse_ai_generation(tenant_id, command_id)
WHERE command_id IS NOT NULL;
CREATE INDEX idx_muse_ai_generation_owner_status
ON muse_ai_generation(tenant_id, owner_user_id, status, create_time)
WHERE owner_user_id IS NOT NULL;
CREATE INDEX idx_muse_ai_generation_job
ON muse_ai_generation(tenant_id, job_id)
WHERE job_id IS NOT NULL;
CREATE INDEX idx_muse_ai_generation_correlation
ON muse_ai_generation(tenant_id, correlation_id)
WHERE correlation_id IS NOT NULL;
CREATE TABLE muse_ai_runtime_call (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
correlation_id VARCHAR(200) NOT NULL,
task_id VARCHAR(128) NOT NULL,
job_id VARCHAR(128) NOT NULL,
command_id VARCHAR(128),
operation_id VARCHAR(128) NOT NULL,
actor_user_id BIGINT NOT NULL,
owner_user_id BIGINT NOT NULL,
target_type VARCHAR(64) NOT NULL,
target_id BIGINT,
target_key VARCHAR(160) NOT NULL,
attempt_no INT NOT NULL DEFAULT 1,
model_key VARCHAR(128),
prompt_template_version VARCHAR(80),
status VARCHAR(32) NOT NULL,
request_hash CHAR(64),
request_summary JSONB,
response_summary JSONB,
usage_summary JSONB,
cost_cents BIGINT,
provider_request_id VARCHAR(200),
failure_type VARCHAR(64),
provider_status_code INT,
error_code VARCHAR(64),
error_message TEXT,
retryable BOOLEAN NOT NULL DEFAULT FALSE,
next_retry_at TIMESTAMP,
started_at TIMESTAMP,
finished_at TIMESTAMP,
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_ai_runtime_call_attempt UNIQUE (tenant_id, correlation_id, attempt_no)
);
CREATE INDEX idx_muse_ai_runtime_call_owner_status
ON muse_ai_runtime_call(tenant_id, owner_user_id, status, create_time);
CREATE INDEX idx_muse_ai_runtime_call_task
ON muse_ai_runtime_call(tenant_id, task_id, attempt_no);
CREATE INDEX idx_muse_ai_runtime_call_job
ON muse_ai_runtime_call(tenant_id, job_id, attempt_no);
CREATE TRIGGER trg_muse_ai_runtime_call_updated_at
BEFORE UPDATE ON muse_ai_runtime_call
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_task_event (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
task_id VARCHAR(128) NOT NULL,
sequence_no BIGINT NOT NULL,
event_type VARCHAR(40) NOT NULL,
task_status VARCHAR(32) NOT NULL,
owner_user_id BIGINT NOT NULL,
actor_user_id BIGINT,
job_id VARCHAR(128),
correlation_id VARCHAR(200),
payload_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
error_code VARCHAR(64),
error_message TEXT,
emitted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
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_ai_task_event_sequence UNIQUE (tenant_id, task_id, sequence_no)
);
CREATE INDEX idx_muse_ai_task_event_owner_status
ON muse_ai_task_event(tenant_id, owner_user_id, task_status, create_time);
CREATE UNIQUE INDEX uk_muse_ai_task_event_terminal
ON muse_ai_task_event(tenant_id, task_id)
WHERE event_type IN ('done', 'error');
CREATE INDEX idx_muse_ai_task_event_job
ON muse_ai_task_event(tenant_id, job_id, sequence_no)
WHERE job_id IS NOT NULL;
CREATE TRIGGER trg_muse_ai_task_event_updated_at
BEFORE UPDATE ON muse_ai_task_event
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_job (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
job_id VARCHAR(128) NOT NULL,
job_type VARCHAR(64) NOT NULL,
task_id VARCHAR(128),
command_id VARCHAR(128),
request_hash CHAR(64),
operation_id VARCHAR(128) NOT NULL,
actor_user_id BIGINT NOT NULL,
owner_user_id BIGINT NOT NULL,
work_id BIGINT,
status VARCHAR(32) NOT NULL,
retry_count INT NOT NULL DEFAULT 0,
retryable BOOLEAN NOT NULL DEFAULT FALSE,
retry_group_id VARCHAR(128),
next_retry_at TIMESTAMP,
source_snapshot_id VARCHAR(128),
runtime_permission_envelope_id VARCHAR(128),
correlation_id VARCHAR(200),
input_summary JSONB,
result_summary JSONB,
error_code VARCHAR(64),
error_message TEXT,
started_at TIMESTAMP,
finished_at TIMESTAMP,
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_ai_job UNIQUE (tenant_id, job_id),
CONSTRAINT uk_muse_ai_job_command UNIQUE (tenant_id, command_id)
);
CREATE INDEX idx_muse_ai_job_owner_status
ON muse_ai_job(tenant_id, owner_user_id, status, create_time);
CREATE INDEX idx_muse_ai_job_work_status
ON muse_ai_job(tenant_id, work_id, status, create_time)
WHERE work_id IS NOT NULL;
CREATE INDEX idx_muse_ai_job_retry_group
ON muse_ai_job(tenant_id, retry_group_id, create_time)
WHERE retry_group_id IS NOT NULL;
CREATE UNIQUE INDEX uk_muse_ai_job_active_retry_group
ON muse_ai_job(tenant_id, retry_group_id)
WHERE retry_group_id IS NOT NULL
AND operation_id = 'adminRetryJob'
AND status IN ('queued', 'running', 'streaming')
AND deleted = FALSE;
CREATE TRIGGER trg_muse_ai_job_updated_at
BEFORE UPDATE ON muse_ai_job
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_source_event (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
source_event_id VARCHAR(128) NOT NULL,
source_owner VARCHAR(64) NOT NULL,
source_type VARCHAR(64) NOT NULL,
source_id VARCHAR(128) NOT NULL,
source_revision VARCHAR(80),
owner_user_id BIGINT NOT NULL,
work_id BIGINT,
status VARCHAR(32) NOT NULL DEFAULT 'blocked',
action_policy VARCHAR(64) NOT NULL DEFAULT 'blocked',
command_id VARCHAR(128),
job_id VARCHAR(128),
event_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
error_code VARCHAR(64),
error_message TEXT,
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_ai_source_event UNIQUE (tenant_id, source_event_id),
CONSTRAINT chk_muse_ai_source_event_status
CHECK (status IN ('active', 'stale', 'revoked', 'recalled', 'delisted', 'blocked', 'owner_missing', 'unauthorized')),
CONSTRAINT chk_muse_ai_source_event_action_policy
CHECK (action_policy IN ('allowed', 'read_only', 'blocked', 'needs_recheck'))
);
CREATE INDEX idx_muse_ai_source_event_owner_status
ON muse_ai_source_event(tenant_id, owner_user_id, status, create_time);
CREATE INDEX idx_muse_ai_source_event_admin_list
ON muse_ai_source_event(tenant_id, source_type, status, create_time);
CREATE INDEX idx_muse_ai_source_event_source
ON muse_ai_source_event(tenant_id, source_owner, source_type, source_id, create_time);
CREATE TRIGGER trg_muse_ai_source_event_updated_at
BEFORE UPDATE ON muse_ai_source_event
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_source_status_projection (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
source_owner VARCHAR(64) NOT NULL,
source_type VARCHAR(64) NOT NULL,
source_id VARCHAR(128) NOT NULL,
source_revision VARCHAR(80),
owner_user_id BIGINT NOT NULL,
work_id BIGINT,
status VARCHAR(32) NOT NULL DEFAULT 'blocked',
action_policy VARCHAR(64) NOT NULL DEFAULT 'blocked',
last_event_id VARCHAR(128),
status_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
checked_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
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_ai_source_status UNIQUE (tenant_id, owner_user_id, source_owner, source_type, source_id),
CONSTRAINT chk_muse_ai_source_status_projection_status
CHECK (status IN ('active', 'stale', 'revoked', 'recalled', 'delisted', 'blocked', 'owner_missing', 'unauthorized')),
CONSTRAINT chk_muse_ai_source_status_projection_action_policy
CHECK (action_policy IN ('allowed', 'read_only', 'blocked', 'needs_recheck'))
);
CREATE INDEX idx_muse_ai_source_status_owner_status
ON muse_ai_source_status_projection(tenant_id, owner_user_id, status, create_time);
CREATE INDEX idx_muse_ai_source_status_work
ON muse_ai_source_status_projection(tenant_id, work_id, status, create_time)
WHERE work_id IS NOT NULL;
CREATE TRIGGER trg_muse_ai_source_status_updated_at
BEFORE UPDATE ON muse_ai_source_status_projection
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_agent_slot_precheck (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
precheck_id VARCHAR(128) NOT NULL,
command_id VARCHAR(128) NOT NULL,
request_hash CHAR(64) NOT NULL,
work_id BIGINT NOT NULL,
slot_key VARCHAR(160) NOT NULL,
source_agent_id BIGINT NOT NULL,
source_agent_version INT NOT NULL,
expected_slot_revision INT,
authorization_snapshot_id VARCHAR(128),
status VARCHAR(32) NOT NULL,
expires_at TIMESTAMP NOT NULL,
consumed_at TIMESTAMP,
result_summary JSONB,
owner_user_id BIGINT NOT NULL,
actor_user_id BIGINT 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_ai_agent_slot_precheck_id UNIQUE (tenant_id, precheck_id),
CONSTRAINT uk_muse_ai_agent_slot_precheck_command UNIQUE (tenant_id, command_id)
);
CREATE INDEX idx_muse_ai_agent_slot_precheck_work_slot_status
ON muse_ai_agent_slot_precheck(tenant_id, work_id, slot_key, status);
CREATE INDEX idx_muse_ai_agent_slot_precheck_owner_status
ON muse_ai_agent_slot_precheck(tenant_id, owner_user_id, status, expires_at);
CREATE TRIGGER trg_muse_ai_agent_slot_precheck_updated_at
BEFORE UPDATE ON muse_ai_agent_slot_precheck
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_suggestion_decision (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
suggestion_id BIGINT NOT NULL,
decision_id VARCHAR(128) NOT NULL,
decision VARCHAR(32) NOT NULL,
reason_code VARCHAR(64),
owner_user_id BIGINT NOT NULL,
actor_user_id BIGINT NOT NULL,
work_id BIGINT,
command_id VARCHAR(128) NOT NULL,
request_hash CHAR(64) NOT NULL,
decision_summary 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_ai_suggestion_decision UNIQUE (tenant_id, decision_id),
CONSTRAINT uk_muse_ai_suggestion_decision_command UNIQUE (tenant_id, command_id)
);
CREATE INDEX idx_muse_ai_suggestion_decision_owner
ON muse_ai_suggestion_decision(tenant_id, owner_user_id, create_time);
CREATE INDEX idx_muse_ai_suggestion_decision_suggestion
ON muse_ai_suggestion_decision(tenant_id, suggestion_id, create_time);
CREATE TRIGGER trg_muse_ai_suggestion_decision_updated_at
BEFORE UPDATE ON muse_ai_suggestion_decision
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_evaluation_run (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
run_id VARCHAR(128) NOT NULL,
policy_key VARCHAR(100) NOT NULL,
policy_version_no INT,
job_id VARCHAR(128),
command_id VARCHAR(128),
actor_user_id BIGINT NOT NULL,
owner_user_id BIGINT,
status VARCHAR(32) NOT NULL,
sample_count INT NOT NULL DEFAULT 0,
passed_count INT NOT NULL DEFAULT 0,
failed_count INT NOT NULL DEFAULT 0,
metric_summary JSONB,
error_code VARCHAR(64),
error_message TEXT,
started_at TIMESTAMP,
finished_at TIMESTAMP,
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_ai_evaluation_run UNIQUE (tenant_id, run_id)
);
CREATE INDEX idx_muse_ai_evaluation_run_owner_status
ON muse_ai_evaluation_run(tenant_id, owner_user_id, status, create_time)
WHERE owner_user_id IS NOT NULL;
CREATE INDEX idx_muse_ai_evaluation_run_policy
ON muse_ai_evaluation_run(tenant_id, policy_key, create_time);
CREATE TRIGGER trg_muse_ai_evaluation_run_updated_at
BEFORE UPDATE ON muse_ai_evaluation_run
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_ai_evaluation_sample_result (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
run_id VARCHAR(128) NOT NULL,
sample_id VARCHAR(128) NOT NULL,
owner_user_id BIGINT,
status VARCHAR(32) NOT NULL,
score NUMERIC(10, 4),
metric_summary JSONB,
input_summary JSONB,
output_summary JSONB,
error_code VARCHAR(64),
error_message TEXT,
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_ai_evaluation_sample UNIQUE (tenant_id, run_id, sample_id)
);
CREATE INDEX idx_muse_ai_evaluation_sample_owner_status
ON muse_ai_evaluation_sample_result(tenant_id, owner_user_id, status, create_time)
WHERE owner_user_id IS NOT NULL;
CREATE INDEX idx_muse_ai_evaluation_sample_run
ON muse_ai_evaluation_sample_result(tenant_id, run_id, create_time);
CREATE TRIGGER trg_muse_ai_evaluation_sample_updated_at
BEFORE UPDATE ON muse_ai_evaluation_sample_result
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_api_access_log_projection (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
access_id VARCHAR(128) NOT NULL,
operation_id VARCHAR(128) NOT NULL,
actor_user_id BIGINT,
owner_user_id BIGINT,
side VARCHAR(32) NOT NULL,
method VARCHAR(16) NOT NULL,
path VARCHAR(300) NOT NULL,
status_code INT,
business_code INT,
command_id VARCHAR(128),
correlation_id VARCHAR(200),
request_summary JSONB,
response_summary JSONB,
sanitized_client_ip_hash CHAR(64),
duration_ms BIGINT,
occurred_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
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_api_access_log UNIQUE (tenant_id, access_id)
);
CREATE INDEX idx_muse_api_access_log_owner
ON muse_api_access_log_projection(tenant_id, owner_user_id, occurred_at)
WHERE owner_user_id IS NOT NULL;
CREATE INDEX idx_muse_api_access_log_tenant_time
ON muse_api_access_log_projection(tenant_id, occurred_at);
CREATE INDEX idx_muse_api_access_log_actor_time
ON muse_api_access_log_projection(tenant_id, actor_user_id, occurred_at)
WHERE actor_user_id IS NOT NULL;
CREATE INDEX idx_muse_api_access_log_operation
ON muse_api_access_log_projection(tenant_id, operation_id, occurred_at);
CREATE TRIGGER trg_muse_api_access_log_updated_at
BEFORE UPDATE ON muse_api_access_log_projection
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE muse_business_audit_event (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
operation_id VARCHAR(128) NOT NULL,
actor_user_id BIGINT,
owner_user_id BIGINT,
side VARCHAR(32) NOT NULL,
target_type VARCHAR(64) NOT NULL,
target_id BIGINT,
command_id VARCHAR(128),
request_hash CHAR(64),
correlation_id VARCHAR(200),
request_summary JSONB,
response_summary JSONB,
risk_summary JSONB,
status VARCHAR(32) NOT NULL,
error_code VARCHAR(64),
error_message TEXT,
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_business_audit_owner
ON muse_business_audit_event(tenant_id, owner_user_id, create_time)
WHERE owner_user_id IS NOT NULL;
CREATE INDEX idx_muse_business_audit_tenant_time
ON muse_business_audit_event(tenant_id, create_time);
CREATE INDEX idx_muse_business_audit_operation
ON muse_business_audit_event(tenant_id, operation_id, create_time);
CREATE INDEX idx_muse_business_audit_correlation
ON muse_business_audit_event(tenant_id, correlation_id)
WHERE correlation_id IS NOT NULL;
CREATE TRIGGER trg_muse_business_audit_updated_at
BEFORE UPDATE ON muse_business_audit_event
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- WHY历史环境可能已经因为缺少 partial unique index 而存在同一 Prompt 多个 active 版本;
-- 父表 muse_prompt.active_version 是既有线上指针,优先保留它指向的 active 行,避免迁移把业务正在使用的版本误降级。
WITH ranked_prompt_active AS (
SELECT version.id,
ROW_NUMBER() OVER (
PARTITION BY version.tenant_id, version.prompt_key
ORDER BY CASE WHEN prompt.active_version = version.version THEN 0 ELSE 1 END,
version.update_time DESC, version.create_time DESC, version.id DESC
) AS rn
FROM muse_prompt_version version
LEFT JOIN muse_prompt prompt
ON prompt.tenant_id = version.tenant_id
AND prompt.prompt_key = version.prompt_key
AND prompt.deleted = FALSE
WHERE version.status = 'active' AND version.deleted = FALSE
)
UPDATE muse_prompt_version version
SET status = 'draft',
update_time = CURRENT_TIMESTAMP
FROM ranked_prompt_active duplicate
WHERE version.id = duplicate.id
AND duplicate.rn > 1;
WITH kept_prompt_active AS (
SELECT tenant_id, prompt_key, version
FROM muse_prompt_version
WHERE status = 'active' AND deleted = FALSE
)
UPDATE muse_prompt prompt
SET active_version = kept.version,
update_time = CURRENT_TIMESTAMP
FROM kept_prompt_active kept
WHERE prompt.tenant_id = kept.tenant_id
AND prompt.prompt_key = kept.prompt_key
AND prompt.deleted = FALSE
AND prompt.active_version IS DISTINCT FROM kept.version;
CREATE UNIQUE INDEX uk_muse_prompt_version_active
ON muse_prompt_version(tenant_id, prompt_key)
WHERE status = 'active' AND deleted = FALSE;
-- WHY历史环境可能已经因为缺少 partial unique index 而存在同一质量策略多个 active 版本;
-- 父表 muse_quality_policy.active_version 存 varchar而 version 表是 int必须按 version_no::text 优先保留父表指向版本。
WITH ranked_quality_policy_active AS (
SELECT version.id,
ROW_NUMBER() OVER (
PARTITION BY version.tenant_id, version.policy_key
ORDER BY CASE WHEN policy.active_version = version.version_no::text THEN 0 ELSE 1 END,
version.update_time DESC, version.create_time DESC, version.id DESC
) AS rn
FROM muse_quality_policy_version version
LEFT JOIN muse_quality_policy policy
ON policy.tenant_id = version.tenant_id
AND policy.policy_key = version.policy_key
AND policy.deleted = FALSE
WHERE version.active_flag = TRUE AND version.deleted = FALSE
)
UPDATE muse_quality_policy_version version
SET active_flag = FALSE,
update_time = CURRENT_TIMESTAMP
FROM ranked_quality_policy_active duplicate
WHERE version.id = duplicate.id
AND duplicate.rn > 1;
WITH kept_quality_policy_active AS (
SELECT tenant_id, policy_key, version_no
FROM muse_quality_policy_version
WHERE active_flag = TRUE AND deleted = FALSE
)
UPDATE muse_quality_policy policy
SET active_version = kept.version_no::text,
update_time = CURRENT_TIMESTAMP
FROM kept_quality_policy_active kept
WHERE policy.tenant_id = kept.tenant_id
AND policy.policy_key = kept.policy_key
AND policy.deleted = FALSE
AND policy.active_version IS DISTINCT FROM kept.version_no::text;
CREATE UNIQUE INDEX uk_muse_quality_policy_version_active
ON muse_quality_policy_version(tenant_id, policy_key)
WHERE active_flag = TRUE AND deleted = FALSE;