CREATE TABLE IF NOT EXISTS viewer_accounts ( scope TEXT NOT NULL, room_id TEXT NOT NULL, uid TEXT NOT NULL, display_name TEXT NOT NULL, points INTEGER NOT NULL DEFAULT 0 CHECK(points >= 0), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY(scope, room_id, uid) ); CREATE TABLE IF NOT EXISTS point_ledger ( id UUID PRIMARY KEY, scope TEXT NOT NULL, room_id TEXT NOT NULL, uid TEXT NOT NULL, delta INTEGER NOT NULL, reason TEXT NOT NULL, source_event_id TEXT UNIQUE, metadata JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS wheel_spins ( id UUID PRIMARY KEY, scope TEXT NOT NULL, room_id TEXT NOT NULL, uid TEXT NOT NULL, category TEXT NOT NULL, song_id INTEGER NOT NULL, song_title TEXT NOT NULL, fallback BOOLEAN NOT NULL, cost INTEGER NOT NULL, balance_after INTEGER NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS viewer_accounts_name_idx ON viewer_accounts(scope, room_id, display_name); CREATE INDEX IF NOT EXISTS point_ledger_recent_idx ON point_ledger(scope, room_id, created_at DESC); CREATE TABLE IF NOT EXISTS live_session_outbox ( id BIGSERIAL PRIMARY KEY, streamer_uid BIGINT NOT NULL, event_ts_ms BIGINT NOT NULL, payload BYTEA NOT NULL, retry_count INTEGER NOT NULL DEFAULT 0, next_retry_at_ms BIGINT NOT NULL ); CREATE INDEX IF NOT EXISTS live_session_outbox_due_idx ON live_session_outbox(next_retry_at_ms, id);