feat(research): add GET /api/research/track/stats — per-track Songstats stats

Merged
SW
5mo ago
+357-0

Implements recoupable/chat#1789 (api step) against the docs#236 contract. Pairs with recoupable/docs#236 (merge docs first).

Adds GET /api/research/track/stats — per-track, per-source current stats (incl. absolute streams_total) so agents can attribute streams to specific recordings. Today /api/research/metrics is artist-level only and /api/research/track(s) return metadata without stream counts.

Design — thin passthrough, not new infra

  • Resolution: isrc (or songstats_track_id / spotify_track_id / apple_music_track_id); source required (comma list or all); optional with_playlists/charts/stations/videos/links, only_current, limit, offset forwarded 1:1 to Songstats enterprise/v1/tracks/stats.
  • Reuses the existing fetchSongstats client (enterprise apikey server-side via SONGSTATS_API_KEY, never echoed) and the research validate → handler → successResponse shape. Response mirrors /api/research/metrics ({ status, result, message, stats:[{source,data}], track_info }).
  • Auth + credits identical to other /api/research/* endpoints: validateAuthContext (401), ensureResearchCredits gate, 5-credit deduction on a successful read. No database change.

Files

  • app/api/research/track/stats/route.ts (GET + OPTIONS)
  • lib/research/validateGetResearchTrackStatsRequest.ts · getResearchTrackStats.ts · getResearchTrackStatsHandler.ts

Tests (TDD, red→green)

validate (5), getResearchTrackStats (2), handler (3) — 10 new, all green; full lib/research suite 151/151 (no regressions); tsc + lint clean.

Test plan (preview, per #1789 Done-when)

  • ?isrc=USQY51771120&source=spotify → 200 with stats[0].data.streams_total integer (Mac Miller — K.I.D.S.).
  • source=all → one stats[] per source; resolving by songstats_track_id/spotify_track_id works equivalently.
  • 401 without a valid key; SONGSTATS_API_KEY never echoed.
  • Sum of K.I.D.S. per-track streams_total ≪ artist-level streams_total (~19.9B).

🤖 Generated with Claude Code


Summary by cubic

Adds GET /api/research/track/stats to return per-track, per-source Songstats current stats, including streams_total, so agents can attribute streams to specific recordings. This is a thin passthrough and reuses existing auth and credit rules.

  • New Features

    • Resolve by isrc, songstats_track_id, spotify_track_id, or apple_music_track_id; source is required. Optional with_*, only_current, limit, and offset are forwarded 1:1.
    • Response mirrors /api/research/metrics ({ status, result, message, stats:[{ source, data }], track_info }); includes CORS OPTIONS.
    • Reuses fetchSongstats; same auth and credits as other research endpoints with a 5-credit deduction on successful 200. No database changes.
  • Bug Fixes

    • Validator now enforces exactly one track identifier; returns 400 if multiple are provided (per docs#236).