Skip to main content

Copyright Recommendations

Copyright Recommendations are user-submitted suggestions that a specific track is copyright-safe and should be added to the curated safe-songs catalog. Users vote or flag a track via the streamer dashboard; those submissions land in this queue with report_type = recommendation. Admins accept (promoting the track to the safe catalog, optionally into a specific Curated Playlist) or dismiss (rejecting the suggestion).

Where to find it

Admin sidebar → Recommendations (/copyright-recommendations).

Quick start

  1. Open Admin → Recommendations.
  2. Default status filter is Pending; flip to Confirmed or Dismissed to review past decisions.
  3. Read the song / artist / category for each row.
  4. Click Accept to promote to safe songs. In the dialog, optionally pick a Curated Playlist to drop the track into.
  5. Click Dismiss to reject the suggestion.

Detailed walkthrough

Status filters

A pill bar across the top: All, Pending, Confirmed, Dismissed. Pending is the default landing state. A \{N\} total counter sits at the right end of the bar; the list loads 50 rows at a time with no pagination controls.

Recommendation cards

Recommendations render as cards, not table rows. Each card shows:

  • Song — track title, with an external-link icon to open.spotify.com/track/… when a Spotify track ID is present.
  • Artist — track artist.
  • Category — the recommendation_category value, as an outline badge, when set.
  • Status — coloured badge.
  • Confirmations\{N\} confirmations, the count of other users who upvoted the same recommendation.

Card actions, rendered only while the status is pending:

  • Accept — opens the Accept Recommendation dialog.
  • Dismiss — one-click reject.

Accept Recommendation dialog

  • Title: "Accept Recommendation".
  • Song name, artist, and the outcome hint "Will be added to global safe list".
  • Add to curated playlist (optional) — dropdown of all curated playlists; default is None. Rendered only when at least one curated playlist exists.
  • Accept — runs the shared approve mutation with the optional addToPlaylistId.

Accepting inserts the track into the safe-songs catalog and, when a playlist is selected, also appends it to that playlist's track list.

Common scenarios

  • Lo-fi track submitted by community — accept and route into the lofi curated playlist.
  • Obvious copyrighted track mis-recommended — dismiss; the recommendation moves to the Dismissed tab.
  • Duplicate suggestions — the Confirmations column reveals how many users agree. Don't accept the same track twice; the second recommendation can be dismissed.
  • Batch processing — cycle through Pending, decide one by one. There is no bulk action.
  • Filter state is not in the URL — it lives in React state and resets on reload.

Permissions

ActionPermission
View recommendationscopyright:read
Accept / dismisscopyright:moderate

copyright:moderate governs the global, cross-account safe/blocked lists and is distinct from copyright:edit. Dashboard entry requires admin:access. System admins implicitly hold both.

API

Recommendations share the copyright_reports table with copyright reports, distinguished by the report_type column (recommendation vs copyright). They use the same approve / dismiss mutations as reports.

This surface is GraphQL-first. There are no /v1/copyright/recommendations or /v1/copyright/reports* REST endpoints — the paths below are the admin app's own Next.js proxy routes.

UI actionGraphQLAdmin proxy route
List recommendations (filtered)adminReports(reportType: "recommendation", status, limit, offset)GET /api/copyright/recommendations?status=...
Accept (with optional playlist)approveReport(id, addToPlaylistId)POST /api/copyright/reports/\{id\}/approve
DismissdismissReport(id)POST /api/copyright/reports/\{id\}/dismiss
Curated playlists for the dropdownpublicSystemPlaylistsGET /api/copyright/playlists

The page is server-rendered: page.tsx runs the adminReports and publicSystemPlaylists queries through serverGqlSSR and hands the results to the client list, which refetches through the proxy whenever the status filter changes.

Tips & gotchas

  • Accept is destructive-ish — the track enters the global safe catalog. Review the artist + track carefully.
  • The playlist dropdown is optional, and disappears entirely when no curated playlists exist. Accepting without picking a playlist still promotes the track to the catalog; it just doesn't appear in any curated playlist yet.
  • Dismissed recommendations can be re-submitted by the same user later. The UI does not dedupe across time.
  • Reports and recommendations share one mutation; accepting a recommendation is implemented as approveReport internally.