Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 74 additions & 58 deletions docs/PRD.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Sona — Product Requirements Document

**Version:** 1.1
**Version:** 1.3
**Status:** Active
**Last Updated:** April 2026
**Author:** Liam Buckman
**Changelog:**

- v1.1: Removed audio features (Spotify deprecated Nov 2024); added Last.fm genre integration; updated Spotify field changes from Feb 2026 API changelog; noted Spotify development mode 25-user limit
- v1.2: Removed recently played; added guest AI interaction and rate limiting; updated goals and success metrics framing
- v1.3: Corrected Sprint 3 status — chat implemented as context-dump + streaming (not agentic tool use); agentic tool use deferred to post-v1; updated architecture summary and open questions accordingly

---

Expand Down Expand Up @@ -40,15 +42,15 @@ There is no tool that uses AI to make listening data feel personal, expressive,
- Deliver a polished, production-grade full-stack web application that solves a real user need and is publicly accessible
- Implement Spotify OAuth 2.0 (Authorization Code Flow) with secure, encrypted token management
- Surface key listening stats (top tracks, top artists, genre breakdown) in a clean, accessible portfolio-style layout where Sona's AI voice narrates each section
- Integrate an LLM (Claude Haiku 4.5) with an agentic tool-use architecture for the chat interface, enabling Claude to dynamically decide which user data to fetch based on the question
- Integrate an LLM (Claude Haiku 4.5) for personalized music insights, a music personality profile, and a conversational chat interface grounded in the user's Spotify data
- Allow unauthenticated (guest) users to interact with Sona's AI on the landing page with general music knowledge — no sign-in required unless personal data or account actions are needed
- Deploy publicly on Vercel with a live URL

### Secondary Goals

- Demonstrate exemplary repository practices: conventional commits, CI/CD via GitHub Actions, typed schema, Zod validation, documented architecture in `docs/`
- Serve as a learning vehicle for: Spotify OAuth, relational database design, LLM API integration, agentic AI patterns, prompt engineering, rate limiting, and caching strategies
- Build a foundation extensible to future features (playlist generation, social listening, shareable public profiles)
- Serve as a learning vehicle for: Spotify OAuth, relational database design, LLM API integration, prompt engineering, SSE streaming, rate limiting, and caching strategies
- Build a foundation extensible to future features (agentic tool use, playlist generation, social listening, shareable public profiles)

---

Expand All @@ -57,6 +59,7 @@ There is no tool that uses AI to make listening data feel personal, expressive,
- **No music playback** — Sona surfaces insights about music, it does not play it
- **No recently played data** — omitted to reduce API surface and token cost; Spotify natively displays this for users
- **No audio features** — Spotify deprecated this endpoint for new apps in November 2024; genre signals are derived from Last.fm instead
- **No agentic tool use in v1** — the chat interface uses a pre-built context dump rather than dynamic tool calls; true agentic tool use is a post-v1 enhancement (see Section 12)
- **No social features in v1** — friend comparisons, shared profiles, and listening rooms are post-v1
- **No Apple Music support** — Spotify-only for initial release
- **No mobile app** — web-only; responsive design supports mobile browsers
Expand Down Expand Up @@ -101,15 +104,16 @@ There is no tool that uses AI to make listening data feel personal, expressive,

#### F-03 · Protected Route Layout ✅

- All `/profile` and `/chat` routes require an active session
- All `/profile` routes require an active session
- Unauthenticated users are redirected to `/`
- Authenticated users visiting `/` are redirected to `/profile`
- `/chat` is accessible to guests with reduced functionality (general music intelligence only)

#### F-04 · Landing Page ✅ (placeholder — full design Sprint 4)

---

### Sprint 2 — Core Stats Data Layer ✅ (in progress)
### Sprint 2 — Core Stats Data Layer ✅

**Goal:** Authenticated users have real Spotify data available via typed, cached API routes.

Expand Down Expand Up @@ -140,81 +144,91 @@ There is no tool that uses AI to make listening data feel personal, expressive,
- `tracks` field renamed to `items` in Spotify's Feb 2026 changelog — updated
- Cached in DB (30-minute TTL)

#### F-09 · Guest AI Interaction (Landing Page) — Sprint 3

- Landing page hero input functional for unauthenticated users
- General music intelligence responses (no personal Spotify data)
- Contextual sign-in prompt when personal data is needed

#### F-10 · Profile Page UI — in progress
#### F-09 · Profile Page UI ✅

- TanStack Query provider and hooks
- Portfolio layout with real data sections
- Portfolio layout with Artists, Genre, Tracks, and Playlists sections
- Skeleton loading states per section
- Sticky nav with section anchors

---

### Sprint 3 — Sona AI Layer
### Sprint 3 — Sona AI Layer

**Goal:** Transform the stats portfolio into a genuinely intelligent experience.
**Goal:** Transform the stats portfolio into a genuinely intelligent experience using Claude Haiku 4.5.

#### F-11 · Sona Voice (Inline AI Narration)
#### F-10 · Sona Insights Card ✅

- Each portfolio section opens with a short Sona-written observation
- Generated from real user data; cached per section per day
- Tone: second person, specific, grounded in data, never generic
- Featured AI-generated 2–4 sentence daily insight at the top of the profile page
- Synthesizes top artists, genre breakdown, and listening patterns via pre-built context
- Cached per user per day (24-hour TTL in `ai_cache`)
- Skeleton loading state while generating

#### F-12 · Sona Insights Card
#### F-11 · Sona Profile (Music Personality) ✅

- Featured AI-generated summary at top of profile page, streamed live
- Synthesizes top artists, genre breakdown, and listening patterns
- Cached per user per day (24-hour TTL)
- Full AI-generated music personality profile (3–5 sentences)
- Assigns a named listening archetype (e.g. "The Devoted Follower")
- Cached with 7-day TTL; expires automatically
- Rendered in Sona's italic serif voice

#### F-13 · Sona Profile (Music Personality)
#### F-12 · Ask Sona — Chat Interface ✅

- Full AI-generated music personality profile
- Assigns a personality archetype
- Regeneratable once per 7 days; cached with 7-day TTL
- Dedicated `/chat` page accessible to both authenticated and guest users
- **Implementation note:** Chat uses a pre-built context dump approach — the user's full listening context (top tracks, top artists, genre breakdown) is assembled server-side and passed as a system prompt to Claude. Claude does not dynamically call tools to fetch data per-question in v1.
- Streaming responses via Server-Sent Events (SSE) — responses appear word-by-word in real time
- Multi-turn conversation history maintained client-side (server is stateless)
- Authenticated users receive personalized responses grounded in their Spotify data
- Guest users receive general music intelligence responses (no personal data)
- Input validation: message capped at 4,000 characters, history capped at 12 turns
- Suggested prompts shown before first message

#### F-14 · Sona Moods (Playlist Analysis)
#### F-13 · Sona Voice Prompt System ✅

- Classify playlists by mood using AI interpretation of names, track counts, and genre context
- Display as mood-tagged playlist cards
- Shared prompt templates enforcing Sona's tone: second person, data-grounded, slightly poetic
- Context wrapped in `<listening_data>` delimiters to prevent prompt injection
- Genre breakdown capped at 8 entries before serialization
- `server-only` guard on Anthropic client

#### F-15 · Ask Sona — Agentic Chat Interface
#### F-14 · Guest AI Interaction ✅ (partial)

- Dedicated `/chat` page with conversational interface
- Claude uses tool use to fetch only the data needed per question
- Available tools: `get_top_tracks`, `get_top_artists`, `get_genre_breakdown`, `get_playlist_moods`
- Floating shortcut button on profile page
- Guest version on landing page with general (non-personal) responses
- Chat page accessible without sign-in
- General music intelligence responses for guests
- Full landing page guest experience deferred to Sprint 4

---

### Sprint 4 — Polish, A11y & Deployment

#### F-15 · Landing Page with Guest AI Hero

- Suno-style hero input on landing page
- Guest can ask a music question and receive an AI response without signing in
- Contextual "Connect Spotify" prompt when personal data would improve the answer

#### F-16 · Guest Rate Limiting

- 10 AI requests per hour per IP via Upstash Redis at the Vercel Edge layer

#### F-17 · Responsive Design

- All views functional on mobile (≥ 375px), tablet (≥ 768px), and desktop
- Profile sections reflow gracefully at small widths

#### F-18 · Accessibility (A11y)

- Keyboard navigation, semantic HTML, ARIA labels, WCAG 2.1 AA contrast
- No motion for `prefers-reduced-motion`
- Screen reader testing on key flows

#### F-19 · Loading, Error & Empty States

- Skeleton loading states for all data-fetching components
- User-friendly error messages with retry
- Graceful empty states for first-time users
- User-friendly error messages with retry on all data sections
- Graceful empty states for first-time users with sparse data

#### F-20 · Vercel Deployment ✅

- Live at `https://sonamusic.vercel.app`
- Preview deployments on all PRs
- Preview deployments enabled for all PRs

#### F-21 · README & Documentation ✅

Expand All @@ -231,18 +245,18 @@ User Browser
Next.js 16 (App Router) — Vercel
├── / (landing) Public — guest AI interaction
├── / (landing) Public — guest AI interaction (Sprint 4)
├── /profile Protected — portfolio layout, AI narration
├── /chat Protectedagentic Ask Sona interface
├── /chat Publicchat (personalized if auth'd, general if guest)
├── /api/auth/* OAuth routes
├── /api/spotify/* Spotify data proxy (cached)
├── /api/lastfm/* Last.fm genre data (cached)
└── /api/ai/* AI generation + agentic chat
└── /api/ai/* AI generation + context-dump chat
├── Vercel Edge Middleware Guest rate limiting (Upstash Redis)
├── Vercel Edge Middleware Guest rate limiting (Upstash Redis) — Sprint 4
├── Spotify Web API OAuth 2.0 + top tracks/artists/playlists
├── Last.fm API Artist genre tags (artist.getTopTags)
├── Anthropic API Claude Haiku 4.5 with tool use
├── Anthropic API Claude Haiku 4.5 (context-dump, streaming SSE)
└── Neon Postgres Users, tokens, Spotify cache, AI cache
└── Drizzle ORM Type-safe queries + versioned migrations
```
Expand Down Expand Up @@ -310,45 +324,47 @@ ai_cache
**Product quality**

- All Sprint 1–3 features complete and functional with real Spotify data
- Guest AI interaction works without sign-in; rate limiting is enforced
- Guest chat works without sign-in; rate limiting enforced in Sprint 4
- Application loads within acceptable performance budgets
- Zero TypeScript errors or console errors in production build
- WCAG 2.1 AA accessibility compliance on all primary views

**Engineering quality**

- CI pipeline is green on `main` with every commit
- Codebase demonstrates: OAuth 2.0, AES-256-GCM encryption, DB caching with multiple TTLs, agentic LLM integration, multi-API orchestration, TypeScript strict mode, and edge rate limiting
- Codebase demonstrates: OAuth 2.0, AES-256-GCM encryption, DB caching with multiple TTLs, LLM integration with streaming SSE, multi-API orchestration, TypeScript strict mode, input validation, and edge rate limiting
- Conventional commit history is clean and readable as a project narrative
- `docs/` folder contains up-to-date PRD and system design document

---

## 11. Sprint Timeline

| Sprint | Focus | Status |
| -------- | ----------------------------------- | -------------- |
| Sprint 1 | Foundation, Auth, DB schema | ✅ Complete |
| Sprint 2 | Core Stats + Data Layer | 🔄 In Progress |
| Sprint 3 | Sona AI Layer | Upcoming |
| Sprint 4 | Polish, A11y, Rate Limiting, Deploy | Upcoming |
| Sprint | Focus | Status |
| -------- | ----------------------------------------- | ----------- |
| Sprint 1 | Foundation, Auth, DB schema | ✅ Complete |
| Sprint 2 | Core Stats + Data Layer + Profile UI | ✅ Complete |
| Sprint 3 | Sona AI Layer | ✅ Complete |
| Sprint 4 | Landing Page, Polish, A11y, Rate Limiting | 🔄 Next |

---

## 12. Post-v1 Roadmap

- **Agentic tool use for chat** — upgrade Ask Sona so Claude dynamically decides which data to fetch per question via tool calls (`get_top_tracks`, `get_top_artists`, `get_genre_breakdown`, `get_playlist_moods`), rather than receiving a full pre-built context dump. More efficient, more capable, better interview story.
- **Shareable public profile** (`/u/username`) — public URL for your music identity
- **Playlist generation with Spotify import** — AI-generated playlists pushed to Spotify
- **Social listening rooms** — real-time WebSocket sessions with AI commentary
- **Persistent chat history** — store conversations across sessions
- **Persistent chat history** — store conversations across sessions in the database
- **Apple Music support** — extend data pipeline beyond Spotify
- **Spotify quota extension** — apply for Extended Quota Mode to remove 25-user limit

---

## 13. Open Questions

- [ ] Should guest AI responses use a lighter model than authenticated responses?
- [ ] Should chat history be sent as part of the tool-use message array or maintained separately?
- [ ] Should the public profile page (post-v1) require explicit opt-in from the user?
- [ ] Should guest AI responses use a lighter/faster model than authenticated responses to reduce cost?
- [ ] When implementing agentic tool use (post-v1), should tool results be passed back into the message array or handled via a separate context assembly step?
- [ ] Should the public profile page (post-v1) require explicit opt-in from the user, or be opt-out?
- [ ] When should we apply for Spotify quota extension — before or after v1.0 launch?
- [ ] Should the chat history cap (currently 12 turns) be user-configurable in a future version?
Loading
Loading