CREATE TABLE workflow_runs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), album_id UUID NOT NULL REFERENCES albums(id) ON DELETE CASCADE, quality VARCHAR(20) NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'running', error_message TEXT, started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), running_lock BOOLEAN GENERATED ALWAYS AS (CASE WHEN status = 'running' THEN TRUE ELSE NULL END) STORED, CONSTRAINT idx_workflow_runs_active UNIQUE (album_id, quality, running_lock) ); CREATE INDEX idx_workflow_runs_status ON workflow_runs(status); CREATE TABLE album_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), seq BIGSERIAL NOT NULL, workflow_run_id UUID NOT NULL REFERENCES workflow_runs(id) ON DELETE CASCADE, album_id UUID NOT NULL, event_type VARCHAR(20) NOT NULL, step VARCHAR(50) NOT NULL, message TEXT NOT NULL, data_json JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_album_events_workflow ON album_events(workflow_run_id); CREATE INDEX idx_album_events_album ON album_events(album_id); CREATE INDEX idx_album_events_seq ON album_events(seq); ALTER TYPE download_state ADD VALUE IF NOT EXISTS 'cancelled';