-- Sweepstakes/Lottery system -- Tables: sweepstakes, sweepstake_prizes, sweepstake_entries, sweepstake_winners -- Main sweepstakes table CREATE TABLE IF NOT EXISTS sweepstakes ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, title VARCHAR(255) NOT NULL, description TEXT, image_url VARCHAR(500), rules_url VARCHAR(500), start_at TIMESTAMPTZ NOT NULL, end_at TIMESTAMPTZ NOT NULL, status VARCHAR(16) NOT NULL DEFAULT 'draft', -- draft|scheduled|active|locked|finalized|archived picker_style VARCHAR(16) NOT NULL DEFAULT 'wheel', -- wheel|cycler total_prizes INTEGER NOT NULL DEFAULT 1, prize_summary TEXT, winners_selected_at TIMESTAMPTZ, visibility_until TIMESTAMPTZ, -- set to end_at + 3 days at finalize draw_seed VARCHAR(64), max_entries_per_user INTEGER NOT NULL DEFAULT 1 ); CREATE INDEX IF NOT EXISTS idx_sweepstakes_status ON sweepstakes(status); CREATE INDEX IF NOT EXISTS idx_sweepstakes_start ON sweepstakes(start_at); CREATE INDEX IF NOT EXISTS idx_sweepstakes_end ON sweepstakes(end_at); -- Prizes (per sweepstake) CREATE TABLE IF NOT EXISTS sweepstake_prizes ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, sweepstake_id BIGINT NOT NULL REFERENCES sweepstakes(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, description TEXT, image_url VARCHAR(500), value VARCHAR(255), quantity INTEGER NOT NULL DEFAULT 1, display_order INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX IF NOT EXISTS idx_prizes_sweepstake ON sweepstake_prizes(sweepstake_id); -- Entries (unique per user per sweepstake) CREATE TABLE IF NOT EXISTS sweepstake_entries ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, sweepstake_id BIGINT NOT NULL REFERENCES sweepstakes(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, status VARCHAR(16) NOT NULL DEFAULT 'valid', -- valid|invalid|withdrawn ip_hash VARCHAR(64), visual_played_at TIMESTAMPTZ, view_count INTEGER NOT NULL DEFAULT 0, UNIQUE (sweepstake_id, user_id) ); CREATE INDEX IF NOT EXISTS idx_entries_sweepstake ON sweepstake_entries(sweepstake_id); CREATE INDEX IF NOT EXISTS idx_entries_user ON sweepstake_entries(user_id); -- Winners (one per prize unit, unique winner per sweepstake) CREATE TABLE IF NOT EXISTS sweepstake_winners ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, sweepstake_id BIGINT NOT NULL REFERENCES sweepstakes(id) ON DELETE CASCADE, entry_id BIGINT NOT NULL REFERENCES sweepstake_entries(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, prize_id BIGINT REFERENCES sweepstake_prizes(id) ON DELETE SET NULL, prize_name VARCHAR(255), -- denormalized for safety announced_at TIMESTAMPTZ, notified_user_at TIMESTAMPTZ, notified_admin_at TIMESTAMPTZ, claim_status VARCHAR(16) NOT NULL DEFAULT 'pending', -- pending|claimed|delivered claim_note TEXT, UNIQUE (sweepstake_id, user_id) ); CREATE INDEX IF NOT EXISTS idx_winners_sweepstake ON sweepstake_winners(sweepstake_id); CREATE INDEX IF NOT EXISTS idx_winners_user ON sweepstake_winners(user_id);