gengx
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);
|
||||
Reference in New Issue
Block a user