CREATE TABLE IF NOT EXISTS photos_galleries ( id uuid PRIMARY KEY, slug varchar(160) NOT NULL UNIQUE, title varchar(200) NOT NULL, title_es varchar(200), description text, description_es text, event_id uuid, visibility varchar(10) NOT NULL DEFAULT 'private' CHECK (visibility IN ('public','private','link','ticket')), share_token varchar(64) NOT NULL UNIQUE, cover_photo_id uuid, created_by uuid, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL ); CREATE INDEX IF NOT EXISTS photos_galleries_event_idx ON photos_galleries (event_id); CREATE INDEX IF NOT EXISTS photos_galleries_visibility_idx ON photos_galleries (visibility); CREATE TABLE IF NOT EXISTS photos_photos ( id uuid PRIMARY KEY, gallery_id uuid NOT NULL REFERENCES photos_galleries(id) ON DELETE CASCADE, position integer NOT NULL DEFAULT 0, original_key text NOT NULL, original_filename text, content_type varchar(50) NOT NULL, size_bytes bigint NOT NULL, width integer, height integer, thumb_key text, preview_key text, taken_at timestamptz, status varchar(12) NOT NULL DEFAULT 'queued' CHECK (status IN ('queued','processing','ready','failed')), attempts integer NOT NULL DEFAULT 0, next_attempt_at timestamptz NOT NULL, last_error text, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL ); CREATE INDEX IF NOT EXISTS photos_photos_gallery_pos_idx ON photos_photos (gallery_id, position); CREATE INDEX IF NOT EXISTS photos_photos_queue_idx ON photos_photos (status, next_attempt_at) WHERE status IN ('queued','failed');