-- Client-reported playback errors. Populated by clients when a track -- fails to play (zero duration, decode error, etc.); surfaced in the -- admin /admin/playback-errors inbox so the operator can hide / delete -- / re-request the offending track. -- -- resolved_at + resolved_by + resolution are NULL until an admin acts -- on the row. Auto-resolved by the client when the admin clicks Hide / -- Delete / Re-request from the inbox row, with the resolution string -- recording which path was taken. The partial index keeps the -- unresolved-queue lookup fast even as resolved history accumulates. -- -- CHECK constraints on kind/resolution gate the enum values so client -- typos can't pollute the data (per the standing rule about -- enum-CHECK whitelists needing migrations). CREATE TABLE playback_errors ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), track_id uuid NOT NULL REFERENCES tracks(id) ON DELETE CASCADE, user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, client_id text NOT NULL, kind text NOT NULL, detail text, occurred_at timestamptz NOT NULL DEFAULT now(), resolved_at timestamptz, resolved_by uuid REFERENCES users(id), resolution text, CONSTRAINT playback_errors_kind_check CHECK (kind IN ('zero_duration', 'load_failed', 'stalled')), CONSTRAINT playback_errors_resolution_check CHECK (resolution IS NULL OR resolution IN ('hidden', 'deleted', 'requested', 'fixed', 'ignored')), CONSTRAINT playback_errors_resolved_consistency CHECK ((resolved_at IS NULL) = (resolution IS NULL)) ); CREATE INDEX idx_playback_errors_unresolved ON playback_errors (occurred_at DESC) WHERE resolved_at IS NULL; CREATE INDEX idx_playback_errors_track ON playback_errors (track_id);