Skip to content

feat(api): collaborative tracks — notifications, embed, profile + dashboard merge#932

Open
raymondjacobson wants to merge 2 commits into
mainfrom
claude/collab-api
Open

feat(api): collaborative tracks — notifications, embed, profile + dashboard merge#932
raymondjacobson wants to merge 2 commits into
mainfrom
claude/collab-api

Conversation

@raymondjacobson

Copy link
Copy Markdown
Member

Phase 2 of collaborative tracks (the api slice). Consumes the ETL TrackCollaborator entity (go-openaudio #345 / #346) and surfaces it through the API. Ships inert — nothing emits the on-chain invites/accepts until the client work lands, so this is safe to deploy dark.

Recap

A track owner tags collaborator artists (in track metadata); each must accept (pending → accepted). Accepted collaborators get the track on their profile and merged into their dashboard analytics. Scope is display + analytics only — no revenue split, no edit rights.

What's here

Table + notifications

  • ddl/migrations/0220_track_collaborators.sql mirrors the ETL table with CREATE TABLE IF NOT EXISTS (byte-compatible with go-openaudio migration 0033). It runs in the migrations/ pass, before functions/, so the trigger always has its table regardless of ETL-indexer timing.
  • ddl/functions/handle_track_collaborator.sql — a trigger modeled on handle_manager_request.sql: a new pending invite notifies the collaborator (track_collaborator_invite); a transition to accepted notifies the inviter/owner (track_collaborator_accept).
  • Both types added to the notifications request whitelist.

Read path

  • Track responses now carry a collaborators array (accepted only), bulk-resolved in a single indexed query folded into the existing user fetch — no N+1.
  • GET /users/:id/tracks UNIONs the user's owned tracks with tracks they've accepted a credit on, preserving sort/pagination. The artist-pick pin now references the profile user, so a collaborator's track is never spuriously pinned by the owner's pick.

Dashboard

  • GET /users/:id/listen_counts_monthly widens to include co-owned tracks (engagement analytics).
  • The dashboard track table is powered by GET /users/:id/tracks, so it merges automatically.
  • Sales/revenue intentionally left scoped to the seller — collaborators don't share revenue (per the no-split scope). Easy to widen later if desired; flagging for a decision.

New endpoint

  • GET /users/:id/collaboration_invites?status=pending|accepted|rejected lists a user's invites/credits with the inviter embedded as a user object (mirrors /managers). Powers the client's accept/decline UX.

Performance

  • The collaborators embed is one extra indexed query per track-list response (returns 0 rows for the common no-collaborator case; backed by the track_collaborators PK). The profile UNION uses the covering (collaborator_user_id, status, track_id) index.
  • Every track response now includes a collaborators field (empty array when none) — a small, constant payload addition.

Tests

api/v1_track_collaborators_test.go: collaborators embedded on track responses, accepted credit appears on the collaborator's profile, pending invite stays hidden, the invites endpoint (status filter + validation), and the notification trigger firing for both invite and accept. Full ./api/ package suite passes.

Note: sql/01_schema.sql carries the table + trigger inline so fresh/test DBs have them; make test-schema (which needs an exclusive local pg) will canonicalize the placement on the next regen.

Next

Phase 3 (apps): SDK methods, upload tagging UI, push + in-app notifications, comma-separated artist line, dashboard — web + mobile, behind a flag.

🤖 Generated with Claude Code

… + dashboard merge

Consumes the ETL TrackCollaborator entity (go-openaudio #345/#346) to surface
collaborative tracks. Ships inert until clients write the on-chain invites and
accepts.

- Migration 0220 mirrors the ETL track_collaborators table (IF NOT EXISTS) so
  it exists before the functions/ pass; handle_track_collaborator.sql adds a
  notification trigger (invite -> collaborator, accept -> owner) modeled on the
  manager-request trigger.
- Track responses embed a `collaborators` array (accepted only), bulk-resolved
  in one query alongside the existing owner/user fetch.
- Profile track list (GET /users/:id/tracks) UNIONs owned + accepted-collab
  tracks, fixing the artist-pick pin to reference the profile user (so a
  collaborator's track is never spuriously pinned by the owner's pick).
- Dashboard monthly listens widen to co-owned tracks. Sales/revenue stays
  scoped to the seller (no revenue split, per the feature's scope).
- New GET /users/:id/collaboration_invites lists a user's invites/credits,
  optionally filtered by status.
- track_collaborator_invite / track_collaborator_accept added to the
  notifications type whitelist.

Bumps the ETL module to 3904b9d. sqlc regenerated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collect data.inviter_user_id and data.collaborator_user_id when resolving
notification-related users, so the track_collaborator_invite / _accept
notifications hydrate their user entities (mirrors grantee_user_id for
managers). Notification id hashing is already generic (HashifyJson).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant