| name | spotify-integration |
| description | Work on Spotify API, API routes, or Spotify UI. Use when modifying Spotify playback, playlists, profile, top artists/tracks, token refresh, normalization, or Spotify-related hooks and components. |
Spotify integration
Guidance for the Spotify feature (API, routes, hooks, and UI).
Server: client and cache
- Client: lib/spotify.ts —
SpotifyClient class (token refresh, retries, timeout, in-memory cache). Uses env: SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, SPOTIFY_REFRESH_TOKEN.
- OAuth: Refresh-token flow only; no user login on the site. Token is refreshed in
getAccessToken() when expired.
- Server-side dedup: All public getters are wrapped in React
cache() so the same request deduplicates within one RSC request:
getCurrentlyListening, getRecentlyPlayed, getTopArtists, getTopTracks, getUserProfile, getUserPlaylists, getUserPublicPlaylists(userId, limit, offset).
API routes
- Base path:
app/api/spotify/.
- Routes:
- Error handling: Routes that must return a safe payload on failure return 200 with a fallback body (e.g.
BadResponse for currently-listening). Use 503 for "Spotify not available" when appropriate. SWR fetchers must throw on non-ok so the client gets isError.
Normalization
- lib/utils/normalizers/index.ts — e.g.
normalizeCurrentlyListening, normalizeArtists, normalizeTracks. Use these before sending API responses so the client gets a stable shape.
Client: hooks and SWR
UI and dynamic loading
- Pages: app/spotify/page.tsx — Spotify page; uses Suspense and dynamic wrappers.
- Heavy components are loaded with
next/dynamic (skeleton as loading):
- Shared state: components/providers/ui-provider.tsx —
listening, recentlyPlayed, setSpotifyListening, setSpotifyRecentlyPlayed. Use for compact player and any component that shows "now playing" or "recently played" without refetching.
- Accessibility: Spotify player and dynamic content use
aria-live="polite" and sr-only for track announcements per project a11y standards.
Types
- types/spotify.ts — API and normalized types (e.g.
NormalizedSpotifyProfile, now-playing shape).
Adding a new endpoint or hook
- Add the method to
SpotifyClient in lib/spotify.ts if it calls Spotify API; wrap the public getter in cache().
- Add route under
app/api/spotify/; use normalizers for the response.
- Add or reuse a hook with SWR; throw in fetcher on
!res.ok and surface isError in UI.