feat: add tenant-scoped rule and permission management
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================================
|
||||
-- RAG 公共知识库未归属默认项迁移
|
||||
--
|
||||
-- 背景:
|
||||
-- 历史 RAG 知识库存在 tenant_code 为空、area 为空/default/公共、is_public=true 的公共知识库。
|
||||
-- 如果这类记录是默认知识库,后端会禁止直接取消默认/删除;同时 PUBLIC 组另有默认
|
||||
-- 时,页面会出现两个“默认”,但它们属于不同默认组。
|
||||
--
|
||||
-- 目标:
|
||||
-- 1. 将历史未归属公共 RAG 知识库迁移到 tenant_code='PUBLIC'、area='公共'
|
||||
-- 2. 同步其关联 rag_chat_app 的 tenant_code/area
|
||||
-- 3. 迁移后 PUBLIC 组只保留一个默认知识库/默认应用
|
||||
--
|
||||
-- 执行前:
|
||||
-- 先执行 precheck_rag_public_orphan_defaults.sql,确认候选记录符合预期。
|
||||
-- ============================================================================
|
||||
|
||||
ALTER TABLE public.rag_dataset
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64);
|
||||
|
||||
ALTER TABLE public.rag_chat_app
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rag_dataset_tenant_code
|
||||
ON public.rag_dataset(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rag_chat_app_tenant_code
|
||||
ON public.rag_chat_app(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE TEMP TABLE tmp_rag_public_orphan_dataset_ids (
|
||||
id BIGINT PRIMARY KEY
|
||||
) ON COMMIT DROP;
|
||||
|
||||
INSERT INTO tmp_rag_public_orphan_dataset_ids (id)
|
||||
SELECT d.id
|
||||
FROM public.rag_dataset d
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '')
|
||||
AND d.is_public IS TRUE
|
||||
AND (
|
||||
d.area IS NULL
|
||||
OR BTRIM(d.area) = ''
|
||||
OR LOWER(BTRIM(d.area)) = 'default'
|
||||
OR BTRIM(d.area) = '公共'
|
||||
)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
WITH
|
||||
updated_dataset AS (
|
||||
UPDATE public.rag_dataset d
|
||||
SET tenant_code = 'PUBLIC',
|
||||
area = '公共',
|
||||
is_public = TRUE,
|
||||
updated_at = NOW()
|
||||
FROM tmp_rag_public_orphan_dataset_ids orphan
|
||||
WHERE d.id = orphan.id
|
||||
RETURNING d.id
|
||||
)
|
||||
UPDATE public.rag_chat_app a
|
||||
SET tenant_code = 'PUBLIC',
|
||||
area = '公共',
|
||||
updated_at = NOW()
|
||||
FROM updated_dataset ud
|
||||
WHERE a.dataset_id = ud.id
|
||||
AND a.deleted_at IS NULL;
|
||||
|
||||
WITH ranked_public_dataset AS (
|
||||
SELECT
|
||||
d.id,
|
||||
ROW_NUMBER() OVER (
|
||||
ORDER BY
|
||||
d.is_default DESC,
|
||||
CASE WHEN orphan.id IS NULL THEN 0 ELSE 1 END,
|
||||
d.created_at DESC,
|
||||
d.id DESC
|
||||
) AS keep_default_rank
|
||||
FROM public.rag_dataset d
|
||||
LEFT JOIN tmp_rag_public_orphan_dataset_ids orphan ON orphan.id = d.id
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND BTRIM(COALESCE(d.tenant_code, '')) = 'PUBLIC'
|
||||
),
|
||||
normalized_public_dataset AS (
|
||||
UPDATE public.rag_dataset d
|
||||
SET is_default = (rpd.keep_default_rank = 1),
|
||||
updated_at = NOW()
|
||||
FROM ranked_public_dataset rpd
|
||||
WHERE d.id = rpd.id
|
||||
RETURNING d.id, d.is_default
|
||||
)
|
||||
UPDATE public.rag_chat_app a
|
||||
SET is_default = npd.is_default,
|
||||
tenant_code = 'PUBLIC',
|
||||
area = '公共',
|
||||
updated_at = NOW()
|
||||
FROM normalized_public_dataset npd
|
||||
WHERE a.dataset_id = npd.id
|
||||
AND a.deleted_at IS NULL;
|
||||
|
||||
-- 验收输出:PUBLIC 组当前默认知识库应只剩 1 条。
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE is_default = TRUE) AS public_default_count,
|
||||
COUNT(*) AS public_dataset_count
|
||||
FROM public.rag_dataset
|
||||
WHERE deleted_at IS NULL
|
||||
AND BTRIM(COALESCE(tenant_code, '')) = 'PUBLIC';
|
||||
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
area,
|
||||
tenant_code,
|
||||
is_public,
|
||||
is_default,
|
||||
CASE
|
||||
WHEN id IN (SELECT id FROM tmp_rag_public_orphan_dataset_ids) THEN 'migrated_orphan'
|
||||
ELSE 'existing_public'
|
||||
END AS source_scope,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM public.rag_dataset
|
||||
WHERE deleted_at IS NULL
|
||||
AND BTRIM(COALESCE(tenant_code, '')) = 'PUBLIC'
|
||||
ORDER BY is_default DESC, created_at DESC, id DESC;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,282 @@
|
||||
-- ============================================================================
|
||||
-- Evaluation Points Tenant Cleanup Precheck
|
||||
-- 目标:
|
||||
-- 1. 在执行 schema_evaluation_points_tenant_cleanup.sql 前先识别风险
|
||||
-- 2. 输出 area 分布、无法映射记录、共享域残留、编码重复情况
|
||||
-- 3. 供 DBA / 开发在评审和落库前人工确认
|
||||
-- 说明:
|
||||
-- - 本脚本只读,不修改任何数据
|
||||
-- - 建议在生产、预发、测试库分别执行并保存结果
|
||||
-- ============================================================================
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 0. 当前表结构确认
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
column_name,
|
||||
data_type,
|
||||
is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'evaluation_points'
|
||||
ORDER BY ordinal_position;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 1. 基础体量
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT COUNT(*) AS total_points
|
||||
FROM public.evaluation_points;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 1.1 构建兼容旧库的预检视图
|
||||
-- - 若旧库还没有 tenant_code / tenant_name,则自动补 NULL 占位
|
||||
-- - 后续所有预检统一只读这个临时视图
|
||||
-- --------------------------------------------------------------------------
|
||||
DO $$
|
||||
DECLARE
|
||||
has_tenant_code BOOLEAN;
|
||||
has_tenant_name BOOLEAN;
|
||||
tenant_code_expr TEXT;
|
||||
tenant_name_expr TEXT;
|
||||
BEGIN
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'evaluation_points'
|
||||
AND column_name = 'tenant_code'
|
||||
) INTO has_tenant_code;
|
||||
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'evaluation_points'
|
||||
AND column_name = 'tenant_name'
|
||||
) INTO has_tenant_name;
|
||||
|
||||
tenant_code_expr := CASE
|
||||
WHEN has_tenant_code THEN 'tenant_code'
|
||||
ELSE 'NULL::VARCHAR(64) AS tenant_code'
|
||||
END;
|
||||
|
||||
tenant_name_expr := CASE
|
||||
WHEN has_tenant_name THEN 'tenant_name'
|
||||
ELSE 'NULL::VARCHAR(128) AS tenant_name'
|
||||
END;
|
||||
|
||||
EXECUTE format(
|
||||
'CREATE TEMP VIEW tmp_evaluation_points_precheck AS
|
||||
SELECT
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
area,
|
||||
%s,
|
||||
%s
|
||||
FROM public.evaluation_points',
|
||||
tenant_code_expr,
|
||||
tenant_name_expr
|
||||
);
|
||||
END $$;
|
||||
|
||||
SELECT
|
||||
COUNT(*) AS total_points,
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS missing_tenant_code,
|
||||
COUNT(*) FILTER (WHERE tenant_name IS NULL OR BTRIM(tenant_name) = '') AS missing_tenant_name,
|
||||
COUNT(*) FILTER (WHERE area IS NULL OR BTRIM(area) = '') AS blank_area
|
||||
FROM tmp_evaluation_points_precheck;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 2. area 值分布
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
COALESCE(NULLIF(BTRIM(area), ''), '<EMPTY>') AS area_value,
|
||||
COUNT(*) AS point_count
|
||||
FROM tmp_evaluation_points_precheck
|
||||
GROUP BY 1
|
||||
ORDER BY point_count DESC, area_value ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 3. area 无法映射租户编码的残留清单
|
||||
-- 规则:别名表 -> 租户名 -> 共享域兼容值
|
||||
-- --------------------------------------------------------------------------
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_points AS (
|
||||
SELECT
|
||||
ep.id,
|
||||
ep.code,
|
||||
ep.name,
|
||||
ep.area,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(ep.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(ep.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code
|
||||
FROM tmp_evaluation_points_precheck ep
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(ep.area, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(ep.area, ''))) = tn.normalized_tenant_name
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
area
|
||||
FROM resolved_points
|
||||
WHERE resolved_tenant_code IS NULL
|
||||
ORDER BY id ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 4. 共享域残留统计
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
CASE
|
||||
WHEN area IS NULL OR BTRIM(area) = '' THEN '<EMPTY>'
|
||||
ELSE BTRIM(area)
|
||||
END AS shared_area_value,
|
||||
COUNT(*) AS point_count
|
||||
FROM tmp_evaluation_points_precheck
|
||||
WHERE area IS NULL
|
||||
OR BTRIM(area) = ''
|
||||
OR LOWER(BTRIM(area)) = 'default'
|
||||
OR BTRIM(area) IN ('公共', '省级', '省局')
|
||||
GROUP BY 1
|
||||
ORDER BY point_count DESC, shared_area_value ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 5. tenant_name 映射冲突预检
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
COUNT(DISTINCT tenant_code) AS tenant_code_count,
|
||||
ARRAY_AGG(DISTINCT tenant_code ORDER BY tenant_code) AS tenant_codes
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
AND tenant_name IS NOT NULL
|
||||
AND BTRIM(tenant_name) <> ''
|
||||
GROUP BY 1
|
||||
HAVING COUNT(DISTINCT tenant_code) > 1
|
||||
ORDER BY normalized_tenant_name ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 6. alias 映射冲突预检
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
COUNT(DISTINCT tenant_code) AS tenant_code_count,
|
||||
ARRAY_AGG(DISTINCT tenant_code ORDER BY tenant_code) AS tenant_codes
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
AND alias_value IS NOT NULL
|
||||
AND BTRIM(alias_value) <> ''
|
||||
GROUP BY 1
|
||||
HAVING COUNT(DISTINCT tenant_code) > 1
|
||||
ORDER BY normalized_alias_value ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 7. 编码唯一性现状预检
|
||||
-- 注意:当前 service 仍按全局唯一校验 code,不是按 tenant_code + code 校验
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
LOWER(BTRIM(code)) AS normalized_code,
|
||||
COUNT(*) AS duplicate_count,
|
||||
ARRAY_AGG(id ORDER BY id) AS point_ids
|
||||
FROM tmp_evaluation_points_precheck
|
||||
WHERE code IS NOT NULL
|
||||
AND BTRIM(code) <> ''
|
||||
GROUP BY 1
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY duplicate_count DESC, normalized_code ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 8. 若后续想把 code 改成“按租户唯一”,先看跨租户重复情况
|
||||
-- 这里用“预估 tenant_code”做模拟,不代表当前表已有 tenant_code
|
||||
-- --------------------------------------------------------------------------
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_points AS (
|
||||
SELECT
|
||||
ep.id,
|
||||
LOWER(BTRIM(ep.code)) AS normalized_code,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(ep.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(ep.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code
|
||||
FROM tmp_evaluation_points_precheck ep
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(ep.area, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(ep.area, ''))) = tn.normalized_tenant_name
|
||||
WHERE ep.code IS NOT NULL
|
||||
AND BTRIM(ep.code) <> ''
|
||||
)
|
||||
SELECT
|
||||
normalized_code,
|
||||
COUNT(*) AS duplicate_count,
|
||||
COUNT(DISTINCT resolved_tenant_code) AS tenant_count,
|
||||
ARRAY_AGG(
|
||||
CONCAT(id, ':', COALESCE(resolved_tenant_code, '<UNRESOLVED>'))
|
||||
ORDER BY id
|
||||
) AS point_ids_with_tenant
|
||||
FROM resolved_points
|
||||
GROUP BY normalized_code
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY duplicate_count DESC, normalized_code ASC;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 9. 执行后验收时建议对照的基线统计
|
||||
-- --------------------------------------------------------------------------
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS missing_tenant_code,
|
||||
COUNT(*) FILTER (WHERE tenant_name IS NULL OR BTRIM(tenant_name) = '') AS missing_tenant_name
|
||||
FROM tmp_evaluation_points_precheck;
|
||||
@@ -0,0 +1,134 @@
|
||||
-- ============================================================================
|
||||
-- RAG 公共知识库未归属默认项迁移前检查
|
||||
--
|
||||
-- 用途:
|
||||
-- 检查历史 tenant_code 为空,area 为空/default/公共,且 is_public=true 的 RAG 知识库/应用。
|
||||
-- 这些记录在页面显示为“未分配地区”,且如果 is_default=true,会导致无法删除。
|
||||
--
|
||||
-- 执行:
|
||||
-- psql -h <host> -U <user> -d <db_name> -v ON_ERROR_STOP=1 \
|
||||
-- -f scripts/创建sql/precheck_rag_public_orphan_defaults.sql
|
||||
-- ============================================================================
|
||||
|
||||
-- 1. 历史未归属公共知识库迁移候选
|
||||
SELECT
|
||||
d.id,
|
||||
d.name,
|
||||
d.description,
|
||||
d.area,
|
||||
d.tenant_code,
|
||||
d.is_public,
|
||||
d.is_default,
|
||||
d.status,
|
||||
d.created_at,
|
||||
d.updated_at
|
||||
FROM public.rag_dataset d
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '')
|
||||
AND d.is_public IS TRUE
|
||||
AND (
|
||||
d.area IS NULL
|
||||
OR BTRIM(d.area) = ''
|
||||
OR LOWER(BTRIM(d.area)) = 'default'
|
||||
OR BTRIM(d.area) = '公共'
|
||||
)
|
||||
ORDER BY d.is_default DESC, d.created_at DESC, d.id DESC;
|
||||
|
||||
-- 2. 当前 PUBLIC 组默认知识库
|
||||
SELECT
|
||||
d.id,
|
||||
d.name,
|
||||
d.description,
|
||||
d.area,
|
||||
d.tenant_code,
|
||||
d.is_public,
|
||||
d.is_default,
|
||||
d.status,
|
||||
d.created_at,
|
||||
d.updated_at
|
||||
FROM public.rag_dataset d
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND BTRIM(COALESCE(d.tenant_code, '')) = 'PUBLIC'
|
||||
ORDER BY d.is_default DESC, d.created_at DESC, d.id DESC;
|
||||
|
||||
-- 3. 迁移后 PUBLIC 组默认冲突预览
|
||||
WITH candidate AS (
|
||||
SELECT
|
||||
d.id,
|
||||
d.name,
|
||||
d.area,
|
||||
CASE
|
||||
WHEN BTRIM(COALESCE(d.tenant_code, '')) = 'PUBLIC' THEN 'existing_public'
|
||||
ELSE 'orphan_public'
|
||||
END AS source_scope,
|
||||
COALESCE(NULLIF(BTRIM(d.tenant_code), ''), 'PUBLIC') AS target_tenant_code,
|
||||
d.is_default,
|
||||
d.is_public,
|
||||
d.created_at
|
||||
FROM public.rag_dataset d
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND (
|
||||
BTRIM(COALESCE(d.tenant_code, '')) = 'PUBLIC'
|
||||
OR (
|
||||
(d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '')
|
||||
AND d.is_public IS TRUE
|
||||
AND (
|
||||
d.area IS NULL
|
||||
OR BTRIM(d.area) = ''
|
||||
OR LOWER(BTRIM(d.area)) = 'default'
|
||||
OR BTRIM(d.area) = '公共'
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
ranked AS (
|
||||
SELECT
|
||||
c.*,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY c.target_tenant_code
|
||||
ORDER BY
|
||||
c.is_default DESC,
|
||||
CASE WHEN c.source_scope = 'existing_public' THEN 0 ELSE 1 END,
|
||||
c.created_at DESC,
|
||||
c.id DESC
|
||||
) AS keep_default_rank
|
||||
FROM candidate c
|
||||
)
|
||||
SELECT
|
||||
target_tenant_code,
|
||||
id,
|
||||
name,
|
||||
area,
|
||||
source_scope,
|
||||
is_public,
|
||||
is_default AS current_is_default,
|
||||
keep_default_rank,
|
||||
CASE WHEN keep_default_rank = 1 THEN '迁移后保留默认' ELSE '迁移后取消默认' END AS planned_default_action
|
||||
FROM ranked
|
||||
ORDER BY target_tenant_code, keep_default_rank, id;
|
||||
|
||||
-- 4. 关联应用候选
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.area,
|
||||
a.tenant_code,
|
||||
a.dataset_id,
|
||||
a.is_default,
|
||||
a.status,
|
||||
a.created_at,
|
||||
a.updated_at
|
||||
FROM public.rag_chat_app a
|
||||
JOIN public.rag_dataset d ON d.id = a.dataset_id
|
||||
WHERE a.deleted_at IS NULL
|
||||
AND d.deleted_at IS NULL
|
||||
AND (a.tenant_code IS NULL OR BTRIM(a.tenant_code) = '')
|
||||
AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '')
|
||||
AND d.is_public IS TRUE
|
||||
AND (
|
||||
d.area IS NULL
|
||||
OR BTRIM(d.area) = ''
|
||||
OR LOWER(BTRIM(d.area)) = 'default'
|
||||
OR BTRIM(d.area) = '公共'
|
||||
)
|
||||
ORDER BY a.is_default DESC, a.created_at DESC, a.id DESC;
|
||||
@@ -0,0 +1,118 @@
|
||||
-- ============================================================================
|
||||
-- Rule Domain Tenant Phase 1 Precheck
|
||||
-- 目标:
|
||||
-- 1. 执行前确认规则域现状
|
||||
-- 2. 识别历史全局规则资产规模
|
||||
-- 3. 识别运行结果快照回填影响范围
|
||||
-- ============================================================================
|
||||
|
||||
-- 1. 核心表是否存在
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = current_schema()
|
||||
AND table_name IN (
|
||||
'leaudit_rule_sets',
|
||||
'leaudit_rule_versions',
|
||||
'leaudit_rule_group_bindings',
|
||||
'leaudit_rule_type_bindings',
|
||||
'leaudit_audit_runs',
|
||||
'leaudit_rule_results',
|
||||
'leaudit_run_errors',
|
||||
'leaudit_run_metrics'
|
||||
)
|
||||
ORDER BY table_name;
|
||||
|
||||
-- 2. 当前列缺失情况
|
||||
SELECT
|
||||
table_name,
|
||||
column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = current_schema()
|
||||
AND table_name IN (
|
||||
'leaudit_rule_sets',
|
||||
'leaudit_rule_versions',
|
||||
'leaudit_rule_group_bindings',
|
||||
'leaudit_rule_type_bindings',
|
||||
'leaudit_audit_runs',
|
||||
'leaudit_rule_results',
|
||||
'leaudit_run_errors',
|
||||
'leaudit_run_metrics'
|
||||
)
|
||||
AND column_name IN (
|
||||
'tenant_code',
|
||||
'scope_type',
|
||||
'tenant_code_snapshot',
|
||||
'scope_type_snapshot',
|
||||
'source_rule_set_id',
|
||||
'source_version_id',
|
||||
'tenant_name_snapshot',
|
||||
'group_id_snapshot',
|
||||
'rule_binding_id_snapshot'
|
||||
)
|
||||
ORDER BY table_name, column_name;
|
||||
|
||||
-- 3. 规则集与规则版本规模
|
||||
SELECT 'leaudit_rule_sets' AS table_name, COUNT(*) AS total
|
||||
FROM leaudit_rule_sets
|
||||
WHERE deleted_at IS NULL
|
||||
UNION ALL
|
||||
SELECT 'leaudit_rule_versions' AS table_name, COUNT(*) AS total
|
||||
FROM leaudit_rule_versions
|
||||
UNION ALL
|
||||
SELECT 'leaudit_rule_group_bindings' AS table_name, COUNT(*) AS total
|
||||
FROM leaudit_rule_group_bindings
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- 4. 历史全局规则资产规模
|
||||
SELECT
|
||||
COUNT(*) AS global_rule_sets_without_tenant_code
|
||||
FROM leaudit_rule_sets
|
||||
WHERE deleted_at IS NULL
|
||||
AND (
|
||||
tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = ''
|
||||
);
|
||||
|
||||
SELECT
|
||||
COUNT(*) AS global_group_bindings_without_tenant_code
|
||||
FROM leaudit_rule_group_bindings
|
||||
WHERE deleted_at IS NULL
|
||||
AND (
|
||||
tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = ''
|
||||
);
|
||||
|
||||
-- 5. 运行主表与结果表快照缺口
|
||||
SELECT
|
||||
COUNT(*) AS audit_runs_missing_tenant_code
|
||||
FROM leaudit_audit_runs
|
||||
WHERE tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = '';
|
||||
|
||||
SELECT
|
||||
COUNT(*) AS rule_results_missing_tenant_code
|
||||
FROM leaudit_rule_results
|
||||
WHERE tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = '';
|
||||
|
||||
SELECT
|
||||
COUNT(*) AS run_errors_missing_tenant_code
|
||||
FROM leaudit_run_errors
|
||||
WHERE tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = '';
|
||||
|
||||
SELECT
|
||||
COUNT(*) AS run_metrics_missing_tenant_code
|
||||
FROM leaudit_run_metrics
|
||||
WHERE tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = '';
|
||||
|
||||
-- 6. 文档租户缺口,会直接影响 audit_runs 回填质量
|
||||
SELECT
|
||||
COUNT(*) AS documents_missing_tenant_code
|
||||
FROM leaudit_documents
|
||||
WHERE deleted_at IS NULL
|
||||
AND (
|
||||
tenant_code IS NULL
|
||||
OR BTRIM(tenant_code) = ''
|
||||
);
|
||||
@@ -0,0 +1,38 @@
|
||||
CREATE TABLE IF NOT EXISTS public.leaudit_page_quality_runs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
document_id BIGINT NOT NULL,
|
||||
document_file_id BIGINT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'queued',
|
||||
summary_status VARCHAR(32) NULL,
|
||||
total_pages INTEGER NOT NULL DEFAULT 0,
|
||||
review_page_count INTEGER NOT NULL DEFAULT 0,
|
||||
reject_page_count INTEGER NOT NULL DEFAULT 0,
|
||||
skip_reason VARCHAR(64) NULL,
|
||||
task_id VARCHAR(128) NULL,
|
||||
error_message TEXT NULL,
|
||||
started_at TIMESTAMP NULL,
|
||||
finished_at TIMESTAMP NULL,
|
||||
created_by BIGINT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMP NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.leaudit_page_quality_results (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
run_id BIGINT NOT NULL,
|
||||
document_id BIGINT NOT NULL,
|
||||
page_num INTEGER NOT NULL,
|
||||
quality_status VARCHAR(32) NOT NULL,
|
||||
quality_score NUMERIC(10, 4) NULL,
|
||||
reason_text TEXT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_page_quality_runs_document_id
|
||||
ON public.leaudit_page_quality_runs(document_id)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_page_quality_results_run_id
|
||||
ON public.leaudit_page_quality_results(run_id);
|
||||
@@ -0,0 +1,78 @@
|
||||
-- 入口模块租户关系表
|
||||
-- 目的:
|
||||
-- 1. 替代 leaudit_entry_modules.areas 的硬编码地区数组
|
||||
-- 2. 支持新增自定义租户后为入口模块直接分配 tenant_code
|
||||
-- 3. 保留旧 areas 字段作为兼容读写镜像,逐步退出
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS leaudit_entry_module_tenants (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
entry_module_id BIGINT NOT NULL,
|
||||
tenant_code VARCHAR(64) NOT NULL,
|
||||
tenant_name VARCHAR(128) NULL,
|
||||
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ NULL,
|
||||
UNIQUE (entry_module_id, tenant_code)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_entry_module_tenants_module
|
||||
ON leaudit_entry_module_tenants(entry_module_id, sort_order, id)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_entry_module_tenants_tenant
|
||||
ON leaudit_entry_module_tenants(tenant_code, is_enabled, sort_order)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
COMMENT ON TABLE leaudit_entry_module_tenants IS '入口模块与租户的多对多配置关系表';
|
||||
COMMENT ON COLUMN leaudit_entry_module_tenants.entry_module_id IS '入口模块ID';
|
||||
COMMENT ON COLUMN leaudit_entry_module_tenants.tenant_code IS '租户编码,引用 sys_tenants.tenant_code';
|
||||
COMMENT ON COLUMN leaudit_entry_module_tenants.tenant_name IS '配置快照名称,便于前端直接展示';
|
||||
|
||||
INSERT INTO leaudit_entry_module_tenants (
|
||||
entry_module_id, tenant_code, tenant_name, is_enabled, sort_order, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
em.id,
|
||||
alias_map.tenant_code,
|
||||
COALESCE(t.tenant_name, area_item->>'area') AS tenant_name,
|
||||
COALESCE((area_item->>'enabled')::boolean, TRUE) AS is_enabled,
|
||||
COALESCE((area_item->>'sort_order')::int, 0) AS sort_order,
|
||||
NOW(),
|
||||
NOW(),
|
||||
NULL
|
||||
FROM leaudit_entry_modules em
|
||||
CROSS JOIN LATERAL jsonb_array_elements(COALESCE(em.areas, '[]'::jsonb)) AS area_item
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT a.tenant_code
|
||||
FROM sys_tenant_aliases a
|
||||
WHERE a.alias_value = area_item->>'area'
|
||||
AND a.deleted_at IS NULL
|
||||
AND a.is_enabled = TRUE
|
||||
ORDER BY
|
||||
CASE a.alias_type
|
||||
WHEN 'DISPLAY' THEN 1
|
||||
WHEN 'LEGACY_AREA' THEN 2
|
||||
WHEN 'LEGACY_REGION' THEN 3
|
||||
ELSE 9
|
||||
END ASC,
|
||||
a.id ASC
|
||||
LIMIT 1
|
||||
) alias_map ON TRUE
|
||||
LEFT JOIN sys_tenants t
|
||||
ON t.tenant_code = alias_map.tenant_code
|
||||
AND t.deleted_at IS NULL
|
||||
WHERE em.deleted_at IS NULL
|
||||
AND alias_map.tenant_code IS NOT NULL
|
||||
ON CONFLICT (entry_module_id, tenant_code) DO UPDATE
|
||||
SET
|
||||
tenant_name = EXCLUDED.tenant_name,
|
||||
is_enabled = EXCLUDED.is_enabled,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = NOW(),
|
||||
deleted_at = NULL;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,198 @@
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================================
|
||||
-- Evaluation Points Tenant Cleanup
|
||||
-- 目标:
|
||||
-- 1. 为旧表 evaluation_points 补 tenant_code / tenant_name
|
||||
-- 2. 建立基础索引,支持评查点模块彻底切到 tenant_code 主链
|
||||
-- 3. 基于 sys_tenant_aliases / sys_tenants 做首轮历史回填
|
||||
-- 说明:
|
||||
-- - 当前真实运行链路仍使用旧表 evaluation_points
|
||||
-- - 本脚本只做“补列 + 建索引 + 回填”
|
||||
-- - 不在本阶段删除旧 area 字段
|
||||
-- - 不在本阶段强制 NOT NULL
|
||||
-- ============================================================================
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 1. 补字段
|
||||
-- --------------------------------------------------------------------------
|
||||
ALTER TABLE public.evaluation_points
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
|
||||
ADD COLUMN IF NOT EXISTS tenant_name VARCHAR(128);
|
||||
|
||||
COMMENT ON COLUMN public.evaluation_points.tenant_code IS '所属租户编码:评查点历史收尾阶段新增,后续替代 area 作为真实归属主字段';
|
||||
COMMENT ON COLUMN public.evaluation_points.tenant_name IS '所属租户名称:展示字段,和 tenant_code 配套回填';
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 2. 基础索引
|
||||
-- --------------------------------------------------------------------------
|
||||
CREATE INDEX IF NOT EXISTS idx_evaluation_points_tenant_code
|
||||
ON public.evaluation_points(tenant_code);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_evaluation_points_group_tenant_code
|
||||
ON public.evaluation_points(evaluation_point_groups_id, tenant_code);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_evaluation_points_group_pid_tenant_code
|
||||
ON public.evaluation_points(evaluation_point_groups_pid, tenant_code);
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 3. 公共 / 省级规范租户兜底
|
||||
-- --------------------------------------------------------------------------
|
||||
INSERT INTO public.sys_tenants (
|
||||
tenant_code, tenant_name, tenant_short_name, tenant_type,
|
||||
parent_tenant_code, is_enabled, is_public, display_order, ext,
|
||||
created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
'PUBLIC', '公共资源域', '公共', 'PUBLIC',
|
||||
NULL, TRUE, TRUE, 0, '{}'::jsonb,
|
||||
NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM public.sys_tenants WHERE tenant_code = 'PUBLIC'
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenants (
|
||||
tenant_code, tenant_name, tenant_short_name, tenant_type,
|
||||
parent_tenant_code, is_enabled, is_public, display_order, ext,
|
||||
created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
'PROVINCIAL', '省级统管域', '省级', 'GOV',
|
||||
NULL, TRUE, FALSE, 1, '{}'::jsonb,
|
||||
NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM public.sys_tenants WHERE tenant_code = 'PROVINCIAL'
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PUBLIC', 'DISPLAY', '公共', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PUBLIC'
|
||||
AND alias_value = '公共'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PUBLIC', 'LEGACY_REGION', 'default', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PUBLIC'
|
||||
AND alias_value = 'default'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PROVINCIAL', 'DISPLAY', '省级', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PROVINCIAL'
|
||||
AND alias_value = '省级'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PROVINCIAL', 'LEGACY_REGION', '省局', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PROVINCIAL'
|
||||
AND alias_value = '省局'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 4. 历史回填:优先按别名表映射
|
||||
-- --------------------------------------------------------------------------
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_points AS (
|
||||
SELECT
|
||||
ep.id,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(ep.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(ep.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(ep.tenant_name), ''),
|
||||
st.tenant_name,
|
||||
NULLIF(BTRIM(ep.area), ''),
|
||||
CASE
|
||||
WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN '公共资源域'
|
||||
WHEN LOWER(BTRIM(ep.area)) = 'default' THEN '公共资源域'
|
||||
WHEN BTRIM(ep.area) = '公共' THEN '公共资源域'
|
||||
WHEN BTRIM(ep.area) IN ('省级', '省局') THEN '省级统管域'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_name
|
||||
FROM public.evaluation_points ep
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(ep.area, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(ep.area, ''))) = tn.normalized_tenant_name
|
||||
LEFT JOIN public.sys_tenants st
|
||||
ON st.tenant_code = COALESCE(
|
||||
NULLIF(BTRIM(ep.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(ep.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(ep.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
)
|
||||
AND st.deleted_at IS NULL
|
||||
AND st.is_enabled = TRUE
|
||||
WHERE
|
||||
ep.tenant_code IS NULL
|
||||
OR BTRIM(ep.tenant_code) = ''
|
||||
OR ep.tenant_name IS NULL
|
||||
OR BTRIM(ep.tenant_name) = ''
|
||||
)
|
||||
UPDATE public.evaluation_points ep
|
||||
SET tenant_code = COALESCE(NULLIF(BTRIM(ep.tenant_code), ''), rp.resolved_tenant_code),
|
||||
tenant_name = COALESCE(NULLIF(BTRIM(ep.tenant_name), ''), rp.resolved_tenant_name)
|
||||
FROM resolved_points rp
|
||||
WHERE ep.id = rp.id
|
||||
AND (
|
||||
rp.resolved_tenant_code IS NOT NULL
|
||||
OR rp.resolved_tenant_name IS NOT NULL
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
@@ -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;
|
||||
@@ -0,0 +1,453 @@
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================================
|
||||
-- High Risk Tenant Code Phase 1
|
||||
-- 目标:
|
||||
-- 1. 为高风险核心业务表补 tenant_code / tenant 快照字段
|
||||
-- 2. 补基础索引,支持后续 service 改为 tenant_code 主链
|
||||
-- 3. 基于 sys_tenant_aliases / sys_tenants 做第一轮历史回填
|
||||
-- 说明:
|
||||
-- - 本脚本只做“补列 + 建索引 + 回填”
|
||||
-- - 不在本阶段强制 NOT NULL
|
||||
-- - 不在本阶段删除旧 region/area 字段
|
||||
-- ============================================================================
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 1. leaudit_documents
|
||||
-- --------------------------------------------------------------------------
|
||||
ALTER TABLE public.leaudit_documents
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64);
|
||||
|
||||
COMMENT ON COLUMN public.leaudit_documents.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 region 作为真实归属主字段';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_documents_tenant_code
|
||||
ON public.leaudit_documents(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_documents_type_tenant_name_latest
|
||||
ON public.leaudit_documents(type_id, tenant_code, normalized_name, is_latest_version)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 2. contract_templates
|
||||
-- --------------------------------------------------------------------------
|
||||
ALTER TABLE public.contract_templates
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64),
|
||||
ADD COLUMN IF NOT EXISTS tenant_name VARCHAR(128);
|
||||
|
||||
COMMENT ON COLUMN public.contract_templates.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 region 作为真实归属主字段';
|
||||
COMMENT ON COLUMN public.contract_templates.tenant_name IS '所属租户名称:展示字段,和 tenant_code 配套回填';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_contract_templates_tenant_code_active
|
||||
ON public.contract_templates(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_contract_templates_tenant_code_code_active
|
||||
ON public.contract_templates(tenant_code, template_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 3. usage_login_events
|
||||
-- --------------------------------------------------------------------------
|
||||
ALTER TABLE public.usage_login_events
|
||||
ADD COLUMN IF NOT EXISTS tenant_code_snapshot VARCHAR(64),
|
||||
ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(128);
|
||||
|
||||
COMMENT ON COLUMN public.usage_login_events.tenant_code_snapshot IS '登录时租户编码快照';
|
||||
COMMENT ON COLUMN public.usage_login_events.tenant_name_snapshot IS '登录时租户名称快照';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_login_events_tenant_code
|
||||
ON public.usage_login_events(tenant_code_snapshot, login_time DESC);
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 4. rag_dataset
|
||||
-- --------------------------------------------------------------------------
|
||||
ALTER TABLE public.rag_dataset
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64);
|
||||
|
||||
COMMENT ON COLUMN public.rag_dataset.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 area 作为真实归属主字段';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rag_dataset_tenant_code
|
||||
ON public.rag_dataset(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 5. rag_chat_app
|
||||
-- --------------------------------------------------------------------------
|
||||
ALTER TABLE public.rag_chat_app
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64);
|
||||
|
||||
COMMENT ON COLUMN public.rag_chat_app.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 area 作为真实归属主字段';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rag_chat_app_tenant_code
|
||||
ON public.rag_chat_app(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 6. 公共 / 省级规范租户兜底
|
||||
-- --------------------------------------------------------------------------
|
||||
INSERT INTO public.sys_tenants (
|
||||
tenant_code, tenant_name, tenant_short_name, tenant_type,
|
||||
parent_tenant_code, is_enabled, is_public, display_order, ext,
|
||||
created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
'PUBLIC', '公共资源域', '公共', 'PUBLIC',
|
||||
NULL, TRUE, TRUE, 0, '{}'::jsonb,
|
||||
NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM public.sys_tenants WHERE tenant_code = 'PUBLIC'
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenants (
|
||||
tenant_code, tenant_name, tenant_short_name, tenant_type,
|
||||
parent_tenant_code, is_enabled, is_public, display_order, ext,
|
||||
created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT
|
||||
'PROVINCIAL', '省级统管域', '省级', 'GOV',
|
||||
NULL, TRUE, FALSE, 1, '{}'::jsonb,
|
||||
NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM public.sys_tenants WHERE tenant_code = 'PROVINCIAL'
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PUBLIC', 'DISPLAY', '公共', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PUBLIC'
|
||||
AND alias_value = '公共'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PUBLIC', 'LEGACY_REGION', 'default', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PUBLIC'
|
||||
AND alias_value = 'default'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PROVINCIAL', 'DISPLAY', '省级', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PROVINCIAL'
|
||||
AND alias_value = '省级'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
INSERT INTO public.sys_tenant_aliases (
|
||||
tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at
|
||||
)
|
||||
SELECT 'PROVINCIAL', 'LEGACY_REGION', '省局', TRUE, NOW(), NOW(), NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE tenant_code = 'PROVINCIAL'
|
||||
AND alias_value = '省局'
|
||||
AND deleted_at IS NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- 7. 第一轮历史回填:优先按别名表映射
|
||||
-- --------------------------------------------------------------------------
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_documents AS (
|
||||
SELECT
|
||||
d.id,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(d.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN d.region IS NULL OR BTRIM(d.region) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(d.region)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(d.region) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(d.region) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code
|
||||
FROM public.leaudit_documents d
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(d.region, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(d.region, ''))) = tn.normalized_tenant_name
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '')
|
||||
)
|
||||
UPDATE public.leaudit_documents d
|
||||
SET tenant_code = rd.resolved_tenant_code
|
||||
FROM resolved_documents rd
|
||||
WHERE d.id = rd.id
|
||||
AND rd.resolved_tenant_code IS NOT NULL;
|
||||
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_templates AS (
|
||||
SELECT
|
||||
t.id,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(t.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN t.region IS NULL OR BTRIM(t.region) = '' THEN 'PROVINCIAL'
|
||||
WHEN LOWER(BTRIM(t.region)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(t.region) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(t.region) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(t.tenant_name), ''),
|
||||
NULLIF(BTRIM(t.region), ''),
|
||||
st.tenant_name,
|
||||
CASE
|
||||
WHEN t.region IS NULL OR BTRIM(t.region) = '' THEN '省级'
|
||||
WHEN LOWER(BTRIM(t.region)) = 'default' THEN '公共'
|
||||
WHEN BTRIM(t.region) = '公共' THEN '公共'
|
||||
WHEN BTRIM(t.region) IN ('省级', '省局') THEN '省级'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_name
|
||||
FROM public.contract_templates t
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(t.region, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(t.region, ''))) = tn.normalized_tenant_name
|
||||
LEFT JOIN public.sys_tenants st
|
||||
ON st.tenant_code = COALESCE(
|
||||
NULLIF(BTRIM(t.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN t.region IS NULL OR BTRIM(t.region) = '' THEN 'PROVINCIAL'
|
||||
WHEN LOWER(BTRIM(t.region)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(t.region) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(t.region) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
)
|
||||
AND st.deleted_at IS NULL
|
||||
AND st.is_enabled = TRUE
|
||||
WHERE t.deleted_at IS NULL
|
||||
AND (
|
||||
t.tenant_code IS NULL
|
||||
OR BTRIM(t.tenant_code) = ''
|
||||
OR t.tenant_name IS NULL
|
||||
OR BTRIM(t.tenant_name) = ''
|
||||
)
|
||||
)
|
||||
UPDATE public.contract_templates t
|
||||
SET tenant_code = COALESCE(t.tenant_code, rt.resolved_tenant_code),
|
||||
tenant_name = COALESCE(NULLIF(BTRIM(t.tenant_name), ''), rt.resolved_tenant_name)
|
||||
FROM resolved_templates rt
|
||||
WHERE t.id = rt.id
|
||||
AND (
|
||||
rt.resolved_tenant_code IS NOT NULL
|
||||
OR rt.resolved_tenant_name IS NOT NULL
|
||||
);
|
||||
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_rag_dataset AS (
|
||||
SELECT
|
||||
d.id,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(d.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN d.area IS NULL OR BTRIM(d.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(d.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(d.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(d.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code
|
||||
FROM public.rag_dataset d
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(d.area, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(d.area, ''))) = tn.normalized_tenant_name
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '')
|
||||
)
|
||||
UPDATE public.rag_dataset d
|
||||
SET tenant_code = rrd.resolved_tenant_code
|
||||
FROM resolved_rag_dataset rrd
|
||||
WHERE d.id = rrd.id
|
||||
AND rrd.resolved_tenant_code IS NOT NULL;
|
||||
|
||||
WITH alias_map AS (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
),
|
||||
tenant_name_map AS (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
),
|
||||
resolved_rag_chat_app AS (
|
||||
SELECT
|
||||
a.id,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(a.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN a.area IS NULL OR BTRIM(a.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(a.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(a.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(a.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code
|
||||
FROM public.rag_chat_app a
|
||||
LEFT JOIN alias_map am
|
||||
ON LOWER(BTRIM(COALESCE(a.area, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN tenant_name_map tn
|
||||
ON LOWER(BTRIM(COALESCE(a.area, ''))) = tn.normalized_tenant_name
|
||||
WHERE a.deleted_at IS NULL
|
||||
AND (a.tenant_code IS NULL OR BTRIM(a.tenant_code) = '')
|
||||
)
|
||||
UPDATE public.rag_chat_app a
|
||||
SET tenant_code = rca.resolved_tenant_code
|
||||
FROM resolved_rag_chat_app rca
|
||||
WHERE a.id = rca.id
|
||||
AND rca.resolved_tenant_code IS NOT NULL;
|
||||
|
||||
WITH user_tenant_map AS (
|
||||
SELECT
|
||||
u.id AS user_id,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(u.tenant_code), ''),
|
||||
am.tenant_code,
|
||||
tn.tenant_code,
|
||||
CASE
|
||||
WHEN u.area IS NULL OR BTRIM(u.area) = '' THEN 'PUBLIC'
|
||||
WHEN LOWER(BTRIM(u.area)) = 'default' THEN 'PUBLIC'
|
||||
WHEN BTRIM(u.area) = '公共' THEN 'PUBLIC'
|
||||
WHEN BTRIM(u.area) IN ('省级', '省局') THEN 'PROVINCIAL'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_code,
|
||||
COALESCE(
|
||||
NULLIF(BTRIM(u.tenant_name), ''),
|
||||
t.tenant_name,
|
||||
NULLIF(BTRIM(u.area), ''),
|
||||
CASE
|
||||
WHEN u.area IS NULL OR BTRIM(u.area) = '' THEN '公共资源域'
|
||||
ELSE NULL
|
||||
END
|
||||
) AS resolved_tenant_name
|
||||
FROM public.sso_users u
|
||||
LEFT JOIN public.sys_tenant_aliases sa
|
||||
ON LOWER(BTRIM(COALESCE(u.area, ''))) = LOWER(BTRIM(sa.alias_value))
|
||||
AND sa.deleted_at IS NULL
|
||||
AND sa.is_enabled = TRUE
|
||||
LEFT JOIN public.sys_tenants t
|
||||
ON t.tenant_code = COALESCE(NULLIF(BTRIM(u.tenant_code), ''), sa.tenant_code)
|
||||
AND t.deleted_at IS NULL
|
||||
AND t.is_enabled = TRUE
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT ON (LOWER(BTRIM(alias_value)))
|
||||
LOWER(BTRIM(alias_value)) AS normalized_alias_value,
|
||||
tenant_code
|
||||
FROM public.sys_tenant_aliases
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
ORDER BY LOWER(BTRIM(alias_value)), id ASC
|
||||
) am
|
||||
ON LOWER(BTRIM(COALESCE(u.area, ''))) = am.normalized_alias_value
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
LOWER(BTRIM(tenant_name)) AS normalized_tenant_name,
|
||||
tenant_code
|
||||
FROM public.sys_tenants
|
||||
WHERE deleted_at IS NULL
|
||||
AND is_enabled = TRUE
|
||||
) tn
|
||||
ON LOWER(BTRIM(COALESCE(u.area, ''))) = tn.normalized_tenant_name
|
||||
WHERE u.deleted_at IS NULL
|
||||
)
|
||||
UPDATE public.usage_login_events e
|
||||
SET tenant_code_snapshot = COALESCE(e.tenant_code_snapshot, utm.resolved_tenant_code),
|
||||
tenant_name_snapshot = COALESCE(e.tenant_name_snapshot, utm.resolved_tenant_name)
|
||||
FROM user_tenant_map utm
|
||||
WHERE e.deleted_at IS NULL
|
||||
AND e.user_id = utm.user_id
|
||||
AND (
|
||||
e.tenant_code_snapshot IS NULL
|
||||
OR BTRIM(e.tenant_code_snapshot) = ''
|
||||
OR e.tenant_name_snapshot IS NULL
|
||||
OR BTRIM(e.tenant_name_snapshot) = ''
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,163 @@
|
||||
-- 租户主数据底座
|
||||
-- 目的:
|
||||
-- 1. 为“地区 -> 租户”升级提供稳定主数据
|
||||
-- 2. 为后续入口模块、RAG、文档、模板等模块提供 tenant_code
|
||||
-- 3. 保持对现有 area / region / tenant_name 的兼容
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_tenants (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_code VARCHAR(64) NOT NULL UNIQUE,
|
||||
tenant_name VARCHAR(128) NOT NULL,
|
||||
tenant_short_name VARCHAR(64) NULL,
|
||||
tenant_type VARCHAR(32) NOT NULL,
|
||||
parent_tenant_code VARCHAR(64) NULL,
|
||||
display_order INT NOT NULL DEFAULT 0,
|
||||
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
is_builtin BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_public BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_host_entry_module BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
can_host_documents BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
can_host_rag BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
can_host_templates BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
ext JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_tenants_enabled_order
|
||||
ON sys_tenants(is_enabled, display_order, id)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_tenant_aliases (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_code VARCHAR(64) NOT NULL,
|
||||
alias_value VARCHAR(128) NOT NULL,
|
||||
alias_type VARCHAR(32) NOT NULL,
|
||||
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ NULL,
|
||||
UNIQUE (tenant_code, alias_value)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_tenant_aliases_lookup
|
||||
ON sys_tenant_aliases(alias_value, alias_type)
|
||||
WHERE deleted_at IS NULL AND is_enabled = TRUE;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_tenant_feature_flags (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_code VARCHAR(64) NOT NULL,
|
||||
feature_key VARCHAR(64) NOT NULL,
|
||||
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
ext JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ NULL,
|
||||
UNIQUE (tenant_code, feature_key)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_tenant_features_lookup
|
||||
ON sys_tenant_feature_flags(tenant_code, feature_key)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
ALTER TABLE sso_users
|
||||
ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64) NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sso_users_tenant_code
|
||||
ON sso_users(tenant_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
COMMENT ON TABLE sys_tenants IS '系统租户主数据表';
|
||||
COMMENT ON TABLE sys_tenant_aliases IS '租户历史别名与展示别名映射表';
|
||||
COMMENT ON TABLE sys_tenant_feature_flags IS '租户能力开关表';
|
||||
COMMENT ON COLUMN sso_users.tenant_code IS '用户主归属租户编码,优先于 area 作为租户边界';
|
||||
|
||||
INSERT INTO sys_tenants (
|
||||
tenant_code, tenant_name, tenant_short_name, tenant_type, parent_tenant_code,
|
||||
display_order, is_enabled, is_builtin, is_public,
|
||||
can_host_entry_module, can_host_documents, can_host_rag, can_host_templates, ext
|
||||
)
|
||||
VALUES
|
||||
('MZ', '梅州', '梅州', 'LOCAL', NULL, 10, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, '{}'::jsonb),
|
||||
('YF', '云浮', '云浮', 'LOCAL', NULL, 20, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, '{}'::jsonb),
|
||||
('JY', '揭阳', '揭阳', 'LOCAL', NULL, 30, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, '{}'::jsonb),
|
||||
('CZ', '潮州', '潮州', 'LOCAL', NULL, 40, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, '{}'::jsonb),
|
||||
('PROVINCIAL', '省局', '省局', 'HEADQUARTER', NULL, 90, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, '{}'::jsonb),
|
||||
('PUBLIC', '公共资源域', '公共', 'PUBLIC', NULL, 100, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, '{}'::jsonb)
|
||||
ON CONFLICT (tenant_code) DO UPDATE
|
||||
SET
|
||||
tenant_name = EXCLUDED.tenant_name,
|
||||
tenant_short_name = EXCLUDED.tenant_short_name,
|
||||
tenant_type = EXCLUDED.tenant_type,
|
||||
parent_tenant_code = EXCLUDED.parent_tenant_code,
|
||||
display_order = EXCLUDED.display_order,
|
||||
is_enabled = EXCLUDED.is_enabled,
|
||||
is_builtin = EXCLUDED.is_builtin,
|
||||
is_public = EXCLUDED.is_public,
|
||||
can_host_entry_module = EXCLUDED.can_host_entry_module,
|
||||
can_host_documents = EXCLUDED.can_host_documents,
|
||||
can_host_rag = EXCLUDED.can_host_rag,
|
||||
can_host_templates = EXCLUDED.can_host_templates,
|
||||
ext = EXCLUDED.ext,
|
||||
updated_at = NOW();
|
||||
|
||||
INSERT INTO sys_tenant_aliases (tenant_code, alias_value, alias_type, is_enabled)
|
||||
VALUES
|
||||
('MZ', '梅州', 'LEGACY_AREA', TRUE),
|
||||
('YF', '云浮', 'LEGACY_AREA', TRUE),
|
||||
('JY', '揭阳', 'LEGACY_AREA', TRUE),
|
||||
('CZ', '潮州', 'LEGACY_AREA', TRUE),
|
||||
('PROVINCIAL', '省局', 'DISPLAY', TRUE),
|
||||
('PUBLIC', '省级', 'LEGACY_REGION', TRUE),
|
||||
('PUBLIC', 'default', 'LEGACY_REGION', TRUE),
|
||||
('PUBLIC', '', 'LEGACY_REGION', TRUE)
|
||||
ON CONFLICT (tenant_code, alias_value) DO UPDATE
|
||||
SET
|
||||
alias_type = EXCLUDED.alias_type,
|
||||
is_enabled = EXCLUDED.is_enabled,
|
||||
updated_at = NOW();
|
||||
|
||||
INSERT INTO sys_tenant_feature_flags (tenant_code, feature_key, is_enabled)
|
||||
VALUES
|
||||
('MZ', 'home.entry_module', TRUE),
|
||||
('YF', 'home.entry_module', TRUE),
|
||||
('JY', 'home.entry_module', TRUE),
|
||||
('CZ', 'home.entry_module', TRUE),
|
||||
('PROVINCIAL', 'home.entry_module', TRUE),
|
||||
('PUBLIC', 'home.entry_module', TRUE),
|
||||
('MZ', 'rag.dataset', TRUE),
|
||||
('YF', 'rag.dataset', TRUE),
|
||||
('JY', 'rag.dataset', TRUE),
|
||||
('CZ', 'rag.dataset', TRUE),
|
||||
('PROVINCIAL', 'rag.dataset', TRUE),
|
||||
('PUBLIC', 'rag.dataset', TRUE),
|
||||
('MZ', 'documents.upload', TRUE),
|
||||
('YF', 'documents.upload', TRUE),
|
||||
('JY', 'documents.upload', TRUE),
|
||||
('CZ', 'documents.upload', TRUE),
|
||||
('PROVINCIAL', 'documents.upload', TRUE),
|
||||
('PUBLIC', 'documents.upload', TRUE)
|
||||
ON CONFLICT (tenant_code, feature_key) DO UPDATE
|
||||
SET
|
||||
is_enabled = EXCLUDED.is_enabled,
|
||||
updated_at = NOW();
|
||||
|
||||
UPDATE sso_users u
|
||||
SET tenant_code = mapped.tenant_code
|
||||
FROM (
|
||||
SELECT DISTINCT ON (a.alias_value)
|
||||
a.alias_value,
|
||||
a.tenant_code
|
||||
FROM sys_tenant_aliases a
|
||||
WHERE a.deleted_at IS NULL
|
||||
AND a.is_enabled = TRUE
|
||||
ORDER BY a.alias_value, a.id ASC
|
||||
) mapped
|
||||
WHERE u.deleted_at IS NULL
|
||||
AND COALESCE(BTRIM(u.tenant_code), '') = ''
|
||||
AND COALESCE(BTRIM(u.area), '') = mapped.alias_value;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1 @@
|
||||
-- 预留:页级图片质量模块权限初始化脚本
|
||||
@@ -0,0 +1 @@
|
||||
-- 预留:页级图片质量模块路由初始化脚本
|
||||
@@ -344,9 +344,13 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('admin', 'rules:version_list:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:content:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:validate:execute', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:version_create:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:publish:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:rollback:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:binding_list:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:binding_create:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:binding_update:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:binding_delete:delete', 'GRANT', 'DEPT'),
|
||||
('admin', 'cross_review:task:create', 'GRANT', 'DEPT'),
|
||||
('admin', 'cross_review:task:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'cross_review:progress:view', 'GRANT', 'DEPT'),
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
-- ============================================================================
|
||||
-- Rule Domain Tenant Phase 1 Verify
|
||||
-- 目标:
|
||||
-- 1. 验证字段与索引已成功补齐
|
||||
-- 2. 验证历史资产已具备基础 tenant_code / scope_type
|
||||
-- 3. 验证运行结果链路具备租户快照
|
||||
-- ============================================================================
|
||||
|
||||
-- 1. 字段检查
|
||||
SELECT
|
||||
table_name,
|
||||
column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = current_schema()
|
||||
AND (
|
||||
(table_name = 'leaudit_rule_sets' AND column_name IN ('tenant_code', 'scope_type', 'source_rule_set_id', 'tenant_name_snapshot'))
|
||||
OR (table_name = 'leaudit_rule_versions' AND column_name IN ('tenant_code_snapshot', 'scope_type_snapshot', 'source_version_id'))
|
||||
OR (table_name = 'leaudit_rule_group_bindings' AND column_name IN ('tenant_code', 'scope_type', 'tenant_name_snapshot'))
|
||||
OR (table_name = 'leaudit_rule_type_bindings' AND column_name IN ('tenant_code', 'scope_type'))
|
||||
OR (table_name = 'leaudit_audit_runs' AND column_name IN ('tenant_code', 'tenant_name_snapshot', 'scope_type_snapshot', 'group_id_snapshot', 'rule_binding_id_snapshot'))
|
||||
OR (table_name = 'leaudit_rule_results' AND column_name IN ('tenant_code', 'tenant_name_snapshot'))
|
||||
OR (table_name = 'leaudit_run_errors' AND column_name IN ('tenant_code', 'tenant_name_snapshot'))
|
||||
OR (table_name = 'leaudit_run_metrics' AND column_name IN ('tenant_code'))
|
||||
)
|
||||
ORDER BY table_name, column_name;
|
||||
|
||||
-- 2. 历史规则资产 tenant_code / scope_type 覆盖率
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS rule_sets_missing_tenant_code,
|
||||
COUNT(*) FILTER (WHERE scope_type IS NULL OR BTRIM(scope_type) = '') AS rule_sets_missing_scope_type
|
||||
FROM leaudit_rule_sets
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS rule_group_bindings_missing_tenant_code,
|
||||
COUNT(*) FILTER (WHERE scope_type IS NULL OR BTRIM(scope_type) = '') AS rule_group_bindings_missing_scope_type
|
||||
FROM leaudit_rule_group_bindings
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- 3. 运行与结果快照覆盖率
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS audit_runs_missing_tenant_code,
|
||||
COUNT(*) FILTER (WHERE scope_type_snapshot IS NULL OR BTRIM(scope_type_snapshot) = '') AS audit_runs_missing_scope_type
|
||||
FROM leaudit_audit_runs;
|
||||
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS rule_results_missing_tenant_code
|
||||
FROM leaudit_rule_results;
|
||||
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS run_errors_missing_tenant_code
|
||||
FROM leaudit_run_errors;
|
||||
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS run_metrics_missing_tenant_code
|
||||
FROM leaudit_run_metrics;
|
||||
|
||||
-- 4. 作用域分布,确认默认回填结果
|
||||
SELECT scope_type, COUNT(*) AS total
|
||||
FROM leaudit_rule_sets
|
||||
WHERE deleted_at IS NULL
|
||||
GROUP BY scope_type
|
||||
ORDER BY scope_type;
|
||||
|
||||
SELECT scope_type, COUNT(*) AS total
|
||||
FROM leaudit_rule_group_bindings
|
||||
WHERE deleted_at IS NULL
|
||||
GROUP BY scope_type
|
||||
ORDER BY scope_type;
|
||||
Reference in New Issue
Block a user