-- TTS 생성 실패 진단 이벤트 (2026-05-20) -- -- 문제: 오류 신고(error_reports)는 클라이언트 측 데이터(route/스크린샷/turn_logs)만 담아 -- TTS 가 "왜" 실패했는지(워커 OOM/토큰 loop/ICL 실패 등)는 못 본다. 그 root cause 는 -- 그 시점 그 워커(vast.ai GPU)의 로그에만 남는데, 워커 로그는 인스턴스 휘발성(destroy 시 소실) -- 이고 신고와 연결할 correlation 도 없었다. -- -- 해결: TTS 실패를 백엔드/워커 양쪽에서 중앙 테이블로 기록. -- - source='backend' : 디스패처가 워커 에러 응답을 감지 (worker_url + 상태/detail) -- - source='worker' : 워커가 생성 예외 traceback 을 POST (인스턴스 죽어도 보존) -- - trace_id 로 두 행 연결. 오류 신고 조회 시 user_id + 시간창으로 join. -- -- 회귀 가드: 이 테이블 insert 는 전부 fire-and-forget(실패 무시) — TTS 핫패스 영향 0. -- user_id 는 TEXT(FK 없음) — 익명/탈퇴 사용자에서도 기록이 거부되지 않도록. CREATE TABLE IF NOT EXISTS public.tts_error_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), trace_id TEXT, -- 백엔드 행 ↔ 워커 행 연결 키 user_id TEXT, -- FK 없음 (기록 거부 회피) session_id TEXT, block_id INTEGER, worker_url TEXT, -- 어느 워커가 처리했는지 (vast.ai 호스트) engine TEXT, -- qwen3 / cosyvoice35 mode TEXT, -- custom_voice / voice_clone status_code INTEGER, -- 워커 HTTP 상태 (backend 감지 시) error_detail TEXT, -- 짧은 에러 메시지 (backend 가 받은 detail) error_trace TEXT, -- 풀 traceback (worker 가 POST) source TEXT NOT NULL DEFAULT 'backend', -- 'backend' | 'worker' created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_tts_error_events_created ON public.tts_error_events (created_at DESC); CREATE INDEX IF NOT EXISTS idx_tts_error_events_user ON public.tts_error_events (user_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_tts_error_events_trace ON public.tts_error_events (trace_id);