SET NAMES utf8mb4; ALTER TABLE user_privacy_settings ADD COLUMN invisible_visit TINYINT(1) NOT NULL DEFAULT 0 AFTER allow_profile_visit_record; ALTER TABLE membership_plans ADD COLUMN daily_like_limit INT UNSIGNED NOT NULL DEFAULT 20 AFTER daily_active_chat_limit, ADD COLUMN can_view_visitors TINYINT(1) NOT NULL DEFAULT 0 AFTER daily_like_limit, ADD COLUMN can_invisible_visit TINYINT(1) NOT NULL DEFAULT 0 AFTER can_view_visitors, ADD COLUMN recommendation_weight INT UNSIGNED NOT NULL DEFAULT 0 AFTER can_invisible_visit; UPDATE membership_plans SET daily_like_limit=CASE WHEN level>=2 THEN 0 WHEN level=1 THEN 100 ELSE 20 END, can_view_visitors=IF(level>=1,1,0), can_invisible_visit=IF(level>=1,1,0), recommendation_weight=CASE WHEN level>=2 THEN 30 WHEN level=1 THEN 15 ELSE 0 END; ALTER TABLE user_verifications DROP PRIMARY KEY, ADD PRIMARY KEY (user_id, verification_type); CREATE TABLE IF NOT EXISTS user_daily_like_usage ( user_id BIGINT UNSIGNED NOT NULL, usage_date DATE NOT NULL, used_count INT UNSIGNED NOT NULL DEFAULT 0, updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (user_id, usage_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_daily_like_targets ( user_id BIGINT UNSIGNED NOT NULL, target_type VARCHAR(20) NOT NULL, target_id BIGINT UNSIGNED NOT NULL, usage_date DATE NOT NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (user_id, target_type, target_id, usage_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_notification_settings ( user_id BIGINT UNSIGNED NOT NULL, im_enabled TINYINT(1) NOT NULL DEFAULT 1, interaction_enabled TINYINT(1) NOT NULL DEFAULT 1, system_enabled TINYINT(1) NOT NULL DEFAULT 1, sound_enabled TINYINT(1) NOT NULL DEFAULT 1, vibration_enabled TINYINT(1) NOT NULL DEFAULT 1, quiet_start VARCHAR(5) NOT NULL DEFAULT '', quiet_end VARCHAR(5) NOT NULL DEFAULT '', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_push_tokens ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, device_id VARCHAR(100) NOT NULL, provider VARCHAR(30) NOT NULL, push_token VARCHAR(500) NOT NULL, platform VARCHAR(20) NOT NULL DEFAULT '', app_version VARCHAR(30) NOT NULL DEFAULT '', status TINYINT UNSIGNED NOT NULL DEFAULT 1, last_active_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_push_device_provider (user_id, device_id, provider), KEY idx_push_user_status (user_id, status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_feedback ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, category VARCHAR(30) NOT NULL, content VARCHAR(2000) NOT NULL, contact VARCHAR(100) NOT NULL DEFAULT '', evidence_json JSON NULL, status VARCHAR(20) NOT NULL DEFAULT 'PENDING', reply_content VARCHAR(2000) NOT NULL DEFAULT '', handled_by BIGINT UNSIGNED NULL, handled_at DATETIME(3) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), KEY idx_feedback_user_created (user_id, created_at), KEY idx_feedback_status_created (status, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_account_closures ( user_id BIGINT UNSIGNED NOT NULL, reason VARCHAR(500) NOT NULL DEFAULT '', status VARCHAR(20) NOT NULL DEFAULT 'PENDING', requested_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), execute_after DATETIME(3) NOT NULL, cancelled_at DATETIME(3) NULL, completed_at DATETIME(3) NULL, updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (user_id), KEY idx_closure_status_execute (status, execute_after) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_consents ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, agreement_type VARCHAR(30) NOT NULL, agreement_version VARCHAR(30) NOT NULL, accepted_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), ip VARCHAR(45) NOT NULL DEFAULT '', device_id VARCHAR(100) NOT NULL DEFAULT '', PRIMARY KEY (id), UNIQUE KEY uk_user_consent_version (user_id, agreement_type, agreement_version) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ALTER TABLE orders ADD COLUMN refund_reason VARCHAR(500) NOT NULL DEFAULT '' AFTER payment_notified_at, ADD COLUMN refund_requested_at DATETIME(3) NULL AFTER refund_reason; INSERT INTO user_notification_settings(user_id) SELECT id FROM users ON DUPLICATE KEY UPDATE user_id=VALUES(user_id); INSERT INTO system_configs (config_key,config_value,value_type,description) VALUES ('membership.free_daily_like_limit','20','number','普通用户每日点赞次数'), ('account.cancellation_cooling_days','7','number','账号注销冷静期天数'), ('legal.user_agreement_version','1.0','string','用户协议版本'), ('legal.privacy_policy_version','1.0','string','隐私政策版本'), ('legal.operator_name','','string','平台运营主体全称(上线前必填)'), ('legal.contact','','string','隐私与客服联系方式(上线前必填)'), ('legal.effective_date','','string','协议生效日期,格式 YYYY-MM-DD'), ('legal.user_agreement_url','','string','完整用户协议 HTTPS 地址'), ('legal.privacy_policy_url','','string','完整隐私政策 HTTPS 地址'), ('app.maintenance.enabled','false','boolean','客户端维护模式'), ('app.maintenance.message','系统维护中,请稍后再试','string','客户端维护提示'), ('app.features.nearby','true','boolean','附近功能开关'), ('app.features.feed','true','boolean','动态功能开关'), ('app.features.membership','true','boolean','会员功能开关'), ('app.features.im','true','boolean','即时通讯功能开关'), ('app.min_version.android','1.0.0','string','Android 最低版本'), ('app.min_version.ios','1.0.0','string','iOS 最低版本'), ('app.min_version.h5','1.0.0','string','H5 最低版本') ON DUPLICATE KEY UPDATE description=VALUES(description),value_type=VALUES(value_type);