Skip to content

Commit ea67f1b

Browse files
MVP: auth, matching, lineup page
1 parent c4b7f9f commit ea67f1b

15 files changed

Lines changed: 6157 additions & 0 deletions

CLAUDE.MD

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# CLAUDE.md — Spotifort Project Brief
2+
3+
## Project Overview
4+
5+
**Spotifort** is a client-side web application that matches a user's Spotify Liked Songs against the Treefort Music Fest 2026 lineup (March 25–29, Boise, Idaho). It identifies which artists the user already likes that are playing the festival.
6+
7+
- **Live site:** https://spotifort.com
8+
- **Repo:** https://github.com/commitconfirm/spotifort
9+
- **Project manager thread:** This project is managed via a dedicated Claude.ai chat thread. Architectural decisions, scope changes, and priorities are tracked there.
10+
11+
## Architecture & Constraints
12+
13+
### Client-Side Only — No Backend
14+
15+
This is a **privacy-first** application. All processing happens in the browser. There is no server, no database, no analytics, no cookies, no tracking. The Spotify access token lives in a JS variable in memory and is never persisted to localStorage, sessionStorage, or any storage API. When the user closes the tab, everything is gone.
16+
17+
### Spotify API — PKCE Auth Flow
18+
19+
- **Auth method:** Authorization Code with PKCE (no client secret)
20+
- **Scopes required:** `user-library-read` (for Liked Songs)
21+
- **Future scope:** `user-top-read` (for top artists feature in List B — not in MVP)
22+
- **Dev redirect URI:** `http://127.0.0.1:9090/callback`
23+
- **Prod redirect URI:** `https://spotifort.com/callback`
24+
- **Client ID:** Stored in `.env.local` as `VITE_SPOTIFY_CLIENT_ID` (not committed to repo)
25+
26+
### Spotify API Restrictions (February 2026 Dev Mode Changes)
27+
28+
Development Mode is limited to 5 authorized users. The app owner must have Spotify Premium. Key constraints:
29+
- Playlist items are only returned for playlists the user owns/collaborates on (cannot read the official Treefort Spotify playlist via API)
30+
- Several endpoints were removed (bulk metadata, new releases, etc.)
31+
- Still available and used by this project: `GET /me/tracks`, `GET /artists/{id}/related-artists`, `GET /me/top/artists`, `GET /artists/{id}`
32+
33+
Future plan: Transition to "Bring Your Own Client ID" (Option A) so any user with Spotify Premium can use the app without being added to our allowlist. This means the UI will eventually need a Client ID input field with a link to setup instructions.
34+
35+
### Treefort Lineup Data
36+
37+
The lineup is stored as a **static JSON file** (`public/lineup.json`) maintained manually. This is intentional — API restrictions prevent reading the official Treefort Spotify playlist, and scraping the Treefort website is fragile.
38+
39+
The JSON file should include:
40+
- `lastUpdated` — ISO date string, displayed on the site
41+
- `artists` — array of objects, each with: `name`, `spotifyId` (nullable), `spotifyUrl` (nullable), `notOnSpotify` (boolean)
42+
43+
Matching is done on `spotifyId`, NOT string comparison of names. This avoids issues with artist name variants.
44+
45+
## Tech Stack
46+
47+
- **Language:** Vanilla JavaScript (no TypeScript, no framework)
48+
- **Build tool:** Vite
49+
- **Styling:** Plain CSS (no Tailwind, no CSS framework)
50+
- **Font:** Ubuntu (Google Fonts) for headings, bold; system sans-serif for body
51+
- **Hosting:** Cloudflare Pages (auto-deploy from `main` branch)
52+
- **Dev server port:** 9090 (configure in `vite.config.js`)
53+
54+
## Project Structure
55+
56+
```
57+
spotifort/
58+
├── public/
59+
│ └── lineup.json # Treefort 2026 artist data (manual)
60+
├── src/
61+
│ ├── index.html # Entry point
62+
│ ├── main.js # App initialization, orchestration
63+
│ ├── auth.js # Spotify PKCE auth flow
64+
│ ├── spotify.js # Spotify API calls
65+
│ ├── matcher.js # Matching logic (liked songs vs lineup)
66+
│ ├── ui.js # DOM rendering and interaction
67+
│ └── style.css # All styles
68+
├── scripts/
69+
│ └── fetch-lineup.js # One-time utility to generate lineup.json (not part of app)
70+
├── .env.local # VITE_SPOTIFY_CLIENT_ID (gitignored)
71+
├── .gitignore
72+
├── CLAUDE.md
73+
├── LICENSE # MIT
74+
├── README.md
75+
├── package.json
76+
└── vite.config.js
77+
```
78+
79+
## MVP Scope (List A Only)
80+
81+
The MVP delivers one core feature: show the user which artists from their Liked Songs are playing Treefort 2026.
82+
83+
### User Flow
84+
85+
1. User lands on spotifort.com
86+
2. User sees a brief explanation of what the app does, disclaimers, and a "Connect Spotify" button
87+
3. User clicks the button → redirected to Spotify auth → grants `user-library-read` permission
88+
4. Redirected back to spotifort.com/callback with auth code
89+
5. App exchanges code for access token (PKCE), stores in memory
90+
6. App fetches all Liked Songs (paginated, 50/request), extracts unique artist IDs
91+
7. App loads `lineup.json`, matches artist IDs
92+
8. App displays the matched artists in List A
93+
94+
### UI Design
95+
96+
- **Color scheme:** Black and white only
97+
- **Typography:** Ubuntu font (Google Fonts), bold, for all headings/titles. System sans-serif for body.
98+
- **Layout:** Two-column on desktop (CSS Grid or Flexbox), single column stacked on mobile. Breakpoint ~768px.
99+
- **Lists:** Displayed in boxes with thick black borders
100+
- **List items:** Each artist is a bullet with `[+]` as the marker, which is clickable. In MVP, `[+]` links to the artist's Spotify page. In future, it expands to show similar artists at Treefort.
101+
- **Bottom section:** List of Treefort artists not found on Spotify (from `lineup.json` where `notOnSpotify: true`)
102+
103+
### Required Disclaimers (visible on the page)
104+
105+
- "Not affiliated with, endorsed by, or associated with Treefort Music Fest or Spotify"
106+
- "Lineup data last updated: [date from lineup.json]"
107+
- "Use at your own risk — no guarantees of accuracy"
108+
- "FOSS — MIT License" with link to repo
109+
- "Built with Claude Code" with link
110+
- Spotify logo/attribution per their branding requirements
111+
112+
## Logging
113+
114+
Use a simple logging utility gated on `import.meta.env.DEV`:
115+
116+
```javascript
117+
const log = {
118+
info: (...args) => import.meta.env.DEV && console.log('[spotifort]', ...args),
119+
warn: (...args) => import.meta.env.DEV && console.warn('[spotifort]', ...args),
120+
error: (...args) => console.error('[spotifort]', ...args), // errors always log
121+
};
122+
```
123+
124+
Verbose logging in dev (auth flow steps, API call counts, match results). Silent in production except for errors.
125+
126+
## Future Enhancements (NOT in MVP)
127+
128+
These are tracked for later and should NOT be built yet:
129+
130+
- **List B:** Top artists from user's listening history that aren't at Treefort, with similar artists who ARE at Treefort (uses `GET /me/top/artists` + `GET /artists/{id}/related-artists`)
131+
- **[+] expansion:** Click `[+]` on any artist to expand and show similar artists also playing Treefort
132+
- **Bring Your Own Client ID:** UI for users to enter their own Spotify Client ID, with a setup guide page
133+
- **Schedule/venue data:** When bands are playing and where during Treefort
134+
- **Bandcamp/Soundcloud:** Support for artists not on Spotify
135+
- **Rate limiting / progress UI:** Progress bar for users with large libraries
136+
137+
## Commands
138+
139+
```bash
140+
# Install dependencies
141+
npm install
142+
143+
# Run dev server (port 9090)
144+
npm run dev
145+
146+
# Build for production
147+
npm run build
148+
149+
# Preview production build locally
150+
npm run preview
151+
```
152+
153+
## Key Decisions Log
154+
155+
1. **Client-side only** — privacy-first, no backend, no data storage
156+
2. **PKCE auth** — recommended by Spotify for SPAs, no client secret needed
157+
3. **Static lineup.json** — more reliable than scraping or API calls to third-party playlists
158+
4. **Match on Spotify artist IDs** — not string names, to avoid mismatches
159+
5. **Vanilla JS + Vite** — minimal dependencies, fast builds, simple
160+
6. **spotifort.com** — standalone domain, Cloudflare Pages
161+
7. **MVP = List A only** — ship matches before Treefort starts March 25
162+
8. **Option B → Option A** — use own Client ID for dev, transition to BYOCID for public launch

0 commit comments

Comments
 (0)