release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m43s
release / integration (push) Successful in 4m56s
release / android (push) Successful in 5m16s
release / Build signed APK (releases and dev) (push) Successful in 5m27s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
- A failed scan run sends scan_failed. Each failure adds to the count and the notice shows the latest error. A scan cut short by shutdown says nothing. - Marking tracks missing sends tracks_missing with a running count. - A duplicate sweep that proposes a group it had not proposed before sends duplicates_found, counting everything awaiting review. A sweep that only re-finds known groups stays quiet, so a read notice isn't repeated every sweep (CountDuplicateGroupsDetectedSince). - A playback-error report sends playback_errors, counting the unresolved errors (CountUnresolvedPlaybackErrors). The library package gets its notifier as a package-level SetNotifier beside SetEventBus, for the same reason the bus is package-level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.7 KiB
SQL
67 lines
2.7 KiB
SQL
-- name: InsertPlaybackError :one
|
|
-- Records a client-reported playback failure. The handler validates
|
|
-- the kind enum before this runs; the CHECK constraint is a
|
|
-- belt-and-braces guard.
|
|
INSERT INTO playback_errors (track_id, user_id, client_id, kind, detail)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING id, track_id, user_id, client_id, kind, detail, occurred_at,
|
|
resolved_at, resolved_by, resolution;
|
|
|
|
-- name: ListAdminPlaybackErrors :many
|
|
-- Admin inbox query. Returns one row per playback_errors row joined
|
|
-- with track / album / artist metadata so the SPA can render without
|
|
-- a second round-trip. Filter by resolved status via the sqlc.arg —
|
|
-- pass true for the Resolved tab, false for Unresolved (the default).
|
|
SELECT
|
|
pe.id AS id,
|
|
pe.track_id AS track_id,
|
|
pe.user_id AS user_id,
|
|
u.username AS username,
|
|
pe.client_id AS client_id,
|
|
pe.kind AS kind,
|
|
pe.detail AS detail,
|
|
pe.occurred_at AS occurred_at,
|
|
pe.resolved_at AS resolved_at,
|
|
pe.resolution AS resolution,
|
|
t.title AS track_title,
|
|
t.file_path AS track_file_path,
|
|
ar.name AS artist_name,
|
|
al.title AS album_title,
|
|
al.id AS album_id
|
|
FROM playback_errors pe
|
|
JOIN users u ON u.id = pe.user_id
|
|
JOIN tracks t ON t.id = pe.track_id
|
|
JOIN albums al ON al.id = t.album_id
|
|
JOIN artists ar ON ar.id = t.artist_id
|
|
WHERE (sqlc.arg(resolved_filter)::bool AND pe.resolved_at IS NOT NULL)
|
|
OR (NOT sqlc.arg(resolved_filter)::bool AND pe.resolved_at IS NULL)
|
|
ORDER BY pe.occurred_at DESC
|
|
LIMIT sqlc.arg(lim)::int OFFSET sqlc.arg(off)::int;
|
|
|
|
-- name: ResolvePlaybackError :one
|
|
-- Marks a single error resolved. Idempotent over (id, resolution) —
|
|
-- a second resolve with the same resolution is a no-op rewrite. Returns
|
|
-- the row so the handler can echo it. The CHECK constraint enforces
|
|
-- the resolution enum.
|
|
UPDATE playback_errors
|
|
SET resolved_at = now(),
|
|
resolved_by = $2,
|
|
resolution = $3
|
|
WHERE id = $1
|
|
RETURNING id, track_id, user_id, client_id, kind, detail, occurred_at,
|
|
resolved_at, resolved_by, resolution;
|
|
|
|
-- name: ResolveAllPlaybackErrorsForTrack :execrows
|
|
-- Bulk-resolve every unresolved error for a track when an admin acts
|
|
-- on it from a non-inbox surface (existing quarantine flow, etc.).
|
|
-- Returns the affected row count so the caller can surface "N reports
|
|
-- auto-resolved" in the response if useful.
|
|
UPDATE playback_errors
|
|
SET resolved_at = now(),
|
|
resolved_by = $2,
|
|
resolution = $3
|
|
WHERE track_id = $1 AND resolved_at IS NULL;
|
|
|
|
-- name: CountUnresolvedPlaybackErrors :one
|
|
SELECT count(*)::bigint FROM playback_errors WHERE resolved_at IS NULL;
|