更新
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
public_id VARCHAR(20) NOT NULL,
|
||||
country_code VARCHAR(8) NOT NULL DEFAULT '+86',
|
||||
phone_hash BINARY(32) NULL,
|
||||
phone_cipher VARBINARY(255) NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
risk_level TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
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),
|
||||
deleted_at DATETIME(3) NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_users_public_id (public_id),
|
||||
UNIQUE KEY uk_users_phone_hash (phone_hash),
|
||||
KEY idx_users_status_created (status, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_profiles (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
nickname VARCHAR(50) NOT NULL,
|
||||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
cover_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
gender TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
birthday DATE NULL,
|
||||
height_cm SMALLINT UNSIGNED NULL,
|
||||
city_code VARCHAR(20) NOT NULL DEFAULT '',
|
||||
city_name VARCHAR(50) NOT NULL DEFAULT '',
|
||||
occupation VARCHAR(100) NOT NULL DEFAULT '',
|
||||
education TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
relationship_status TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
bio VARCHAR(500) NOT NULL DEFAULT '',
|
||||
profile_score SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
is_vip TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
vip_level TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
last_active_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 (user_id),
|
||||
KEY idx_profiles_city_active (city_code, last_active_at),
|
||||
CONSTRAINT fk_profiles_user FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_privacy_settings (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
nearby_visible TINYINT(1) NOT NULL DEFAULT 1,
|
||||
distance_visible TINYINT(1) NOT NULL DEFAULT 1,
|
||||
online_visible TINYINT(1) NOT NULL DEFAULT 1,
|
||||
last_active_visible TINYINT(1) NOT NULL DEFAULT 1,
|
||||
allow_stranger_message TINYINT(1) NOT NULL DEFAULT 1,
|
||||
allow_profile_visit_record TINYINT(1) NOT NULL DEFAULT 1,
|
||||
allow_search TINYINT(1) NOT NULL DEFAULT 1,
|
||||
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),
|
||||
CONSTRAINT fk_privacy_user FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_devices (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
device_id VARCHAR(100) NOT NULL,
|
||||
platform VARCHAR(20) NOT NULL,
|
||||
device_model VARCHAR(100) NOT NULL DEFAULT '',
|
||||
os_version VARCHAR(50) NOT NULL DEFAULT '',
|
||||
app_version VARCHAR(30) NOT NULL DEFAULT '',
|
||||
push_provider VARCHAR(30) NOT NULL DEFAULT '',
|
||||
push_token VARCHAR(255) NOT NULL DEFAULT '',
|
||||
last_ip VARCHAR(45) NOT NULL DEFAULT '',
|
||||
last_active_at DATETIME(3) NULL,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_device_user_device (user_id, device_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
device_id VARCHAR(100) NOT NULL,
|
||||
refresh_token_hash BINARY(32) NOT NULL,
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
last_active_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
revoked_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_sessions_user (user_id, revoked_at),
|
||||
UNIQUE KEY uk_sessions_refresh (refresh_token_hash)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
category VARCHAR(30) NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
icon VARCHAR(100) NOT NULL DEFAULT '',
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_tags_category_name (category, name)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_tags (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
tag_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (user_id, tag_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_users (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
username VARCHAR(50) NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
real_name VARCHAR(50) NOT NULL DEFAULT '',
|
||||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
last_login_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_admin_username (username)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
CREATE TABLE IF NOT EXISTS user_follows (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
target_user_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_follow_pair (user_id, target_user_id),
|
||||
KEY idx_follow_target (target_user_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_likes (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
target_user_id BIGINT UNSIGNED NOT NULL,
|
||||
source VARCHAR(30) NOT NULL DEFAULT 'discover',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_like_pair (user_id, target_user_id),
|
||||
KEY idx_like_target (target_user_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_matches (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user1_id BIGINT UNSIGNED NOT NULL,
|
||||
user2_id BIGINT UNSIGNED NOT NULL,
|
||||
matched_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_match_pair (user1_id, user2_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_blocks (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
blocked_user_id BIGINT UNSIGNED NOT NULL,
|
||||
reason VARCHAR(255) NOT NULL DEFAULT '',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_block_pair (user_id, blocked_user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS profile_visits (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
viewer_user_id BIGINT UNSIGNED NOT NULL,
|
||||
target_user_id BIGINT UNSIGNED NOT NULL,
|
||||
source VARCHAR(30) NOT NULL DEFAULT 'profile',
|
||||
visited_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_visit_target_time (target_user_id, visited_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_location_states (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
city_code VARCHAR(20) NOT NULL,
|
||||
location_cell VARCHAR(32) NOT NULL DEFAULT '',
|
||||
latitude DECIMAL(10,7) NULL,
|
||||
longitude DECIMAL(10,7) NULL,
|
||||
last_location_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
source VARCHAR(20) NOT NULL DEFAULT 'gps',
|
||||
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),
|
||||
KEY idx_location_city_time (city_code, last_location_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
CREATE TABLE IF NOT EXISTS media_assets (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
owner_user_id BIGINT UNSIGNED NOT NULL,
|
||||
media_type VARCHAR(20) NOT NULL,
|
||||
storage_provider VARCHAR(20) NOT NULL DEFAULT 'local',
|
||||
bucket VARCHAR(100) NOT NULL DEFAULT '',
|
||||
object_key VARCHAR(500) NOT NULL DEFAULT '',
|
||||
public_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
mime_type VARCHAR(100) NOT NULL DEFAULT '',
|
||||
file_size BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
width INT UNSIGNED NULL,
|
||||
height INT UNSIGNED NULL,
|
||||
duration_ms INT UNSIGNED NULL,
|
||||
moderation_status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
deleted_at DATETIME(3) NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS posts (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
content VARCHAR(2000) NOT NULL DEFAULT '',
|
||||
visibility TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
city_code VARCHAR(20) NOT NULL DEFAULT '',
|
||||
location_text VARCHAR(100) NOT NULL DEFAULT '',
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
moderation_status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
like_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
comment_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
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),
|
||||
deleted_at DATETIME(3) NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_posts_status_created (status, created_at),
|
||||
KEY idx_posts_user_created (user_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS post_media (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
post_id BIGINT UNSIGNED NOT NULL,
|
||||
media_id BIGINT UNSIGNED NULL,
|
||||
media_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
media_type VARCHAR(20) NOT NULL DEFAULT 'image',
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_post_media_post (post_id, sort_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS post_likes (
|
||||
post_id BIGINT UNSIGNED NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (post_id, user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS post_comments (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
post_id BIGINT UNSIGNED NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
parent_comment_id BIGINT UNSIGNED NULL,
|
||||
reply_user_id BIGINT UNSIGNED NULL,
|
||||
content VARCHAR(1000) NOT NULL,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
moderation_status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
deleted_at DATETIME(3) NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_comments_post_created (post_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
CREATE TABLE IF NOT EXISTS im_conversations (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
conversation_type TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
last_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
last_message_id BIGINT UNSIGNED NULL,
|
||||
last_message_at DATETIME(3) NULL,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
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_conversation_last (last_message_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_direct_conversations (
|
||||
conversation_id BIGINT UNSIGNED NOT NULL,
|
||||
user1_id BIGINT UNSIGNED NOT NULL,
|
||||
user2_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (conversation_id),
|
||||
UNIQUE KEY uk_direct_pair (user1_id, user2_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_conversation_members (
|
||||
conversation_id BIGINT UNSIGNED NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
join_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
read_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
delivered_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
clear_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
pinned TINYINT(1) NOT NULL DEFAULT 0,
|
||||
muted TINYINT(1) NOT NULL DEFAULT 0,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
joined_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 (conversation_id, user_id),
|
||||
KEY idx_member_user (user_id, updated_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_messages (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
conversation_id BIGINT UNSIGNED NOT NULL,
|
||||
seq BIGINT UNSIGNED NOT NULL,
|
||||
sender_id BIGINT UNSIGNED NOT NULL,
|
||||
client_msg_id CHAR(26) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
||||
message_type SMALLINT UNSIGNED NOT NULL,
|
||||
body MEDIUMBLOB NOT NULL,
|
||||
reply_to_message_id BIGINT UNSIGNED NULL,
|
||||
moderation_status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
recalled_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_conv_seq (conversation_id, seq),
|
||||
UNIQUE KEY uk_sender_client_msg (sender_id, client_msg_id),
|
||||
KEY idx_conv_created (conversation_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_user_sync_events (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
event_seq BIGINT UNSIGNED NOT NULL,
|
||||
event_type SMALLINT UNSIGNED NOT NULL,
|
||||
conversation_id BIGINT UNSIGNED NOT NULL,
|
||||
message_seq BIGINT UNSIGNED NOT NULL,
|
||||
event_data MEDIUMBLOB NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (user_id, event_seq),
|
||||
KEY idx_sync_created (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
CREATE TABLE IF NOT EXISTS membership_plans (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
code VARCHAR(30) NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
level TINYINT UNSIGNED NOT NULL,
|
||||
duration_days INT UNSIGNED NOT NULL,
|
||||
price_cent INT UNSIGNED NOT NULL,
|
||||
original_price_cent INT UNSIGNED NOT NULL,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
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_plan_code (code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS benefit_definitions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
benefit_key VARCHAR(50) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
value_type VARCHAR(20) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_benefit_key (benefit_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS plan_benefits (
|
||||
plan_id BIGINT UNSIGNED NOT NULL,
|
||||
benefit_id BIGINT UNSIGNED NOT NULL,
|
||||
benefit_value VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (plan_id, benefit_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS subscriptions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
plan_id BIGINT UNSIGNED NOT NULL,
|
||||
source VARCHAR(30) NOT NULL,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
started_at DATETIME(3) NOT NULL,
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
auto_renew TINYINT(1) NOT NULL DEFAULT 0,
|
||||
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_sub_user_expire (user_id, expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_entitlements (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
benefit_key VARCHAR(50) NOT NULL,
|
||||
benefit_value VARCHAR(255) NOT NULL,
|
||||
source_type VARCHAR(30) NOT NULL,
|
||||
source_id BIGINT UNSIGNED NOT NULL,
|
||||
started_at DATETIME(3) NOT NULL,
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_entitlement_user_key (user_id, benefit_key, expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS orders (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
order_no VARCHAR(40) NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
product_type VARCHAR(30) NOT NULL,
|
||||
product_id BIGINT UNSIGNED NOT NULL,
|
||||
amount_cent INT UNSIGNED NOT NULL,
|
||||
currency CHAR(3) NOT NULL DEFAULT 'CNY',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CREATED',
|
||||
channel VARCHAR(30) NOT NULL DEFAULT '',
|
||||
paid_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),
|
||||
UNIQUE KEY uk_order_no (order_no),
|
||||
KEY idx_order_user_created (user_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
CREATE TABLE IF NOT EXISTS reports (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
reporter_user_id BIGINT UNSIGNED NOT NULL,
|
||||
target_type VARCHAR(30) NOT NULL,
|
||||
target_id BIGINT UNSIGNED NOT NULL,
|
||||
reason_code VARCHAR(50) NOT NULL,
|
||||
description VARCHAR(1000) NOT NULL DEFAULT '',
|
||||
evidence_json JSON NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
||||
handled_by BIGINT UNSIGNED NULL,
|
||||
handled_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_reports_status_created (status, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS moderation_tasks (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
target_type VARCHAR(30) NOT NULL,
|
||||
target_id BIGINT UNSIGNED NOT NULL,
|
||||
content_type VARCHAR(30) NOT NULL,
|
||||
risk_score INT NOT NULL DEFAULT 0,
|
||||
machine_result JSON NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
||||
reviewer_id BIGINT UNSIGNED NULL,
|
||||
review_result VARCHAR(255) NOT NULL DEFAULT '',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
reviewed_at DATETIME(3) NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_moderation_status_created (status, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_risk_profiles (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
risk_score INT NOT NULL DEFAULT 0,
|
||||
risk_level TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
message_score INT NOT NULL DEFAULT 0,
|
||||
device_score INT NOT NULL DEFAULT 0,
|
||||
report_score INT NOT NULL DEFAULT 0,
|
||||
behavior_score INT NOT NULL DEFAULT 0,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (user_id),
|
||||
KEY idx_risk_level_score (risk_level, risk_score)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS risk_events (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
event_type VARCHAR(50) NOT NULL,
|
||||
score_delta INT NOT NULL,
|
||||
device_id VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ip VARCHAR(45) NOT NULL DEFAULT '',
|
||||
metadata JSON NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_risk_event_user_created (user_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
type VARCHAR(30) NOT NULL,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
content VARCHAR(1000) NOT NULL,
|
||||
biz_type VARCHAR(30) NOT NULL DEFAULT '',
|
||||
biz_id BIGINT UNSIGNED NULL,
|
||||
read_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_notify_user_read_created (user_id, read_at, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
CREATE TABLE IF NOT EXISTS system_configs (
|
||||
config_key VARCHAR(100) NOT NULL,
|
||||
config_value TEXT NOT NULL,
|
||||
value_type VARCHAR(20) NOT NULL DEFAULT 'string',
|
||||
description VARCHAR(255) NOT NULL DEFAULT '',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (config_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS banners (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
image_url VARCHAR(500) NOT NULL,
|
||||
link_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
position VARCHAR(30) NOT NULL DEFAULT 'home',
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
starts_at DATETIME(3) NULL,
|
||||
ends_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS app_versions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
platform VARCHAR(20) NOT NULL,
|
||||
version VARCHAR(30) NOT NULL,
|
||||
build_number INT UNSIGNED NOT NULL,
|
||||
force_update TINYINT(1) NOT NULL DEFAULT 0,
|
||||
download_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
release_notes VARCHAR(2000) NOT NULL DEFAULT '',
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_version_platform_build (platform, build_number)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_audit_logs (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
admin_user_id BIGINT UNSIGNED NOT NULL,
|
||||
action VARCHAR(100) NOT NULL,
|
||||
target_type VARCHAR(50) NOT NULL DEFAULT '',
|
||||
target_id BIGINT UNSIGNED NULL,
|
||||
request_data JSON NULL,
|
||||
ip VARCHAR(45) NOT NULL DEFAULT '',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_audit_admin_created (admin_user_id, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
||||
('im.recall_seconds', '120', 'number', '消息撤回时间窗口'),
|
||||
('nearby.max_distance_km', '50', 'number', '附近的人最大距离'),
|
||||
('stranger.daily_limit', '10', 'number', '普通用户每日主动聊天人数')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description);
|
||||
|
||||
INSERT INTO membership_plans (code, name, level, duration_days, price_cent, original_price_cent, status, sort_order) VALUES
|
||||
('VIP_1M', 'VIP 1个月', 1, 30, 2800, 4000, 1, 10),
|
||||
('VIP_3M', 'VIP 3个月', 1, 90, 6800, 9000, 1, 20),
|
||||
('SVIP_12M', 'SVIP 12个月', 2, 365, 22800, 36000, 1, 30)
|
||||
ON DUPLICATE KEY UPDATE name = VALUES(name), price_cent = VALUES(price_cent), original_price_cent = VALUES(original_price_cent);
|
||||
|
||||
INSERT INTO tags (category, name, icon, status, sort_order) VALUES
|
||||
('personality', '天秤座', '', 1, 10),
|
||||
('hobby', '摄影爱好者', '', 1, 20),
|
||||
('hobby', '旅行达人', '', 1, 30),
|
||||
('hobby', '电影', '', 1, 40),
|
||||
('hobby', '音乐', '', 1, 50)
|
||||
ON DUPLICATE KEY UPDATE status = VALUES(status);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
CREATE TABLE IF NOT EXISTS sms_verification_codes (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
phone_hash BINARY(32) NOT NULL,
|
||||
scene VARCHAR(30) NOT NULL,
|
||||
code_hash BINARY(32) NOT NULL,
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
used_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_sms_phone_scene_created (phone_hash, scene, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
||||
('sms.enabled', 'true', 'boolean', '是否启用短信服务'),
|
||||
('sms.provider', 'debug', 'string', '短信提供商:debug 或 webhook'),
|
||||
('sms.sign_name', '星遇社交', 'string', '短信签名'),
|
||||
('sms.template_register', 'REGISTER', 'string', '注册验证码模板 ID'),
|
||||
('sms.template_login', 'LOGIN', 'string', '登录验证码模板 ID'),
|
||||
('sms.template_reset', 'RESET', 'string', '找回密码模板 ID'),
|
||||
('sms.webhook_url', '', 'string', '短信网关 Webhook 地址'),
|
||||
('sms.webhook_token', '', 'secret', '短信网关鉴权令牌'),
|
||||
('sms.debug_code', '123456', 'secret', '本地调试验证码'),
|
||||
('sms.expire_seconds', '300', 'number', '验证码有效期(秒)'),
|
||||
('payment.mode', 'sandbox', 'string', '支付模式:sandbox 或 live'),
|
||||
('payment.alipay.enabled', 'true', 'boolean', '是否启用支付宝'),
|
||||
('payment.alipay.app_id', '', 'string', '支付宝应用 APPID'),
|
||||
('payment.alipay.private_key', '', 'secret', '支付宝应用私钥'),
|
||||
('payment.alipay.public_key', '', 'secret', '支付宝公钥'),
|
||||
('payment.alipay.notify_url', '', 'string', '支付宝异步通知地址'),
|
||||
('payment.wechat.enabled', 'true', 'boolean', '是否启用微信支付'),
|
||||
('payment.wechat.app_id', '', 'string', '微信支付 AppID'),
|
||||
('payment.wechat.mch_id', '', 'string', '微信支付商户号'),
|
||||
('payment.wechat.api_v3_key', '', 'secret', '微信支付 APIv3 密钥'),
|
||||
('payment.wechat.private_key', '', 'secret', '微信支付商户私钥'),
|
||||
('payment.wechat.serial_no', '', 'string', '微信支付证书序列号'),
|
||||
('payment.wechat.notify_url', '', 'string', '微信支付回调地址')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description), value_type = VALUES(value_type);
|
||||
@@ -0,0 +1,6 @@
|
||||
-- PowerShell 5 may encode text piped to native executables as the active ANSI
|
||||
-- code page. Repair the only user-visible non-ASCII integration default for
|
||||
-- databases initialized by the earlier migration runner.
|
||||
UPDATE system_configs
|
||||
SET config_value = CONVERT(0xE6989FE98187E7A4BEE4BAA4 USING utf8mb4)
|
||||
WHERE config_key = 'sms.sign_name' AND config_value = '????';
|
||||
@@ -0,0 +1,64 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_verifications (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
verification_type VARCHAR(30) NOT NULL DEFAULT 'real_name',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'UNVERIFIED',
|
||||
real_name VARCHAR(50) NOT NULL DEFAULT '',
|
||||
document_mask VARCHAR(80) NOT NULL DEFAULT '',
|
||||
remark VARCHAR(500) NOT NULL DEFAULT '',
|
||||
reviewer_admin_id BIGINT UNSIGNED NULL,
|
||||
submitted_at DATETIME(3) NULL,
|
||||
reviewed_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 (user_id),
|
||||
KEY idx_verification_status_updated (status, updated_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sanctions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
sanction_type VARCHAR(30) NOT NULL,
|
||||
reason VARCHAR(500) NOT NULL,
|
||||
starts_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
expires_at DATETIME(3) NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
operator_admin_id BIGINT UNSIGNED NOT NULL,
|
||||
revoked_by BIGINT UNSIGNED NULL,
|
||||
revoked_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_sanction_user_status_expire (user_id, status, expires_at),
|
||||
KEY idx_sanction_created (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_security_controls (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
token_version INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
force_logout_at DATETIME(3) NULL,
|
||||
password_reset_at DATETIME(3) NULL,
|
||||
last_operator_admin_id BIGINT UNSIGNED NULL,
|
||||
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;
|
||||
|
||||
SET @token_version_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='user_security_controls' AND COLUMN_NAME='token_version');
|
||||
SET @token_version_sql=IF(@token_version_exists=0,'ALTER TABLE user_security_controls ADD COLUMN token_version INT UNSIGNED NOT NULL DEFAULT 0 AFTER user_id','SELECT 1');
|
||||
PREPARE token_version_stmt FROM @token_version_sql;
|
||||
EXECUTE token_version_stmt;
|
||||
DEALLOCATE PREPARE token_version_stmt;
|
||||
|
||||
INSERT INTO user_verifications (user_id, status)
|
||||
SELECT u.id, 'UNVERIFIED' FROM users u
|
||||
LEFT JOIN user_verifications v ON v.user_id=u.id
|
||||
WHERE v.user_id IS NULL;
|
||||
|
||||
INSERT INTO subscriptions (user_id, plan_id, source, status, started_at, expires_at)
|
||||
SELECT p.user_id, mp.id, 'legacy_backfill', 1, NOW(3), DATE_ADD(NOW(3), INTERVAL mp.duration_days DAY)
|
||||
FROM user_profiles p
|
||||
JOIN membership_plans mp ON mp.level=p.vip_level
|
||||
AND mp.duration_days=(SELECT MAX(mp2.duration_days) FROM membership_plans mp2 WHERE mp2.level=p.vip_level)
|
||||
WHERE p.is_vip=1 AND p.vip_level>0
|
||||
AND NOT EXISTS (SELECT 1 FROM subscriptions s WHERE s.user_id=p.user_id AND s.status=1 AND s.expires_at>NOW(3));
|
||||
@@ -0,0 +1,25 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
SET @plan_deleted_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='membership_plans' AND COLUMN_NAME='deleted_at');
|
||||
SET @plan_deleted_sql=IF(@plan_deleted_exists=0,'ALTER TABLE membership_plans ADD COLUMN deleted_at DATETIME(3) NULL AFTER updated_at','SELECT 1');
|
||||
PREPARE plan_deleted_stmt FROM @plan_deleted_sql;
|
||||
EXECUTE plan_deleted_stmt;
|
||||
DEALLOCATE PREPARE plan_deleted_stmt;
|
||||
|
||||
SET @order_deleted_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND COLUMN_NAME='deleted_at');
|
||||
SET @order_deleted_sql=IF(@order_deleted_exists=0,'ALTER TABLE orders ADD COLUMN deleted_at DATETIME(3) NULL AFTER updated_at','SELECT 1');
|
||||
PREPARE order_deleted_stmt FROM @order_deleted_sql;
|
||||
EXECUTE order_deleted_stmt;
|
||||
DEALLOCATE PREPARE order_deleted_stmt;
|
||||
|
||||
SET @plan_deleted_index_exists=(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='membership_plans' AND INDEX_NAME='idx_plan_deleted_sort');
|
||||
SET @plan_deleted_index_sql=IF(@plan_deleted_index_exists=0,'ALTER TABLE membership_plans ADD KEY idx_plan_deleted_sort (deleted_at,sort_order)','SELECT 1');
|
||||
PREPARE plan_deleted_index_stmt FROM @plan_deleted_index_sql;
|
||||
EXECUTE plan_deleted_index_stmt;
|
||||
DEALLOCATE PREPARE plan_deleted_index_stmt;
|
||||
|
||||
SET @order_deleted_index_exists=(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND INDEX_NAME='idx_order_deleted_created');
|
||||
SET @order_deleted_index_sql=IF(@order_deleted_index_exists=0,'ALTER TABLE orders ADD KEY idx_order_deleted_created (deleted_at,created_at)','SELECT 1');
|
||||
PREPARE order_deleted_index_stmt FROM @order_deleted_index_sql;
|
||||
EXECUTE order_deleted_index_stmt;
|
||||
DEALLOCATE PREPARE order_deleted_index_stmt;
|
||||
@@ -0,0 +1,6 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- Accept both the canonical 26-character client ID and UUID-style IDs from
|
||||
-- older/cached clients while preserving sender-level idempotency.
|
||||
ALTER TABLE im_messages
|
||||
MODIFY COLUMN client_msg_id VARCHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;
|
||||
@@ -0,0 +1,12 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS api_rate_limits (
|
||||
bucket_key BINARY(32) NOT NULL,
|
||||
action_name VARCHAR(40) NOT NULL,
|
||||
hits INT UNSIGNED NOT NULL DEFAULT 1,
|
||||
expires_at DATETIME(3) NOT 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 (bucket_key),
|
||||
KEY idx_rate_limit_expires (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,61 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
SET @provider_order_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND COLUMN_NAME='provider_order_no');
|
||||
SET @provider_order_sql=IF(@provider_order_exists=0,'ALTER TABLE orders ADD COLUMN provider_order_no VARCHAR(100) NOT NULL DEFAULT '''' AFTER channel','SELECT 1');
|
||||
PREPARE provider_order_stmt FROM @provider_order_sql;
|
||||
EXECUTE provider_order_stmt;
|
||||
DEALLOCATE PREPARE provider_order_stmt;
|
||||
|
||||
SET @checkout_url_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND COLUMN_NAME='checkout_url');
|
||||
SET @checkout_url_sql=IF(@checkout_url_exists=0,'ALTER TABLE orders ADD COLUMN checkout_url VARCHAR(1000) NOT NULL DEFAULT '''' AFTER provider_order_no','SELECT 1');
|
||||
PREPARE checkout_url_stmt FROM @checkout_url_sql;
|
||||
EXECUTE checkout_url_stmt;
|
||||
DEALLOCATE PREPARE checkout_url_stmt;
|
||||
|
||||
SET @payment_payload_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND COLUMN_NAME='payment_payload');
|
||||
SET @payment_payload_sql=IF(@payment_payload_exists=0,'ALTER TABLE orders ADD COLUMN payment_payload MEDIUMTEXT NULL AFTER checkout_url','SELECT 1');
|
||||
PREPARE payment_payload_stmt FROM @payment_payload_sql;
|
||||
EXECUTE payment_payload_stmt;
|
||||
DEALLOCATE PREPARE payment_payload_stmt;
|
||||
|
||||
SET @paid_amount_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND COLUMN_NAME='paid_amount_cent');
|
||||
SET @paid_amount_sql=IF(@paid_amount_exists=0,'ALTER TABLE orders ADD COLUMN paid_amount_cent INT UNSIGNED NULL AFTER amount_cent','SELECT 1');
|
||||
PREPARE paid_amount_stmt FROM @paid_amount_sql;
|
||||
EXECUTE paid_amount_stmt;
|
||||
DEALLOCATE PREPARE paid_amount_stmt;
|
||||
|
||||
SET @payment_notified_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND COLUMN_NAME='payment_notified_at');
|
||||
SET @payment_notified_sql=IF(@payment_notified_exists=0,'ALTER TABLE orders ADD COLUMN payment_notified_at DATETIME(3) NULL AFTER paid_at','SELECT 1');
|
||||
PREPARE payment_notified_stmt FROM @payment_notified_sql;
|
||||
EXECUTE payment_notified_stmt;
|
||||
DEALLOCATE PREPARE payment_notified_stmt;
|
||||
|
||||
SET @provider_order_index_exists=(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='orders' AND INDEX_NAME='idx_order_provider_no');
|
||||
SET @provider_order_index_sql=IF(@provider_order_index_exists=0,'ALTER TABLE orders ADD KEY idx_order_provider_no (provider_order_no)','SELECT 1');
|
||||
PREPARE provider_order_index_stmt FROM @provider_order_index_sql;
|
||||
EXECUTE provider_order_index_stmt;
|
||||
DEALLOCATE PREPARE provider_order_index_stmt;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS payment_events (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
event_id VARCHAR(100) NOT NULL,
|
||||
order_no VARCHAR(40) NOT NULL,
|
||||
channel VARCHAR(30) NOT NULL,
|
||||
provider_order_no VARCHAR(100) NOT NULL DEFAULT '',
|
||||
event_status VARCHAR(30) NOT NULL,
|
||||
amount_cent INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
raw_payload MEDIUMTEXT NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_payment_event (event_id),
|
||||
KEY idx_payment_event_order (order_no,created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO system_configs (config_key,config_value,value_type,description) VALUES
|
||||
('payment.gateway.create_url','','string','统一支付网关创建支付地址'),
|
||||
('payment.gateway.token','','secret','统一支付网关 Bearer Token'),
|
||||
('payment.gateway.notify_secret','','secret','支付通知 HMAC-SHA256 密钥'),
|
||||
('payment.gateway.notify_url','','string','本系统支付通知公网 HTTPS 地址'),
|
||||
('payment.gateway.return_url','','string','支付完成后的客户端返回地址'),
|
||||
('payment.gateway.timeout_seconds','10','number','支付网关请求超时秒数')
|
||||
ON DUPLICATE KEY UPDATE description=VALUES(description),value_type=VALUES(value_type);
|
||||
@@ -0,0 +1,5 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
INSERT INTO system_configs (config_key,config_value,value_type,description) VALUES
|
||||
('payment.gateway.refund_url','','string','统一支付网关退款申请地址')
|
||||
ON DUPLICATE KEY UPDATE description=VALUES(description),value_type=VALUES(value_type);
|
||||
@@ -0,0 +1,6 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
ALTER TABLE admin_users
|
||||
ADD COLUMN token_version INT UNSIGNED NOT NULL DEFAULT 0 AFTER status,
|
||||
ADD COLUMN password_changed_at DATETIME(3) NULL AFTER last_login_at;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
||||
('sms.aliyun.endpoint', 'https://dysmsapi.aliyuncs.com', 'string', '阿里云短信 API 地址'),
|
||||
('sms.aliyun.access_key_id', '', 'secret', '阿里云 AccessKey ID'),
|
||||
('sms.aliyun.access_key_secret', '', 'secret', '阿里云 AccessKey Secret'),
|
||||
('sms.aliyun.sign_name', '', 'string', '阿里云短信签名'),
|
||||
('sms.aliyun.template_register', '', 'string', '阿里云注册模板 Code'),
|
||||
('sms.aliyun.template_login', '', 'string', '阿里云登录模板 Code'),
|
||||
('sms.aliyun.template_reset', '', 'string', '阿里云重置密码模板 Code'),
|
||||
('sms.aliyun.template_params', '{"code":"{{code}}"}', 'string', '阿里云模板变量 JSON'),
|
||||
|
||||
('sms.tencent.endpoint', 'https://sms.tencentcloudapi.com', 'string', '腾讯云短信 API 地址'),
|
||||
('sms.tencent.secret_id', '', 'secret', '腾讯云 SecretId'),
|
||||
('sms.tencent.secret_key', '', 'secret', '腾讯云 SecretKey'),
|
||||
('sms.tencent.sdk_app_id', '', 'string', '腾讯云短信 SdkAppId'),
|
||||
('sms.tencent.region', 'ap-guangzhou', 'string', '腾讯云短信地域'),
|
||||
('sms.tencent.sign_name', '', 'string', '腾讯云短信签名'),
|
||||
('sms.tencent.template_register', '', 'string', '腾讯云注册模板 ID'),
|
||||
('sms.tencent.template_login', '', 'string', '腾讯云登录模板 ID'),
|
||||
('sms.tencent.template_reset', '', 'string', '腾讯云重置密码模板 ID'),
|
||||
('sms.tencent.template_params', '["{{code}}"]', 'string', '腾讯云模板参数 JSON'),
|
||||
|
||||
('sms.huawei.endpoint', '', 'string', '华为云短信 APP 接入地址'),
|
||||
('sms.huawei.app_key', '', 'secret', '华为云短信 Application Key'),
|
||||
('sms.huawei.app_secret', '', 'secret', '华为云短信 Application Secret'),
|
||||
('sms.huawei.sender', '', 'string', '华为云短信签名通道号'),
|
||||
('sms.huawei.signature', '', 'string', '华为云短信签名名称'),
|
||||
('sms.huawei.template_register', '', 'string', '华为云注册模板 ID'),
|
||||
('sms.huawei.template_login', '', 'string', '华为云登录模板 ID'),
|
||||
('sms.huawei.template_reset', '', 'string', '华为云重置密码模板 ID'),
|
||||
('sms.huawei.template_params', '["{{code}}"]', 'string', '华为云模板参数 JSON'),
|
||||
('sms.huawei.status_callback', '', 'string', '华为云短信状态回调地址')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description), value_type = VALUES(value_type);
|
||||
|
||||
UPDATE system_configs
|
||||
SET description = '短信提供商:aliyun、tencent、huawei、webhook 或 debug'
|
||||
WHERE config_key = 'sms.provider';
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
||||
('storage.provider', 'local', 'string', '文件存储提供商:local、aliyun_oss、tencent_cos、qiniu、huawei_obs 或 huawei_flexus'),
|
||||
('storage.object_prefix', 'media', 'string', '云端对象键前缀'),
|
||||
|
||||
('storage.local.directory', './uploads', 'string', '本地文件存储目录'),
|
||||
('storage.local.public_base_url', '', 'string', '本地文件公开访问地址'),
|
||||
|
||||
('storage.aliyun_oss.endpoint', 'https://oss-cn-hangzhou.aliyuncs.com', 'string', '阿里云 OSS Endpoint'),
|
||||
('storage.aliyun_oss.region', 'cn-hangzhou', 'string', '阿里云 OSS Region'),
|
||||
('storage.aliyun_oss.bucket', '', 'string', '阿里云 OSS Bucket'),
|
||||
('storage.aliyun_oss.access_key_id', '', 'secret', '阿里云 OSS AccessKey ID'),
|
||||
('storage.aliyun_oss.access_key_secret', '', 'secret', '阿里云 OSS AccessKey Secret'),
|
||||
('storage.aliyun_oss.public_base_url', '', 'string', '阿里云 OSS 文件访问域名'),
|
||||
|
||||
('storage.tencent_cos.endpoint', '', 'string', '腾讯云 COS Bucket URL'),
|
||||
('storage.tencent_cos.bucket', '', 'string', '腾讯云 COS Bucket'),
|
||||
('storage.tencent_cos.secret_id', '', 'secret', '腾讯云 COS SecretId'),
|
||||
('storage.tencent_cos.secret_key', '', 'secret', '腾讯云 COS SecretKey'),
|
||||
('storage.tencent_cos.public_base_url', '', 'string', '腾讯云 COS 文件访问域名'),
|
||||
|
||||
('storage.qiniu.bucket', '', 'string', '七牛云 Kodo 空间名称'),
|
||||
('storage.qiniu.access_key', '', 'secret', '七牛云 AccessKey'),
|
||||
('storage.qiniu.secret_key', '', 'secret', '七牛云 SecretKey'),
|
||||
('storage.qiniu.public_base_url', '', 'string', '七牛云文件访问域名'),
|
||||
|
||||
('storage.huawei_obs.endpoint', 'https://obs.cn-north-4.myhuaweicloud.com', 'string', '华为云 OBS Endpoint'),
|
||||
('storage.huawei_obs.bucket', '', 'string', '华为云 OBS Bucket'),
|
||||
('storage.huawei_obs.access_key', '', 'secret', '华为云 OBS Access Key'),
|
||||
('storage.huawei_obs.secret_key', '', 'secret', '华为云 OBS Secret Key'),
|
||||
('storage.huawei_obs.public_base_url', '', 'string', '华为云 OBS 文件访问域名'),
|
||||
|
||||
('storage.huawei_flexus.endpoint', '', 'string', '华为云 Flexus 对象存储 Endpoint'),
|
||||
('storage.huawei_flexus.bucket', '', 'string', '华为云 Flexus 对象存储 Bucket'),
|
||||
('storage.huawei_flexus.access_key', '', 'secret', '华为云 Flexus 对象存储 Access Key'),
|
||||
('storage.huawei_flexus.secret_key', '', 'secret', '华为云 Flexus 对象存储 Secret Key'),
|
||||
('storage.huawei_flexus.public_base_url', '', 'string', '华为云 Flexus 对象存储文件访问域名')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description), value_type = VALUES(value_type);
|
||||
@@ -0,0 +1,34 @@
|
||||
SET @daily_chat_limit_exists=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='membership_plans' AND COLUMN_NAME='daily_active_chat_limit');
|
||||
SET @daily_chat_limit_sql=IF(@daily_chat_limit_exists=0,'ALTER TABLE membership_plans ADD COLUMN daily_active_chat_limit INT UNSIGNED NOT NULL DEFAULT 20 AFTER duration_days','SELECT 1');
|
||||
PREPARE daily_chat_limit_stmt FROM @daily_chat_limit_sql;
|
||||
EXECUTE daily_chat_limit_stmt;
|
||||
DEALLOCATE PREPARE daily_chat_limit_stmt;
|
||||
|
||||
UPDATE membership_plans
|
||||
SET daily_active_chat_limit=CASE WHEN level>=2 THEN 100 ELSE 20 END
|
||||
WHERE daily_active_chat_limit=20;
|
||||
|
||||
INSERT INTO system_configs(config_key,config_value,value_type,description) VALUES
|
||||
('membership.free_daily_active_chat_limit','5','integer','普通用户每日可主动聊天的不同用户数,0 表示不限制')
|
||||
ON DUPLICATE KEY UPDATE description=VALUES(description);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_daily_active_chat_usage (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
usage_date DATE NOT NULL,
|
||||
used_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
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,usage_date),
|
||||
KEY idx_daily_chat_usage_date (usage_date)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_daily_active_chat_targets (
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
target_user_id BIGINT UNSIGNED NOT NULL,
|
||||
usage_date DATE NOT NULL,
|
||||
conversation_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (user_id,target_user_id,usage_date),
|
||||
KEY idx_daily_chat_target_date (target_user_id,usage_date),
|
||||
KEY idx_daily_chat_conversation (conversation_id,created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,87 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_oauth_identities (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
provider VARCHAR(20) NOT NULL,
|
||||
subject VARCHAR(191) NOT NULL,
|
||||
admin_user_id BIGINT UNSIGNED NOT NULL,
|
||||
email VARCHAR(255) NOT NULL DEFAULT '',
|
||||
display_name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
last_login_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),
|
||||
UNIQUE KEY uk_admin_oauth_provider_subject (provider, subject),
|
||||
UNIQUE KEY uk_admin_oauth_user_provider (admin_user_id, provider),
|
||||
CONSTRAINT fk_admin_oauth_identity_user FOREIGN KEY (admin_user_id) REFERENCES admin_users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_oauth_states (
|
||||
state_hash BINARY(32) NOT NULL,
|
||||
provider VARCHAR(20) NOT NULL,
|
||||
code_verifier VARCHAR(128) NOT NULL DEFAULT '',
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
used_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (state_hash),
|
||||
KEY idx_admin_oauth_state_expiry (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_oauth_login_codes (
|
||||
code_hash BINARY(32) NOT NULL,
|
||||
provider VARCHAR(20) NOT NULL,
|
||||
subject VARCHAR(191) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL DEFAULT '',
|
||||
display_name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
admin_user_id BIGINT UNSIGNED NULL,
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
used_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (code_hash),
|
||||
KEY idx_admin_oauth_code_expiry (expires_at),
|
||||
KEY idx_admin_oauth_code_admin (admin_user_id),
|
||||
CONSTRAINT fk_admin_oauth_code_user FOREIGN KEY (admin_user_id) REFERENCES admin_users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
||||
('oauth.admin.frontend_callback_url', 'http://localhost:5560/auth/social-callback', 'string', '第三方登录完成后跳转的管理端页面;生产环境必须使用 HTTPS'),
|
||||
|
||||
('oauth.wechat.enabled', 'false', 'boolean', '启用微信扫码登录'),
|
||||
('oauth.wechat.client_id', '', 'string', '微信开放平台网站应用 AppID'),
|
||||
('oauth.wechat.client_secret', '', 'secret', '微信开放平台网站应用 AppSecret'),
|
||||
('oauth.wechat.authorization_url', 'https://open.weixin.qq.com/connect/qrconnect', 'string', '微信登录授权地址'),
|
||||
('oauth.wechat.token_url', 'https://api.weixin.qq.com/sns/oauth2/access_token', 'string', '微信登录令牌地址'),
|
||||
('oauth.wechat.userinfo_url', 'https://api.weixin.qq.com/sns/userinfo', 'string', '微信用户信息地址'),
|
||||
('oauth.wechat.scope', 'snsapi_login', 'string', '微信网站应用登录授权范围'),
|
||||
('oauth.wechat.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', '微信开放平台登记的授权回调地址;生产环境必须使用 HTTPS'),
|
||||
|
||||
('oauth.qq.enabled', 'false', 'boolean', '启用 QQ 登录'),
|
||||
('oauth.qq.client_id', '', 'string', 'QQ 互联应用 AppID'),
|
||||
('oauth.qq.client_secret', '', 'secret', 'QQ 互联应用 AppKey'),
|
||||
('oauth.qq.authorization_url', 'https://graph.qq.com/oauth2.0/authorize', 'string', 'QQ 登录授权地址'),
|
||||
('oauth.qq.token_url', 'https://graph.qq.com/oauth2.0/token', 'string', 'QQ 登录令牌地址'),
|
||||
('oauth.qq.openid_url', 'https://graph.qq.com/oauth2.0/me', 'string', 'QQ OpenID 查询地址'),
|
||||
('oauth.qq.userinfo_url', 'https://graph.qq.com/user/get_user_info', 'string', 'QQ 用户信息地址'),
|
||||
('oauth.qq.scope', 'get_user_info', 'string', 'QQ 登录授权范围'),
|
||||
('oauth.qq.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', 'QQ 互联登记的授权回调地址;生产环境必须使用 HTTPS'),
|
||||
|
||||
('oauth.github.enabled', 'false', 'boolean', '启用 GitHub 登录'),
|
||||
('oauth.github.client_id', '', 'string', 'GitHub OAuth App Client ID'),
|
||||
('oauth.github.client_secret', '', 'secret', 'GitHub OAuth App Client Secret'),
|
||||
('oauth.github.authorization_url', 'https://github.com/login/oauth/authorize', 'string', 'GitHub OAuth 授权地址'),
|
||||
('oauth.github.token_url', 'https://github.com/login/oauth/access_token', 'string', 'GitHub OAuth 令牌地址'),
|
||||
('oauth.github.userinfo_url', 'https://api.github.com/user', 'string', 'GitHub 当前用户信息地址'),
|
||||
('oauth.github.scope', 'read:user user:email', 'string', 'GitHub 登录最小授权范围'),
|
||||
('oauth.github.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', 'GitHub OAuth App 登记的 callback URL;生产环境必须使用 HTTPS'),
|
||||
|
||||
('oauth.google.enabled', 'false', 'boolean', '启用 Google 登录'),
|
||||
('oauth.google.client_id', '', 'string', 'Google OAuth 2.0 Client ID'),
|
||||
('oauth.google.client_secret', '', 'secret', 'Google OAuth 2.0 Client Secret'),
|
||||
('oauth.google.authorization_url', 'https://accounts.google.com/o/oauth2/v2/auth', 'string', 'Google OAuth 授权地址'),
|
||||
('oauth.google.token_url', 'https://oauth2.googleapis.com/token', 'string', 'Google OAuth 令牌地址'),
|
||||
('oauth.google.userinfo_url', 'https://openidconnect.googleapis.com/v1/userinfo', 'string', 'Google OpenID Connect UserInfo 地址'),
|
||||
('oauth.google.scope', 'openid profile email', 'string', 'Google 登录授权范围'),
|
||||
('oauth.google.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', 'Google Cloud Console 登记的 redirect URI;生产环境必须使用 HTTPS')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description);
|
||||
@@ -0,0 +1,54 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_oauth_identities (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
provider VARCHAR(20) NOT NULL,
|
||||
subject VARCHAR(191) NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
email VARCHAR(255) NOT NULL DEFAULT '',
|
||||
display_name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
last_login_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),
|
||||
UNIQUE KEY uk_user_oauth_provider_subject (provider, subject),
|
||||
UNIQUE KEY uk_user_oauth_user_provider (user_id, provider),
|
||||
CONSTRAINT fk_user_oauth_identity_user FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_oauth_states (
|
||||
state_hash BINARY(32) NOT NULL,
|
||||
provider VARCHAR(20) NOT NULL,
|
||||
code_verifier VARCHAR(128) NOT NULL DEFAULT '',
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
used_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (state_hash),
|
||||
KEY idx_user_oauth_state_expiry (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_oauth_login_codes (
|
||||
code_hash BINARY(32) NOT NULL,
|
||||
provider VARCHAR(20) NOT NULL,
|
||||
subject VARCHAR(191) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL DEFAULT '',
|
||||
display_name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||||
user_id BIGINT UNSIGNED NULL,
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
used_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (code_hash),
|
||||
KEY idx_user_oauth_code_expiry (expires_at),
|
||||
KEY idx_user_oauth_code_user (user_id),
|
||||
CONSTRAINT fk_user_oauth_code_user FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
||||
('oauth.user.frontend_callback_url', 'http://localhost:5174/#/pages/auth/oauth-callback', 'string', '第三方登录完成后跳转的 uni-app H5 页面;生产环境必须使用 HTTPS'),
|
||||
('oauth.user.wechat.enabled', 'false', 'boolean', '在客户端启用微信登录'),
|
||||
('oauth.user.qq.enabled', 'false', 'boolean', '在客户端启用 QQ 登录'),
|
||||
('oauth.user.github.enabled', 'false', 'boolean', '在客户端启用 GitHub 登录'),
|
||||
('oauth.user.google.enabled', 'false', 'boolean', '在客户端启用 Google 登录')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description);
|
||||
@@ -0,0 +1,17 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_sessions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
admin_user_id BIGINT UNSIGNED NOT NULL,
|
||||
refresh_token_hash BINARY(32) NOT NULL,
|
||||
user_agent_hash BINARY(32) NOT NULL,
|
||||
ip VARCHAR(45) NOT NULL DEFAULT '',
|
||||
expires_at DATETIME(3) NOT NULL,
|
||||
last_active_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
revoked_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_admin_sessions_refresh (refresh_token_hash),
|
||||
KEY idx_admin_sessions_user (admin_user_id, revoked_at, expires_at),
|
||||
CONSTRAINT fk_admin_sessions_user FOREIGN KEY (admin_user_id) REFERENCES admin_users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,77 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_roles (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
role_code VARCHAR(50) NOT NULL,
|
||||
role_name VARCHAR(80) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL DEFAULT '',
|
||||
built_in TINYINT(1) NOT NULL DEFAULT 0,
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
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_admin_roles_code (role_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_permissions (
|
||||
permission_code VARCHAR(80) NOT NULL,
|
||||
permission_name VARCHAR(100) NOT NULL,
|
||||
permission_group VARCHAR(50) NOT NULL,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (permission_code),
|
||||
KEY idx_admin_permissions_group (permission_group, sort_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_role_permissions (
|
||||
role_id BIGINT UNSIGNED NOT NULL,
|
||||
permission_code VARCHAR(80) NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (role_id, permission_code),
|
||||
CONSTRAINT fk_admin_role_permissions_role FOREIGN KEY (role_id) REFERENCES admin_roles(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_admin_role_permissions_permission FOREIGN KEY (permission_code) REFERENCES admin_permissions(permission_code) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_user_roles (
|
||||
admin_user_id BIGINT UNSIGNED NOT NULL,
|
||||
role_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (admin_user_id, role_id),
|
||||
KEY idx_admin_user_roles_role (role_id),
|
||||
CONSTRAINT fk_admin_user_roles_user FOREIGN KEY (admin_user_id) REFERENCES admin_users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_admin_user_roles_role FOREIGN KEY (role_id) REFERENCES admin_roles(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO admin_permissions (permission_code, permission_name, permission_group, sort_order) VALUES
|
||||
('dashboard:view', '查看运营概览', 'dashboard', 10),
|
||||
('users:view', '查看用户', 'users', 20),
|
||||
('users:manage', '编辑用户资料和会员', 'users', 21),
|
||||
('users:security', '重置密码和强制下线', 'users', 22),
|
||||
('verification:manage', '审核用户认证', 'users', 23),
|
||||
('violations:manage', '处理违规和账号处罚', 'users', 24),
|
||||
('content:view', '查看动态内容', 'content', 30),
|
||||
('content:manage', '删除和处置动态', 'content', 31),
|
||||
('messages:view', '查看聊天消息记录', 'content', 32),
|
||||
('reports:handle', '处理举报', 'risk', 40),
|
||||
('risk:view', '查看风险信息', 'risk', 41),
|
||||
('membership:manage', '管理会员套餐', 'commerce', 50),
|
||||
('orders:view', '查看订单', 'commerce', 51),
|
||||
('orders:manage', '变更订单和退款', 'commerce', 52),
|
||||
('system:manage', '管理系统、集成和管理员', 'system', 60)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
permission_name=VALUES(permission_name),
|
||||
permission_group=VALUES(permission_group),
|
||||
sort_order=VALUES(sort_order);
|
||||
|
||||
INSERT INTO admin_roles (role_code, role_name, description, built_in, status)
|
||||
VALUES ('super_admin', '超级管理员', '拥有平台全部权限;内置角色不可删除', 1, 1)
|
||||
ON DUPLICATE KEY UPDATE role_name=VALUES(role_name), description=VALUES(description), built_in=1, status=1;
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_code)
|
||||
SELECT r.id, p.permission_code
|
||||
FROM admin_roles r CROSS JOIN admin_permissions p
|
||||
WHERE r.role_code='super_admin';
|
||||
|
||||
-- Existing administrators keep their current capabilities after RBAC is enabled.
|
||||
INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id)
|
||||
SELECT a.id, r.id
|
||||
FROM admin_users a JOIN admin_roles r ON r.role_code='super_admin';
|
||||
@@ -0,0 +1,11 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
ALTER TABLE user_verifications
|
||||
ADD COLUMN document_hash BINARY(32) NULL AFTER document_mask,
|
||||
ADD COLUMN evidence_json TEXT NULL AFTER document_hash,
|
||||
ADD KEY idx_user_verifications_document (document_hash);
|
||||
|
||||
UPDATE user_verifications SET evidence_json='[]' WHERE evidence_json IS NULL OR evidence_json='';
|
||||
|
||||
ALTER TABLE user_verifications
|
||||
MODIFY COLUMN evidence_json TEXT NOT NULL;
|
||||
@@ -0,0 +1,140 @@
|
||||
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);
|
||||
@@ -0,0 +1,17 @@
|
||||
ALTER TABLE reports
|
||||
ADD COLUMN action_type VARCHAR(30) NOT NULL DEFAULT '' AFTER status,
|
||||
ADD COLUMN handle_remark VARCHAR(1000) NOT NULL DEFAULT '' AFTER action_type;
|
||||
|
||||
CREATE INDEX idx_reports_target ON reports(target_type, target_id, created_at);
|
||||
|
||||
ALTER TABLE im_messages
|
||||
ADD COLUMN admin_removed_at DATETIME(3) NULL AFTER recalled_at,
|
||||
ADD COLUMN admin_removed_by BIGINT UNSIGNED NULL AFTER admin_removed_at,
|
||||
ADD COLUMN admin_remove_reason VARCHAR(500) NOT NULL DEFAULT '' AFTER admin_removed_by;
|
||||
|
||||
INSERT INTO admin_permissions(permission_code,permission_name,permission_group,sort_order)
|
||||
VALUES('messages:manage','下架及恢复违规聊天消息','content',33)
|
||||
ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),permission_group=VALUES(permission_group),sort_order=VALUES(sort_order);
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions(role_id,permission_code)
|
||||
SELECT id,'messages:manage' FROM admin_roles WHERE role_code='super_admin';
|
||||
Reference in New Issue
Block a user