topfans/backend/scripts/init_database.sql
2026-04-07 22:29:48 +08:00

397 lines
16 KiB
SQL

-- TopFans 数据库初始化脚本
-- 创建所有表结构和索引
-- 开启扩展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- ============================================
-- 1. stars 表 - 明星信息表
-- ============================================
CREATE TABLE IF NOT EXISTS stars (
star_id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
tag VARCHAR(100),
name_en VARCHAR(100),
pic_url VARCHAR(500),
description TEXT,
identity_id VARCHAR(50) NOT NULL UNIQUE,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
-- 唯一索引由列级 UNIQUE 约束保证
-- ============================================
-- 2. users 表 - 用户表
-- ============================================
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
mobile VARCHAR(11) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
access_token TEXT,
token_expires_at BIGINT,
avatar_url VARCHAR(500),
global_wallet_address VARCHAR(100),
is_active BOOLEAN NOT NULL DEFAULT true,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
deleted_at BIGINT
);
-- 唯一索引由列级 UNIQUE 约束保证
CREATE INDEX IF NOT EXISTS idx_users_deleted_at ON users(deleted_at);
-- ============================================
-- 3. fan_profiles 表 - 粉丝档案表
-- ============================================
CREATE TABLE IF NOT EXISTS fan_profiles (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
nickname VARCHAR(50) NOT NULL,
level INTEGER NOT NULL DEFAULT 1,
times INTEGER NOT NULL DEFAULT 1,
social INTEGER NOT NULL DEFAULT 0,
experience BIGINT NOT NULL DEFAULT 0,
coin_balance BIGINT NOT NULL DEFAULT 0,
crystal_balance BIGINT NOT NULL DEFAULT 0,
tags JSONB,
avatar_url VARCHAR(500),
starbook_limit INTEGER NOT NULL DEFAULT 3,
slot_limit INTEGER NOT NULL DEFAULT 3,
assets_count INTEGER NOT NULL DEFAULT 0,
chain_address VARCHAR(100),
is_active BOOLEAN NOT NULL DEFAULT true,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_fan_profiles_user_star UNIQUE (user_id, star_id)
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_fan_profiles_star_nickname ON fan_profiles(star_id, nickname);
CREATE INDEX IF NOT EXISTS idx_fan_profiles_user_id ON fan_profiles(user_id);
CREATE INDEX IF NOT EXISTS idx_fan_profiles_star_id ON fan_profiles(star_id);
-- 外键约束
ALTER TABLE fan_profiles
ADD CONSTRAINT fk_fan_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_fan_profiles_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- ============================================
-- 4. assets 表 - 资产表(藏品)
-- ============================================
CREATE TABLE IF NOT EXISTS assets (
id BIGSERIAL PRIMARY KEY,
owner_uid BIGINT NOT NULL,
star_id BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
cover_url VARCHAR(500) NOT NULL,
material_url VARCHAR(500),
description TEXT,
rarity INTEGER,
tags JSONB,
visibility VARCHAR(20) NOT NULL DEFAULT 'private',
status INTEGER NOT NULL DEFAULT 0,
tx_hash VARCHAR(100),
block_number BIGINT,
like_count INTEGER NOT NULL DEFAULT 0,
is_original BOOLEAN NOT NULL DEFAULT false,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
minted_at BIGINT,
deleted_at BIGINT,
is_active BOOLEAN NOT NULL DEFAULT true
);
CREATE INDEX IF NOT EXISTS idx_assets_owner_star ON assets(owner_uid, star_id);
CREATE INDEX IF NOT EXISTS idx_assets_star_active ON assets(star_id, is_active);
CREATE INDEX IF NOT EXISTS idx_assets_status ON assets(status);
CREATE INDEX IF NOT EXISTS idx_assets_tx_hash ON assets(tx_hash);
CREATE INDEX IF NOT EXISTS idx_assets_created_at ON assets(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_assets_deleted_at ON assets(deleted_at);
-- 外键约束
ALTER TABLE assets
ADD CONSTRAINT fk_assets_owner FOREIGN KEY (owner_uid) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_assets_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- ============================================
-- 5. mint_orders 表 - 铸造订单表
-- ============================================
CREATE TABLE IF NOT EXISTS mint_orders (
order_id VARCHAR(100) PRIMARY KEY,
user_id BIGINT NOT NULL,
asset_id BIGINT,
star_id BIGINT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
cost_crystal BIGINT DEFAULT 0,
error_message TEXT,
retry_count INTEGER DEFAULT 0,
material_url VARCHAR(500),
name VARCHAR(100),
description TEXT,
material_type VARCHAR(50),
event VARCHAR(100),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
minted_at BIGINT
);
CREATE INDEX IF NOT EXISTS idx_mint_orders_user_star ON mint_orders(user_id, star_id);
CREATE INDEX IF NOT EXISTS idx_mint_orders_asset ON mint_orders(asset_id);
CREATE INDEX IF NOT EXISTS idx_mint_orders_status ON mint_orders(status);
CREATE INDEX IF NOT EXISTS idx_mint_orders_created_at ON mint_orders(created_at DESC);
-- 外键约束
ALTER TABLE mint_orders
ADD CONSTRAINT fk_mint_orders_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_mint_orders_asset FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_mint_orders_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- ============================================
-- 6. asset_likes 表 - 点赞记录表
-- ============================================
CREATE TABLE IF NOT EXISTS asset_likes (
id BIGSERIAL PRIMARY KEY,
asset_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
created_at BIGINT NOT NULL,
CONSTRAINT uk_asset_likes_user_asset UNIQUE (user_id, asset_id)
);
CREATE INDEX IF NOT EXISTS idx_asset_likes_asset ON asset_likes(asset_id);
CREATE INDEX IF NOT EXISTS idx_asset_likes_user_star ON asset_likes(user_id, star_id);
-- 外键约束
ALTER TABLE asset_likes
ADD CONSTRAINT fk_asset_likes_asset FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_asset_likes_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_asset_likes_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- ============================================
-- 7. friendships 表 - 好友关系表
-- ============================================
CREATE TABLE IF NOT EXISTS friendships (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
friend_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'accepted',
remark VARCHAR(50),
intimacy INTEGER NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_friendships_user_friend_star UNIQUE (user_id, friend_id, star_id)
);
CREATE INDEX IF NOT EXISTS idx_friendships_user_star_status ON friendships(user_id, star_id, status);
CREATE INDEX IF NOT EXISTS idx_friendships_user_star_created ON friendships(user_id, star_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_friendships_friend_star ON friendships(friend_id, star_id);
CREATE INDEX IF NOT EXISTS idx_friendships_list_query ON friendships(user_id, star_id, status, created_at DESC);
-- 外键约束
ALTER TABLE friendships
ADD CONSTRAINT fk_friendships_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_friendships_friend FOREIGN KEY (friend_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_friendships_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- ============================================
-- 8. friend_requests 表 - 好友请求表
-- ============================================
CREATE TABLE IF NOT EXISTS friend_requests (
id BIGSERIAL PRIMARY KEY,
from_user_id BIGINT NOT NULL,
to_user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
message VARCHAR(200),
status VARCHAR(20) NOT NULL DEFAULT 'pending',
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
expires_at BIGINT,
processed_at BIGINT
);
CREATE INDEX IF NOT EXISTS idx_friend_requests_from_status ON friend_requests(from_user_id, status);
CREATE INDEX IF NOT EXISTS idx_friend_requests_to_status ON friend_requests(to_user_id, status);
CREATE INDEX IF NOT EXISTS idx_friend_requests_star ON friend_requests(star_id);
CREATE INDEX IF NOT EXISTS idx_friend_requests_users_star ON friend_requests(from_user_id, to_user_id, star_id);
CREATE INDEX IF NOT EXISTS idx_friend_requests_expires ON friend_requests(expires_at);
-- 外键约束
ALTER TABLE friend_requests
ADD CONSTRAINT fk_friend_requests_from_user FOREIGN KEY (from_user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_friend_requests_to_user FOREIGN KEY (to_user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_friend_requests_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- ============================================
-- 9. booth_slots 表 - 展位表
-- ============================================
CREATE TABLE IF NOT EXISTS booth_slots (
slot_id BIGSERIAL PRIMARY KEY,
host_profile_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
slot_index INTEGER NOT NULL,
visibility VARCHAR(20) NOT NULL DEFAULT 'public',
is_enabled BOOLEAN DEFAULT false,
unlock_type VARCHAR(20),
unlock_value INTEGER,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_host_slot UNIQUE (host_profile_id, slot_index)
);
CREATE INDEX IF NOT EXISTS idx_user_star ON booth_slots(user_id, star_id);
CREATE INDEX IF NOT EXISTS idx_star_enabled ON booth_slots(star_id, is_enabled);
-- 外键约束
ALTER TABLE booth_slots
ADD CONSTRAINT fk_booth_slots_profile FOREIGN KEY (host_profile_id) REFERENCES fan_profiles(id) ON DELETE CASCADE;
-- ============================================
-- 10. exhibitions 表 - 展品展示表
-- ============================================
CREATE TABLE IF NOT EXISTS exhibitions (
id BIGSERIAL PRIMARY KEY,
asset_id BIGINT NOT NULL,
slot_id BIGINT NOT NULL,
host_profile_id BIGINT NOT NULL,
occupier_uid BIGINT NOT NULL,
occupier_star_id BIGINT NOT NULL,
start_time BIGINT NOT NULL,
expire_at BIGINT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_asset UNIQUE (asset_id)
);
CREATE INDEX IF NOT EXISTS idx_slot ON exhibitions(slot_id);
CREATE INDEX IF NOT EXISTS idx_host ON exhibitions(host_profile_id);
CREATE INDEX IF NOT EXISTS idx_occupier ON exhibitions(occupier_uid, occupier_star_id);
CREATE INDEX IF NOT EXISTS idx_expire ON exhibitions(expire_at);
-- 外键约束
ALTER TABLE exhibitions
ADD CONSTRAINT fk_exhibitions_asset FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_exhibitions_slot FOREIGN KEY (slot_id) REFERENCES booth_slots(slot_id) ON DELETE CASCADE;
-- ============================================
-- 注释说明
-- ============================================
COMMENT ON TABLE stars IS '明星信息表';
COMMENT ON TABLE users IS '用户表';
COMMENT ON TABLE fan_profiles IS '粉丝档案表';
COMMENT ON TABLE assets IS '资产表(藏品)';
COMMENT ON TABLE mint_orders IS '铸造订单表';
COMMENT ON TABLE asset_likes IS '点赞记录表';
COMMENT ON TABLE friendships IS '好友关系表';
COMMENT ON TABLE friend_requests IS '好友请求表';
COMMENT ON TABLE booth_slots IS '展位表';
COMMENT ON TABLE exhibitions IS '展品展示表';
-- ============================================
-- 11. activities 表 - 运营活动表
-- ============================================
CREATE TABLE IF NOT EXISTS activities (
id BIGSERIAL PRIMARY KEY,
activity_type VARCHAR(50) NOT NULL, -- 活动类型: birthday/concert/bus
title VARCHAR(100) NOT NULL, -- 活动标题
description TEXT, -- 活动描述
star_id BIGINT NOT NULL, -- 所属明星
start_time BIGINT NOT NULL, -- 开始时间 (毫秒时间戳)
end_time BIGINT NOT NULL, -- 结束时间 (毫秒时间戳)
target_progress BIGINT NOT NULL DEFAULT 1000, -- 目标进度
current_progress BIGINT NOT NULL DEFAULT 0, -- 当前进度
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/active/completed/expired
stage_configs JSONB, -- 阶段配置 (不同进度的背景图等)
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_activities_star_id ON activities(star_id);
CREATE INDEX IF NOT EXISTS idx_activities_status ON activities(status);
CREATE INDEX IF NOT EXISTS idx_activities_start_end ON activities(start_time, end_time);
-- 12. activity_items 表 - 活动道具表 (数据库配置,支持运营平台动态调整)
CREATE TABLE IF NOT EXISTS activity_items (
id BIGSERIAL PRIMARY KEY,
activity_id BIGINT NOT NULL,
item_type VARCHAR(50) NOT NULL, -- 道具类型: firework/megaphone/love
item_name VARCHAR(50) NOT NULL, -- 道具名称
icon_url VARCHAR(500), -- 道具图标
crystal_cost INTEGER NOT NULL, -- 水晶消耗
contribution_points INTEGER NOT NULL, -- 贡献点奖励
sort_order INTEGER NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_activity_items_activity ON activity_items(activity_id);
CREATE INDEX IF NOT EXISTS idx_activity_items_type ON activity_items(item_type);
-- 13. activity_contributions 表 - 用户活动贡献记录表
CREATE TABLE IF NOT EXISTS activity_contributions (
id BIGSERIAL PRIMARY KEY,
activity_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
item_type VARCHAR(50) NOT NULL,
quantity INTEGER NOT NULL DEFAULT 1,
crystal_spent BIGINT NOT NULL,
contribution_points BIGINT NOT NULL,
created_at BIGINT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_activity_contributions_activity ON activity_contributions(activity_id);
CREATE INDEX IF NOT EXISTS idx_activity_contributions_user_star ON activity_contributions(user_id, star_id);
CREATE INDEX IF NOT EXISTS idx_activity_contributions_created ON activity_contributions(created_at DESC);
-- 14. activity_user_stats 表 - 用户活动贡献汇总表 (用于排行榜)
CREATE TABLE IF NOT EXISTS activity_user_stats (
id BIGSERIAL PRIMARY KEY,
activity_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
total_contribution BIGINT NOT NULL DEFAULT 0,
total_crystal_spent BIGINT NOT NULL DEFAULT 0,
total_items INTEGER NOT NULL DEFAULT 0,
last_contribute_at BIGINT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_activity_user_star UNIQUE (activity_id, user_id, star_id)
);
CREATE INDEX IF NOT EXISTS idx_activity_user_stats_activity ON activity_user_stats(activity_id);
CREATE INDEX IF NOT EXISTS idx_activity_user_stats_contribution ON activity_user_stats(activity_id, total_contribution DESC);
CREATE INDEX IF NOT EXISTS idx_activity_user_stats_user_star ON activity_user_stats(user_id, star_id);
-- 外键约束
ALTER TABLE activity_items
ADD CONSTRAINT fk_activity_items_activity FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE;
ALTER TABLE activity_contributions
ADD CONSTRAINT fk_activity_contributions_activity FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_activity_contributions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_activity_contributions_item FOREIGN KEY (item_id) REFERENCES activity_items(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_activity_contributions_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
ALTER TABLE activity_user_stats
ADD CONSTRAINT fk_activity_user_stats_activity FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_activity_user_stats_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_activity_user_stats_star FOREIGN KEY (star_id) REFERENCES stars(star_id) ON DELETE CASCADE;
-- 注释说明
COMMENT ON TABLE activities IS '运营活动表';
COMMENT ON TABLE activity_items IS '活动道具表';
COMMENT ON TABLE activity_contributions IS '用户活动贡献记录表';
COMMENT ON TABLE activity_user_stats IS '用户活动贡献汇总表';