Files
leaudit-platform-backend/scripts/创建sql/verify_entry_module_menu_profile.sql
T
2026-05-25 09:50:01 +08:00

210 lines
6.3 KiB
SQL

-- 入口模块菜单模板、多租户可见性、文档归属巡检脚本
-- 用途:
-- 1. 检查 entry_module_menu_profile_migration.sql 是否补齐字段、索引、默认值。
-- 2. 检查入口模块 features/menu_profile 是否存在非法值或空配置。
-- 3. 检查文档 entry_module_id 回填情况和二级分组重复风险。
-- 4. 本脚本只查询,不修改数据。
--
-- 推荐执行方式:
-- psql "$DATABASE_URL" -f scripts/创建sql/verify_entry_module_menu_profile.sql
-- =========================================================
-- 1. 必要字段检查
-- =========================================================
SELECT
table_name,
column_name,
data_type,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_schema = current_schema()
AND (
(table_name = 'leaudit_entry_modules' AND column_name IN ('menu_profile', 'features'))
OR (table_name = 'leaudit_documents' AND column_name = 'entry_module_id')
)
ORDER BY table_name, column_name;
-- =========================================================
-- 2. 必要索引检查
-- =========================================================
SELECT
schemaname,
tablename,
indexname,
indexdef
FROM pg_indexes
WHERE schemaname = current_schema()
AND indexname IN (
'idx_leaudit_entry_modules_menu_profile',
'idx_leaudit_documents_entry_module_id',
'uq_leaudit_ep_groups_parent_doc_type_active'
)
ORDER BY indexname;
-- =========================================================
-- 3. 入口模块菜单配置总览
-- =========================================================
SELECT
em.id,
em.name,
em.path,
em.menu_profile,
em.features,
em.is_enabled,
COALESCE(
STRING_AGG(emt.tenant_code, ', ' ORDER BY emt.tenant_code)
FILTER (WHERE emt.is_enabled IS TRUE),
''
) AS enabled_tenants
FROM leaudit_entry_modules em
LEFT JOIN leaudit_entry_module_tenants emt
ON emt.entry_module_id = em.id
WHERE em.deleted_at IS NULL
GROUP BY em.id, em.name, em.path, em.menu_profile, em.features, em.is_enabled
ORDER BY em.sort_order, em.id;
-- =========================================================
-- 4. 非法 menu_profile 检查:结果应为空
-- =========================================================
SELECT
id,
name,
path,
menu_profile
FROM leaudit_entry_modules
WHERE deleted_at IS NULL
AND menu_profile NOT IN ('document_review', 'contract', 'govdoc', 'cross_checking', 'custom')
ORDER BY id;
-- =========================================================
-- 5. 空 features 检查:结果应为空或只包含刻意关闭菜单的入口
-- =========================================================
SELECT
id,
name,
path,
menu_profile,
features
FROM leaudit_entry_modules
WHERE deleted_at IS NULL
AND (
features IS NULL
OR jsonb_typeof(features) <> 'array'
OR jsonb_array_length(features) = 0
)
ORDER BY id;
-- =========================================================
-- 6. 非法 feature 编码检查:结果应为空
-- =========================================================
SELECT
em.id,
em.name,
em.menu_profile,
invalid_feature.feature
FROM leaudit_entry_modules em
CROSS JOIN LATERAL jsonb_array_elements_text(em.features) AS invalid_feature(feature)
WHERE em.deleted_at IS NULL
AND invalid_feature.feature NOT IN (
'home',
'documents',
'upload',
'rules',
'rule_groups',
'contract_template_search',
'contract_template_list',
'govdoc_audits',
'govdoc_upload',
'cross_checking',
'cross_checking_upload',
'cross_checking_list',
'usage_stats'
)
ORDER BY em.id, invalid_feature.feature;
-- =========================================================
-- 7. 文档归属缺失检查
-- =========================================================
SELECT
COUNT(*) AS documents_without_entry_module
FROM leaudit_documents
WHERE deleted_at IS NULL
AND entry_module_id IS NULL;
SELECT
d.id,
d.normalized_name AS document_name,
d.type_id,
dt.name AS document_type_name,
d.group_id,
g.name AS group_name,
d.tenant_code,
d.created_at
FROM leaudit_documents d
LEFT JOIN leaudit_document_types dt
ON dt.id = d.type_id
LEFT JOIN leaudit_evaluation_point_groups g
ON g.id = d.group_id
WHERE d.deleted_at IS NULL
AND d.entry_module_id IS NULL
ORDER BY d.created_at DESC NULLS LAST, d.id DESC
LIMIT 50;
-- =========================================================
-- 8. 文档 entry_module_id 与分组/文档类型推导不一致检查
-- =========================================================
SELECT
d.id,
d.normalized_name AS document_name,
d.entry_module_id AS document_entry_module_id,
COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id) AS resolved_entry_module_id,
d.type_id,
d.group_id,
d.tenant_code
FROM leaudit_documents d
LEFT JOIN leaudit_document_types dt
ON dt.id = d.type_id
LEFT JOIN leaudit_evaluation_point_groups g
ON g.id = d.group_id
LEFT JOIN leaudit_evaluation_point_groups parent
ON parent.id = g.pid
WHERE d.deleted_at IS NULL
AND d.entry_module_id IS NOT NULL
AND COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id) IS NOT NULL
AND d.entry_module_id <> COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id)
ORDER BY d.id DESC
LIMIT 100;
-- =========================================================
-- 9. 重复二级分组检查:结果应为空
-- =========================================================
SELECT
pid,
document_type_id,
COUNT(*) AS duplicated_count,
STRING_AGG(id::text || ':' || name, ' / ' ORDER BY id) AS groups
FROM leaudit_evaluation_point_groups
WHERE deleted_at IS NULL
AND COALESCE(pid, 0) <> 0
AND document_type_id IS NOT NULL
GROUP BY pid, document_type_id
HAVING COUNT(*) > 1
ORDER BY duplicated_count DESC, pid, document_type_id;
-- =========================================================
-- 10. 一级分组缺入口模块检查:兼容期允许存在,但新链路应逐步清零
-- =========================================================
SELECT
id,
code,
name,
document_type_id,
sort_order,
is_enabled
FROM leaudit_evaluation_point_groups
WHERE deleted_at IS NULL
AND COALESCE(pid, 0) = 0
AND entry_module_id IS NULL
ORDER BY sort_order, id;