-- ============================================= -- Wei AI App - Supabase 数据库初始化脚本 -- 版本: 1.0.0 -- 日期: 2026-01-28 -- ============================================= -- 1. 创建分类表 (categories) -- 用于 Discovery 页面的筛选标签 CREATE TABLE IF NOT EXISTS categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), code TEXT NOT NULL UNIQUE, -- 分类代码: all, gentle, dom, wild 等 label TEXT NOT NULL, -- 显示名称: 全部, 温柔治愈 等 sort_order INTEGER DEFAULT 0, -- 排序顺序 is_active BOOLEAN DEFAULT true, -- 是否启用 created_at TIMESTAMPTZ DEFAULT now() ); -- 2. 创建标签表 (tags) -- 角色的标签,如 "温顺", "调教", "治愈" 等 CREATE TABLE IF NOT EXISTS tags ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL UNIQUE, -- 标签名称 category_id UUID REFERENCES categories(id) ON DELETE SET NULL, -- 关联分类(可选) color TEXT, -- 标签颜色(可选,HEX 格式) created_at TIMESTAMPTZ DEFAULT now() ); -- 3. 创建角色表 (characters) -- 核心表:存储 AI 角色信息 CREATE TABLE IF NOT EXISTS characters ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- 基本信息 name TEXT NOT NULL, -- 角色名称 tagline TEXT, -- 角色标语/副标题 avatar_path TEXT, -- Storage 中的头像路径 description TEXT, -- 角色描述 -- 状态信息 compatibility REAL DEFAULT 0, -- 契合度 (0-100) status TEXT DEFAULT 'online', -- 状态: online, busy, offline is_locked BOOLEAN DEFAULT false, -- 是否锁定(会员限定) is_active BOOLEAN DEFAULT true, -- 是否上架显示 sort_order INTEGER DEFAULT 0, -- 排序顺序 -- AI 配置 ai_system_prompt TEXT, -- AI 系统提示词(人设 Prompt) ai_greeting TEXT, -- AI 第一句问候语 ai_personality JSONB DEFAULT '{}', -- AI 性格配置 ai_voice_config JSONB DEFAULT '{}', -- 语音配置 -- 时间戳 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 4. 创建角色-标签关联表 (character_tags) CREATE TABLE IF NOT EXISTS character_tags ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE, sort_order INTEGER DEFAULT 0, -- 标签在角色卡片上的显示顺序 -- 唯一约束:一个角色不能有重复标签 UNIQUE(character_id, tag_id) ); -- ============================================= -- 创建索引以提升查询性能 -- ============================================= CREATE INDEX IF NOT EXISTS idx_categories_sort ON categories(sort_order); CREATE INDEX IF NOT EXISTS idx_categories_active ON categories(is_active); CREATE INDEX IF NOT EXISTS idx_tags_category ON tags(category_id); CREATE INDEX IF NOT EXISTS idx_characters_active ON characters(is_active); CREATE INDEX IF NOT EXISTS idx_characters_locked ON characters(is_locked); CREATE INDEX IF NOT EXISTS idx_characters_status ON characters(status); CREATE INDEX IF NOT EXISTS idx_characters_sort ON characters(sort_order); CREATE INDEX IF NOT EXISTS idx_character_tags_character ON character_tags(character_id); CREATE INDEX IF NOT EXISTS idx_character_tags_tag ON character_tags(tag_id); -- ============================================= -- 创建更新时间触发器 -- ============================================= CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ language 'plpgsql'; CREATE TRIGGER update_characters_updated_at BEFORE UPDATE ON characters FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================= -- 创建 RLS (Row Level Security) 策略 -- 暂时允许所有人读取,后续可以根据需求修改 -- ============================================= ALTER TABLE categories ENABLE ROW LEVEL SECURITY; ALTER TABLE tags ENABLE ROW LEVEL SECURITY; ALTER TABLE characters ENABLE ROW LEVEL SECURITY; ALTER TABLE character_tags ENABLE ROW LEVEL SECURITY; -- 允许匿名用户读取所有数据 CREATE POLICY "Allow public read access on categories" ON categories FOR SELECT USING (true); CREATE POLICY "Allow public read access on tags" ON tags FOR SELECT USING (true); CREATE POLICY "Allow public read access on characters" ON characters FOR SELECT USING (is_active = true); CREATE POLICY "Allow public read access on character_tags" ON character_tags FOR SELECT USING (true); -- ============================================= -- 创建视图:角色完整信息(包含标签) -- ============================================= CREATE OR REPLACE VIEW characters_with_tags AS SELECT c.*, COALESCE( jsonb_agg( jsonb_build_object( 'id', t.id, 'name', t.name, 'color', t.color ) ORDER BY ct.sort_order ) FILTER (WHERE t.id IS NOT NULL), '[]'::jsonb ) as tags FROM characters c LEFT JOIN character_tags ct ON c.id = ct.character_id LEFT JOIN tags t ON ct.tag_id = t.id WHERE c.is_active = true GROUP BY c.id ORDER BY c.sort_order, c.created_at; COMMENT ON TABLE categories IS '分类筛选表 - Discovery 页面的筛选选项'; COMMENT ON TABLE tags IS '标签表 - 角色的标签'; COMMENT ON TABLE characters IS '角色表 - AI 角色信息和配置'; COMMENT ON TABLE character_tags IS '角色-标签关联表';