-- TTS 스케일아웃 슬롯 테이블 (Supabase SQL Editor에서 실행) -- -- 사전 발급된 Cloudflare 터널 슬롯(tts4-tts10) + Vast.ai 인스턴스 매핑. -- 운영자가 admin 에서 "TTS 서버 추가" 누르면 free 슬롯 1개 가져와서 -- Vast.ai 에 새 인스턴스 만들고, 그 인스턴스에 슬롯의 cloudflared 자격증명 주입. CREATE TABLE IF NOT EXISTS public.tts_scale_instances ( -- Cloudflare 터널 슬롯 (사전 발급, 절대 안 바뀜) slot_name TEXT PRIMARY KEY, -- 'tts4', 'tts5', ... hostname TEXT NOT NULL, -- 'tts4.stylevoicetalk.com' tunnel_id TEXT NOT NULL, -- Cloudflare tunnel UUID credentials_json JSONB NOT NULL, -- cloudflared credentials (TunnelID/AccountTag/TunnelSecret) -- Vast.ai 인스턴스 매핑 (할당 시 채워짐) vast_instance_id BIGINT, -- 할당된 Vast 인스턴스 ID (NULL = free) vast_offer_id BIGINT, -- 검색 결과 ID (참조용) vast_dph DECIMAL(8,5), -- $/hour 비용 -- 상태 추적 -- 'free' / 'creating' / 'pulling' / 'starting' / 'ready' / 'warm_stopped' / 'destroying' / 'failed' status TEXT NOT NULL DEFAULT 'free', status_detail TEXT, -- 에러 메시지 등 is_warm BOOLEAN NOT NULL DEFAULT false, -- warm pool 멤버인지 (stopped 상태로 유지) assigned_at TIMESTAMPTZ, -- Vast 인스턴스 생성 시각 became_ready_at TIMESTAMPTZ, -- /health 200 도달 시각 released_at TIMESTAMPTZ, -- destroy 완료 시각 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 빈 슬롯 빠르게 찾기 CREATE INDEX IF NOT EXISTS idx_tts_scale_status ON public.tts_scale_instances(status) WHERE status IN ('free', 'warm_stopped'); -- updated_at 자동 갱신 트리거 CREATE OR REPLACE FUNCTION public.set_updated_at_tts_scale() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trg_tts_scale_updated_at ON public.tts_scale_instances; CREATE TRIGGER trg_tts_scale_updated_at BEFORE UPDATE ON public.tts_scale_instances FOR EACH ROW EXECUTE FUNCTION public.set_updated_at_tts_scale(); -- RLS: service_role 만 접근 (관리자 전용 테이블) ALTER TABLE public.tts_scale_instances ENABLE ROW LEVEL SECURITY; -- (정책 추가 안 함 — service_role 은 RLS 우회. 일반 user 접근 0) -- 운영자 설정값 (warm pool toggle 등) — 단일 row 의 key/value CREATE TABLE IF NOT EXISTS public.system_settings ( key TEXT PRIMARY KEY, value JSONB NOT NULL, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 기본값 — warm pool 비활성, max_instances=8 (cap) INSERT INTO public.system_settings(key, value) VALUES ('tts_scale_warm_pool_enabled', 'false'::jsonb), ('tts_scale_max_instances', '8'::jsonb) ON CONFLICT (key) DO NOTHING; ALTER TABLE public.system_settings ENABLE ROW LEVEL SECURITY;