# SERVICES KNOWLEDGE BASE

**Target:** `backend/app/services/`
**Context:** Central business logic, 7+ specialized services, LLM integration.

## OVERVIEW

Core logic hub transforming raw music data into metrics, playlists, and AI narratives.

- **Data Ingress/Egress**: `SpotifyClient` (OAuth/Player), `GeniusClient` (Lyrics), `ReccoBeatsClient` (Audio Features).
- **Analytics**: `StatsService` (HHI, Gini, clustering, heatmaps, skip detection).
- **AI/Narrative**: `NarrativeService` (LLM prompt engineering, multi-provider support), `AIService` (Simple Gemini analysis).
- **Orchestration**: `PlaylistService` (AI-curated dynamic playlist generation).

## WHERE TO LOOK

| Service | File | Key Responsibilities |
|---------|------|----------------------|
| **Analytics** | `stats_service.py` | Metrics (Volume, Vibe, Time, Taste, LifeCycle). |
| **Spotify** | `spotify_client.py` | Auth, Player API, Playlist CRUD. |
| **Narrative** | `narrative_service.py` | LLM payload shaping, system prompts, JSON parsing. |
| **Playlists** | `playlist_service.py` | Periodic curation logic (6h/24h cycles). |
| **Enrichment** | `reccobeats_client.py` | External audio features (energy, valence). |
| **Lyrics** | `genius_client.py` | Song/Artist metadata & lyrics search. |

## CONVENTIONS

- **Async Everywhere**: All external API clients (`Spotify`, `ReccoBeats`) use `httpx.AsyncClient`.
- **Stat Modularization**: `StatsService` splits logic into `compute_X_stats` methods; returns serializable dicts.
- **Provider Agnostic AI**: `NarrativeService` detects `OPENAI_API_KEY` vs `GEMINI_API_KEY` automatically.
- **Payload Shaping**: AI services aggressively prune stats JSON before sending to LLM to save tokens.
- **Fallbacks**: All AI/External calls have explicit fallback/empty return states.

## ANTI-PATTERNS

- **Blocking I/O**: `GeniusClient` is synchronous; avoid calling in hot async paths.
- **Service Circularity**: `PlaylistService` depends on `StatsService`. Avoid reversing this.
- **N+1 DB Hits**: Aggregations in `StatsService` should use `joinedload` or batch queries.
- **Missing Checksums**: Audio features assume presence; always check for `None` before math.
- **Token Waste**: Never pass raw DB models to `NarrativeService`; use shaped dicts.
