99 lines
5.8 KiB
PL/PgSQL
99 lines
5.8 KiB
PL/PgSQL
-- example_reference_authorization_snapshot:参考作品用途授权的不可变快照。
|
||
-- 本表只允许 INSERT;授权变化通过新增版本表达,禁止覆盖或删除历史证据。
|
||
CREATE FUNCTION example_jsonb_text_arrays_disjoint(left_values JSONB, right_values JSONB)
|
||
RETURNS BOOLEAN
|
||
LANGUAGE sql
|
||
IMMUTABLE
|
||
STRICT
|
||
AS $$
|
||
SELECT NOT EXISTS (
|
||
SELECT 1
|
||
FROM jsonb_array_elements_text(left_values) AS left_value(value)
|
||
JOIN jsonb_array_elements_text(right_values) AS right_value(value) USING (value)
|
||
);
|
||
$$;
|
||
|
||
CREATE TABLE example_reference_authorization_snapshot (
|
||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||
reference_work_id BIGINT NOT NULL, -- → example_reference_work.id(软引用)
|
||
work_id BIGINT NOT NULL, -- → muse_content_work.id(软引用)
|
||
knowledge_document_id BIGINT NOT NULL, -- → muse_knowledge_document.id(软引用)
|
||
import_task_id BIGINT NOT NULL, -- → muse_content_import_task.id(软引用)
|
||
source_file VARCHAR(500) NOT NULL, -- 授权对应的原文件名
|
||
source_hash VARCHAR(71) NOT NULL, -- sha256:<64位小写十六进制>
|
||
source_version VARCHAR(96) NOT NULL, -- raw-file-v1:sha256:<64位小写十六进制>
|
||
snapshot_version VARCHAR(160) NOT NULL, -- 授权快照业务版本,不使用物理主键充当合同版本
|
||
copyright_status VARCHAR(30) NOT NULL, -- licensed/public_domain/research_only/unauthorized
|
||
source_status VARCHAR(30) NOT NULL DEFAULT 'active',
|
||
allowed_purpose JSONB NOT NULL DEFAULT '[]', -- 允许用途数组,例如 ["offline_evaluation"]
|
||
forbidden_purpose JSONB NOT NULL DEFAULT '[]', -- 明确禁止用途数组,例如 ["external_distribution"]
|
||
authorization_basis VARCHAR(40) NOT NULL, -- user_authorization/public_domain_record/license_contract
|
||
authorized_by VARCHAR(128) NOT NULL, -- 授权主体或登记责任人
|
||
authorization_evidence JSONB NOT NULL, -- 授权原文摘要、时间和证据定位,不存敏感全文
|
||
display_summary VARCHAR(500) NOT NULL, -- 面向审计面的脱敏摘要
|
||
checked_at TIMESTAMPTZ NOT NULL, -- 本次授权核验时间
|
||
expires_at TIMESTAMPTZ, -- 到期即阻断
|
||
revalidation_at TIMESTAMPTZ, -- 到点必须重验
|
||
creator VARCHAR(64) NOT NULL DEFAULT '',
|
||
create_time TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
CONSTRAINT uk_example_reference_auth_work_version UNIQUE (tenant_id, work_id, snapshot_version),
|
||
CONSTRAINT chk_example_reference_auth_source_hash
|
||
CHECK (source_hash ~ '^sha256:[0-9a-f]{64}$'),
|
||
CONSTRAINT chk_example_reference_auth_source_version
|
||
CHECK (source_version = 'raw-file-v1:' || source_hash),
|
||
CONSTRAINT chk_example_reference_auth_copyright
|
||
CHECK (copyright_status IN ('research_only','public_domain','licensed','unauthorized')),
|
||
CONSTRAINT chk_example_reference_auth_source_status
|
||
CHECK (source_status IN ('active','stale','revoked','delisted','recalled','blocked','owner_missing','unauthorized')),
|
||
CONSTRAINT chk_example_reference_auth_allowed_purpose
|
||
CHECK (jsonb_typeof(allowed_purpose) = 'array'),
|
||
CONSTRAINT chk_example_reference_auth_forbidden_purpose
|
||
CHECK (jsonb_typeof(forbidden_purpose) = 'array'),
|
||
CONSTRAINT chk_example_reference_auth_purpose_disjoint
|
||
CHECK (example_jsonb_text_arrays_disjoint(allowed_purpose, forbidden_purpose)),
|
||
CONSTRAINT chk_example_reference_auth_basis
|
||
CHECK (authorization_basis IN ('user_authorization','public_domain_record','license_contract')),
|
||
CONSTRAINT chk_example_reference_auth_basis_copyright
|
||
CHECK (
|
||
(authorization_basis <> 'user_authorization' OR copyright_status = 'research_only')
|
||
AND (authorization_basis <> 'public_domain_record' OR copyright_status = 'public_domain')
|
||
AND (authorization_basis <> 'license_contract' OR copyright_status = 'licensed')
|
||
),
|
||
CONSTRAINT chk_example_reference_auth_user_purpose
|
||
CHECK (
|
||
authorization_basis <> 'user_authorization'
|
||
OR allowed_purpose = '["offline_evaluation"]'::jsonb
|
||
),
|
||
CONSTRAINT chk_example_reference_auth_evidence
|
||
CHECK (jsonb_typeof(authorization_evidence) = 'object'),
|
||
CONSTRAINT chk_example_reference_auth_purpose
|
||
CHECK (
|
||
(copyright_status = 'unauthorized' AND jsonb_array_length(allowed_purpose) = 0)
|
||
OR (copyright_status <> 'unauthorized' AND jsonb_array_length(allowed_purpose) > 0)
|
||
),
|
||
CONSTRAINT chk_example_reference_auth_recheck
|
||
CHECK (expires_at IS NOT NULL OR revalidation_at IS NOT NULL),
|
||
CONSTRAINT chk_example_reference_auth_expiry_order
|
||
CHECK (expires_at IS NULL OR expires_at > checked_at),
|
||
CONSTRAINT chk_example_reference_auth_revalidation_order
|
||
CHECK (revalidation_at IS NULL OR revalidation_at > checked_at)
|
||
);
|
||
|
||
CREATE INDEX idx_example_reference_auth_latest
|
||
ON example_reference_authorization_snapshot(tenant_id, work_id, checked_at DESC, id DESC);
|
||
|
||
-- 授权快照是审计证据;撤销、到期或用途变化都必须插入新版本,不能改写旧记录。
|
||
CREATE FUNCTION reject_example_reference_authorization_snapshot_mutation()
|
||
RETURNS TRIGGER
|
||
LANGUAGE plpgsql
|
||
AS $$
|
||
BEGIN
|
||
RAISE EXCEPTION 'example_reference_authorization_snapshot 是 append-only 表,禁止 UPDATE/DELETE';
|
||
END;
|
||
$$;
|
||
|
||
CREATE TRIGGER trg_example_reference_auth_append_only
|
||
BEFORE UPDATE OR DELETE ON example_reference_authorization_snapshot
|
||
FOR EACH ROW EXECUTE FUNCTION reject_example_reference_authorization_snapshot_mutation();
|