feat: add tenant-scoped rule and permission management

This commit is contained in:
wren
2026-05-21 22:03:08 +08:00
parent a2c2bf1969
commit 1f1bccf3b3
193 changed files with 64463 additions and 1771 deletions
@@ -0,0 +1,230 @@
BEGIN;
-- ============================================================================
-- Rule Domain Tenant Phase 1
-- 目标:
-- 1. 为规则域核心表补 tenant_code / scope_type / 运行结果快照字段
-- 2. 为运行时 TENANT -> PROVINCIAL -> PUBLIC 解析建立物理载体
-- 3. 将历史全局规则资产默认回填到 PROVINCIAL,而不是 PUBLIC
-- 说明:
-- - 本阶段只做补列、建索引、基础回填
-- - 不强制 NOT NULL
-- - 不删除旧 region / 全局兼容逻辑
-- ============================================================================
-- --------------------------------------------------------------------------
-- 1. leaudit_rule_sets
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_rule_sets
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
ADD COLUMN IF NOT EXISTS scope_type VARCHAR(32) DEFAULT 'PROVINCIAL',
ADD COLUMN IF NOT EXISTS source_rule_set_id BIGINT,
ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(255);
COMMENT ON COLUMN public.leaudit_rule_sets.tenant_code IS '规则集所属租户编码';
COMMENT ON COLUMN public.leaudit_rule_sets.scope_type IS '规则集作用域: TENANT / PROVINCIAL / PUBLIC';
COMMENT ON COLUMN public.leaudit_rule_sets.source_rule_set_id IS '派生规则集来源 rule_set_id';
COMMENT ON COLUMN public.leaudit_rule_sets.tenant_name_snapshot IS '规则集所属租户名称快照';
CREATE INDEX IF NOT EXISTS idx_leaudit_rule_sets_tenant_code
ON public.leaudit_rule_sets(tenant_code)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_leaudit_rule_sets_scope_type
ON public.leaudit_rule_sets(scope_type)
WHERE deleted_at IS NULL;
-- --------------------------------------------------------------------------
-- 2. leaudit_rule_versions
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_rule_versions
ADD COLUMN IF NOT EXISTS tenant_code_snapshot VARCHAR(64),
ADD COLUMN IF NOT EXISTS scope_type_snapshot VARCHAR(32),
ADD COLUMN IF NOT EXISTS source_version_id BIGINT;
COMMENT ON COLUMN public.leaudit_rule_versions.tenant_code_snapshot IS '规则版本所属租户编码快照';
COMMENT ON COLUMN public.leaudit_rule_versions.scope_type_snapshot IS '规则版本作用域快照';
COMMENT ON COLUMN public.leaudit_rule_versions.source_version_id IS '派生版本来源 version_id';
CREATE INDEX IF NOT EXISTS idx_leaudit_rule_versions_tenant_code_snapshot
ON public.leaudit_rule_versions(tenant_code_snapshot);
-- --------------------------------------------------------------------------
-- 3. leaudit_rule_group_bindings
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_rule_group_bindings
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
ADD COLUMN IF NOT EXISTS scope_type VARCHAR(32) DEFAULT 'PROVINCIAL',
ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(255);
COMMENT ON COLUMN public.leaudit_rule_group_bindings.tenant_code IS '业务组绑定所属租户编码';
COMMENT ON COLUMN public.leaudit_rule_group_bindings.scope_type IS '业务组绑定作用域: TENANT / PROVINCIAL / PUBLIC';
COMMENT ON COLUMN public.leaudit_rule_group_bindings.tenant_name_snapshot IS '业务组绑定所属租户名称快照';
CREATE INDEX IF NOT EXISTS idx_leaudit_rule_group_bindings_group_tenant
ON public.leaudit_rule_group_bindings(group_id, tenant_code)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_leaudit_rule_group_bindings_scope_type
ON public.leaudit_rule_group_bindings(scope_type)
WHERE deleted_at IS NULL;
-- --------------------------------------------------------------------------
-- 4. leaudit_rule_type_bindings
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_rule_type_bindings
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
ADD COLUMN IF NOT EXISTS scope_type VARCHAR(32) DEFAULT 'PROVINCIAL';
COMMENT ON COLUMN public.leaudit_rule_type_bindings.tenant_code IS '旧规则类型绑定所属租户编码,仅用于兼容与迁移';
COMMENT ON COLUMN public.leaudit_rule_type_bindings.scope_type IS '旧规则类型绑定作用域,仅用于兼容与迁移';
-- --------------------------------------------------------------------------
-- 5. leaudit_audit_runs
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_audit_runs
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(255),
ADD COLUMN IF NOT EXISTS scope_type_snapshot VARCHAR(32),
ADD COLUMN IF NOT EXISTS group_id_snapshot BIGINT,
ADD COLUMN IF NOT EXISTS rule_binding_id_snapshot BIGINT;
COMMENT ON COLUMN public.leaudit_audit_runs.tenant_code IS '本次运行所属租户编码快照';
COMMENT ON COLUMN public.leaudit_audit_runs.tenant_name_snapshot IS '本次运行所属租户名称快照';
COMMENT ON COLUMN public.leaudit_audit_runs.scope_type_snapshot IS '本次运行命中的规则作用域快照';
COMMENT ON COLUMN public.leaudit_audit_runs.group_id_snapshot IS '本次运行命中的业务组快照';
COMMENT ON COLUMN public.leaudit_audit_runs.rule_binding_id_snapshot IS '本次运行命中的规则绑定快照';
CREATE INDEX IF NOT EXISTS idx_leaudit_audit_runs_tenant_code
ON public.leaudit_audit_runs(tenant_code, created_at DESC);
-- --------------------------------------------------------------------------
-- 6. leaudit_rule_results
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_rule_results
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(255);
COMMENT ON COLUMN public.leaudit_rule_results.tenant_code IS '规则结果所属租户编码快照';
COMMENT ON COLUMN public.leaudit_rule_results.tenant_name_snapshot IS '规则结果所属租户名称快照';
CREATE INDEX IF NOT EXISTS idx_leaudit_rule_results_tenant_code
ON public.leaudit_rule_results(tenant_code);
-- --------------------------------------------------------------------------
-- 7. leaudit_run_errors
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_run_errors
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(255);
COMMENT ON COLUMN public.leaudit_run_errors.tenant_code IS '运行错误所属租户编码快照';
COMMENT ON COLUMN public.leaudit_run_errors.tenant_name_snapshot IS '运行错误所属租户名称快照';
CREATE INDEX IF NOT EXISTS idx_leaudit_run_errors_tenant_code
ON public.leaudit_run_errors(tenant_code);
-- --------------------------------------------------------------------------
-- 8. leaudit_run_metrics
-- --------------------------------------------------------------------------
ALTER TABLE public.leaudit_run_metrics
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64);
COMMENT ON COLUMN public.leaudit_run_metrics.tenant_code IS '运行指标所属租户编码快照';
CREATE INDEX IF NOT EXISTS idx_leaudit_run_metrics_tenant_code
ON public.leaudit_run_metrics(tenant_code);
-- --------------------------------------------------------------------------
-- 9. 历史资产默认回填到 PROVINCIAL
-- --------------------------------------------------------------------------
UPDATE public.leaudit_rule_sets
SET tenant_code = COALESCE(NULLIF(BTRIM(tenant_code), ''), 'PROVINCIAL'),
scope_type = COALESCE(NULLIF(BTRIM(scope_type), ''), 'PROVINCIAL')
WHERE deleted_at IS NULL;
-- 兼容历史唯一约束 (rule_type, region):租户私有规则集必须使用租户编码作为 legacy region
-- 否则会与省级默认 region=default 冲突。
UPDATE public.leaudit_rule_sets
SET region = tenant_code
WHERE deleted_at IS NULL
AND scope_type = 'TENANT'
AND tenant_code IS NOT NULL
AND BTRIM(tenant_code) <> ''
AND region = 'default';
UPDATE public.leaudit_rule_versions rv
SET tenant_code_snapshot = COALESCE(
NULLIF(BTRIM(rv.tenant_code_snapshot), ''),
NULLIF(BTRIM(rs.tenant_code), ''),
'PROVINCIAL'
),
scope_type_snapshot = COALESCE(
NULLIF(BTRIM(rv.scope_type_snapshot), ''),
NULLIF(BTRIM(rs.scope_type), ''),
'PROVINCIAL'
)
FROM public.leaudit_rule_sets rs
WHERE rv.rule_set_id = rs.id;
UPDATE public.leaudit_rule_group_bindings rgb
SET tenant_code = COALESCE(NULLIF(BTRIM(rgb.tenant_code), ''), 'PROVINCIAL'),
scope_type = COALESCE(NULLIF(BTRIM(rgb.scope_type), ''), 'PROVINCIAL')
WHERE rgb.deleted_at IS NULL;
UPDATE public.leaudit_rule_type_bindings
SET tenant_code = COALESCE(NULLIF(BTRIM(tenant_code), ''), 'PROVINCIAL'),
scope_type = COALESCE(NULLIF(BTRIM(scope_type), ''), 'PROVINCIAL')
WHERE deleted_at IS NULL;
-- --------------------------------------------------------------------------
-- 10. 运行与结果快照回填
-- --------------------------------------------------------------------------
UPDATE public.leaudit_audit_runs ar
SET tenant_code = COALESCE(
NULLIF(BTRIM(ar.tenant_code), ''),
NULLIF(BTRIM(d.tenant_code), ''),
'PROVINCIAL'
),
scope_type_snapshot = COALESCE(
NULLIF(BTRIM(ar.scope_type_snapshot), ''),
'PROVINCIAL'
),
group_id_snapshot = COALESCE(ar.group_id_snapshot, d.group_id)
FROM public.leaudit_documents d
WHERE ar.document_id = d.id;
UPDATE public.leaudit_rule_results rr
SET tenant_code = COALESCE(
NULLIF(BTRIM(rr.tenant_code), ''),
NULLIF(BTRIM(ar.tenant_code), ''),
NULLIF(BTRIM(d.tenant_code), ''),
'PROVINCIAL'
)
FROM public.leaudit_audit_runs ar
LEFT JOIN public.leaudit_documents d ON d.id = ar.document_id
WHERE rr.run_id = ar.id;
UPDATE public.leaudit_run_errors re
SET tenant_code = COALESCE(
NULLIF(BTRIM(re.tenant_code), ''),
NULLIF(BTRIM(ar.tenant_code), ''),
NULLIF(BTRIM(d.tenant_code), ''),
'PROVINCIAL'
)
FROM public.leaudit_audit_runs ar
LEFT JOIN public.leaudit_documents d ON d.id = ar.document_id
WHERE re.run_id = ar.id;
UPDATE public.leaudit_run_metrics rm
SET tenant_code = COALESCE(
NULLIF(BTRIM(rm.tenant_code), ''),
NULLIF(BTRIM(ar.tenant_code), ''),
NULLIF(BTRIM(d.tenant_code), ''),
'PROVINCIAL'
)
FROM public.leaudit_audit_runs ar
LEFT JOIN public.leaudit_documents d ON d.id = ar.document_id
WHERE rm.run_id = ar.id;
COMMIT;