Files
im_manager/docs/admin-adfahi-research/sql/Admin-Server改造.sql
T

351 lines
17 KiB
SQL

-- Admin Server schema changes for the GedaDa management-console adaptation.
-- Target: MySQL 8.0+, control database `hotgo`.
-- Scope: control-plane configuration only. Do not create tenant business data here.
-- Review before execution. DDL statements auto-commit in MySQL.
SET NAMES utf8mb4;
USE `hotgo`;
-- ============================================================
-- 1. User policy groups.
-- status: 1=enabled, 2=disabled.
-- policy_json action values: allow, deny, challenge, audit_only.
-- Friend entry values: search, profile_card, group_member, qrcode,
-- invite_auto_add, recommendation.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_user_policy_groups` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global default',
`group_code` varchar(64) NOT NULL COMMENT 'Stable policy group code',
`group_name` varchar(128) NOT NULL COMMENT 'Policy group name',
`priority` int NOT NULL DEFAULT 0 COMMENT 'Higher value has higher priority',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`policy_json` json NOT NULL COMMENT 'Login, friend, message, group and file policies',
`ip_whitelist` json DEFAULT NULL COMMENT 'IPv4/IPv6 or CIDR list',
`ip_blacklist` json DEFAULT NULL COMMENT 'IPv4/IPv6 or CIDR list',
`version` int unsigned NOT NULL DEFAULT 1 COMMENT 'Optimistic-lock/config version',
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_user_policy_group_code` (`tenant_id`, `group_code`),
KEY `idx_im_user_policy_group_list` (`tenant_id`, `status`, `priority`, `id`),
KEY `idx_im_user_policy_group_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM user policy groups';
CREATE TABLE IF NOT EXISTS `im_user_policy_group_members` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0,
`group_id` bigint NOT NULL,
`user_id` bigint NOT NULL COMMENT 'User ID in the tenant database',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`valid_from` datetime(3) DEFAULT NULL,
`valid_until` datetime(3) DEFAULT NULL,
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_user_policy_group_member` (`group_id`, `user_id`),
KEY `idx_im_user_policy_member_user` (`tenant_id`, `user_id`, `status`),
KEY `idx_im_user_policy_member_validity` (`status`, `valid_from`, `valid_until`),
KEY `idx_im_user_policy_member_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM user-to-policy-group assignments';
-- ============================================================
-- 2. Sensitive word dictionary.
-- match_type: exact, contains, regex, pinyin.
-- action: replace, block, audit_only, manual_review.
-- risk_level: low, medium, high.
-- scene_json values include private_message, group_message, user_profile,
-- group_profile, feedback, report.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_sensitive_word_groups` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global dictionary',
`group_code` varchar(64) NOT NULL,
`group_name` varchar(128) NOT NULL,
`priority` int NOT NULL DEFAULT 0,
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_sensitive_word_group_code` (`tenant_id`, `group_code`),
KEY `idx_im_sensitive_word_group_list` (`tenant_id`, `status`, `priority`, `id`),
KEY `idx_im_sensitive_word_group_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM sensitive word groups';
CREATE TABLE IF NOT EXISTS `im_sensitive_words` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global dictionary',
`group_id` bigint NOT NULL,
`word` varchar(255) NOT NULL,
`word_hash` char(64) NOT NULL COMMENT 'SHA-256 of normalized word',
`match_type` varchar(24) NOT NULL DEFAULT 'contains',
`scene_json` json NOT NULL COMMENT 'Enabled scenes',
`action` varchar(24) NOT NULL DEFAULT 'block',
`replacement` varchar(255) NOT NULL DEFAULT '',
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
`priority` int NOT NULL DEFAULT 0,
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_sensitive_word_normalized` (`tenant_id`, `group_id`, `word_hash`),
KEY `idx_im_sensitive_word_list` (`tenant_id`, `status`, `risk_level`, `id`),
KEY `idx_im_sensitive_word_group` (`group_id`, `status`, `priority`),
KEY `idx_im_sensitive_word_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM sensitive words';
-- ============================================================
-- 3. Versioned security policy.
-- publish_status: draft, published, archived, failed.
-- The latest published row is the source of truth. The summary switches in
-- im_tenant_config are updated in the same application transaction on publish.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_security_policy` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global fallback policy',
`policy_version` int unsigned NOT NULL,
`policy_name` varchar(128) NOT NULL DEFAULT '',
`publish_status` varchar(16) NOT NULL DEFAULT 'draft',
`password_policy` json DEFAULT NULL,
`login_rate_limit` json DEFAULT NULL,
`sensitive_word_policy` json DEFAULT NULL,
`file_review_policy` json DEFAULT NULL,
`realname_policy` json DEFAULT NULL,
`risk_challenge_policy` json DEFAULT NULL,
`global_friend_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Backend master switch for every add-friend entry',
`friend_disabled_policy` json DEFAULT NULL COMMENT 'Profile masking, QR and group-member restrictions',
`message_curfew_enabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Backend master switch for message curfew',
`remark` varchar(500) NOT NULL DEFAULT '',
`published_at` datetime(3) DEFAULT NULL,
`published_by` bigint DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_security_policy_version` (`tenant_id`, `policy_version`),
KEY `idx_im_security_policy_publish` (`tenant_id`, `publish_status`, `published_at`),
KEY `idx_im_security_policy_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Versioned IM security policies';
CREATE TABLE IF NOT EXISTS `im_message_curfew_rules` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0,
`policy_id` bigint NOT NULL,
`rule_code` varchar(64) NOT NULL,
`rule_name` varchar(128) NOT NULL,
`date_type` varchar(16) NOT NULL DEFAULT 'daily' COMMENT 'daily, weekday, weekend, custom',
`custom_dates` json DEFAULT NULL COMMENT 'YYYY-MM-DD values for custom date type',
`weekdays` json DEFAULT NULL COMMENT 'ISO weekdays 1 through 7',
`timezone` varchar(64) NOT NULL DEFAULT 'Asia/Shanghai',
`start_time` time NOT NULL,
`end_time` time NOT NULL COMMENT 'Less than start_time means crossing midnight',
`scope` varchar(24) NOT NULL DEFAULT 'private_message' COMMENT 'private_message or group_message',
`whitelist_user_ids` json DEFAULT NULL,
`whitelist_group_ids` json DEFAULT NULL,
`message` varchar(255) NOT NULL DEFAULT '当前时段暂不能发送消息',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`sort` int NOT NULL DEFAULT 0,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_message_curfew_rule` (`policy_id`, `rule_code`),
KEY `idx_im_message_curfew_policy` (`tenant_id`, `policy_id`, `status`, `sort`),
KEY `idx_im_message_curfew_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Message curfew rules';
CREATE TABLE IF NOT EXISTS `im_security_ip_rules` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0,
`rule_type` varchar(16) NOT NULL COMMENT 'whitelist or blacklist',
`ip_cidr` varchar(64) NOT NULL COMMENT 'IPv4, IPv6 or CIDR',
`action` varchar(24) NOT NULL DEFAULT 'block' COMMENT 'allow, challenge, block, audit_only',
`scene_json` json NOT NULL COMMENT 'login, register, message, upload and other scenes',
`risk_level` varchar(16) NOT NULL DEFAULT 'high',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`expires_at` datetime(3) DEFAULT NULL,
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_security_ip_rule` (`tenant_id`, `rule_type`, `ip_cidr`),
KEY `idx_im_security_ip_rule_list` (`tenant_id`, `status`, `rule_type`, `id`),
KEY `idx_im_security_ip_rule_expiry` (`status`, `expires_at`),
KEY `idx_im_security_ip_rule_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM IP whitelist and blacklist rules';
-- ============================================================
-- 4. Lightweight published-policy summary in im_tenant_config.
-- These columns are read optimizations, not the policy source of truth.
-- The conditional ALTER blocks are safe to rerun on MySQL 8.0.
-- ============================================================
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'default_policy_group_id') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `default_policy_group_id` BIGINT DEFAULT NULL COMMENT ''Default user policy group'' AFTER `max_group_members`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'security_policy_version') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `security_policy_version` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''Published security policy version'' AFTER `default_policy_group_id`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'global_friend_enabled') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `global_friend_enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''Published global friend switch'' AFTER `security_policy_version`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'message_curfew_enabled') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `message_curfew_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''Published message curfew switch'' AFTER `global_friend_enabled`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- ============================================================
-- 5. Invitation-code compatibility for the 6-digit target format.
-- Existing 5-letter codes remain stored and valid during the application
-- rollout. New code generation must switch to exactly six ASCII digits, while
-- Admin and IM Server temporarily accept both legacy 5-letter and new 6-digit
-- values. max_uses=0 preserves the current unlimited-use behavior.
-- ============================================================
SET @im_sql = IF(
(SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_codes'
AND COLUMN_NAME = 'code') = 5,
'ALTER TABLE `im_registration_invite_codes` MODIFY COLUMN `code` CHAR(6) CHARACTER SET ascii COLLATE ascii_bin NOT NULL',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_codes'
AND COLUMN_NAME = 'max_uses') = 0,
'ALTER TABLE `im_registration_invite_codes` ADD COLUMN `max_uses` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''0 means unlimited'' AFTER `expires_at`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_batches'
AND COLUMN_NAME = 'max_uses_per_code') = 0,
'ALTER TABLE `im_registration_invite_batches` ADD COLUMN `max_uses_per_code` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''0 means unlimited'' AFTER `quantity`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- ============================================================
-- 6. Safe global fallback policy.
-- Tenant-specific published policies override tenant_id=0.
-- This keeps existing behavior permissive until an administrator publishes
-- the first tenant policy.
-- ============================================================
INSERT INTO `im_security_policy` (
`tenant_id`, `policy_version`, `policy_name`, `publish_status`,
`global_friend_enabled`, `friend_disabled_policy`,
`message_curfew_enabled`, `remark`, `published_at`, `published_by`,
`created_by`, `updated_by`
)
SELECT
0, 1, '全局默认安全策略', 'published',
1,
JSON_OBJECT(
'hide_profile', TRUE,
'block_qrcode', TRUE,
'block_group_member_entry', TRUE,
'blocked_entries', JSON_ARRAY(
'search', 'profile_card', 'group_member',
'qrcode', 'invite_auto_add', 'recommendation'
),
'message', '当前时段暂不允许添加好友'
),
0, '系统初始化:保持原有好友和消息行为', CURRENT_TIMESTAMP(3), 0, 0, 0
WHERE NOT EXISTS (
SELECT 1 FROM `im_security_policy`
WHERE `tenant_id` = 0 AND `publish_status` = 'published' AND `deleted_at` IS NULL
);
UPDATE `im_security_policy`
SET `friend_disabled_policy` = JSON_SET(
`friend_disabled_policy`,
'$.blocked_entries',
JSON_ARRAY('search', 'profile_card', 'group_member', 'qrcode', 'invite_auto_add', 'recommendation')
)
WHERE `tenant_id` = 0
AND `publish_status` = 'published'
AND `deleted_at` IS NULL
AND JSON_CONTAINS_PATH(`friend_disabled_policy`, 'one', '$.blocked_entries') = 0;
-- Post-deployment checks (read-only):
-- SELECT tenant_id, group_code, status, priority FROM im_user_policy_groups;
-- SELECT tenant_id, policy_version, publish_status,
-- global_friend_enabled, message_curfew_enabled
-- FROM im_security_policy ORDER BY tenant_id, policy_version DESC;
-- SELECT tenant_id, policy_id, rule_code, date_type, start_time, end_time, scope
-- FROM im_message_curfew_rules WHERE deleted_at IS NULL;