release / govulncheck (push) Successful in 17s
release / web (push) Successful in 1m33s
release / go (push) Successful in 1m49s
release / integration (push) Successful in 5m42s
release / android (push) Successful in 5m59s
release / Build signed APK (releases and dev) (push) Successful in 6m9s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
Applies rule 32's migration exception: each header still says what the schema was, what changes and what it prevents, but task, milestone, decision and rule ids are replaced by the practice they stood for, the operator quotes by the decision, single-install counts are dropped, and pointers to a deleted package and an external design doc are gone. golang-migrate keeps no checksum, so editing applied migrations' comments is safe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
42 lines
1.8 KiB
SQL
42 lines
1.8 KiB
SQL
-- 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 an admin 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; a new value means swapping the constraint
|
|
-- in the same migration as the code that writes it.
|
|
|
|
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);
|