A rich-text journal that follows whatever you're playing on Spotify. Live at songnotes.codyh.xyz. The Library view at /home/library turns every note you've ever written into a searchable gallery of album-art cards.
More:
ARCHITECTURE.md— how it's wired ·ROADMAP.md— what's next ·CHANGELOG.md— what shipped ·CONTRIBUTING.md— how to help
- Sign in with Spotify and the app mirrors your current playback — track title, artists, album art, transport controls.
- Write notes in a rich-text pane; changes auto-save to Postgres with a debounce, keyed by Spotify
trackId. - Type a timestamp like
1:23and it becomes a clickable chip that seeks Spotify to that position. - Browse every note you've written in the Library: full-text search across notes, songs, and artists; sort pills; a side drawer with play-in-Spotify and delete.
- Write offline. Saves that fail because there's no network are queued in IndexedDB and replayed when the connection comes back; a "Queued · N" chip appears in the header while writes are pending.
- Install as a PWA. The web manifest registers the app as a Web Share Target, so a Spotify track URL shared from the OS share sheet lands at
/shareand bounces straight into the editor for that track. - Export your notes as JSON, wipe everything, or log out from a shared settings modal.
DJing means holding structured opinions about an absurd amount of music. Spotify gives you the catalog but no way to write anything down inside it, so the usual workflow is to alt-tab between a player and a notes app until the thread is lost. My Song Notes collapses that loop — instead of navigating to a song to annotate it, the note pane follows whatever is already playing. Opening the app is the same gesture as "I want to write about this."
- Next.js 16 (App Router) on Vercel, React 19
- Auth.js v5 (next-auth) with the Spotify provider (JWT sessions, refresh-token rotation)
- Drizzle ORM over Neon Postgres (
postgres-jsdriver) - Custom CSS for layout/theming
- DOMPurify to sanitize note HTML,
use-debouncefor autosave
The Spotify access token never reaches the browser — every Spotify call goes
through /api/spotify/* server routes that read the token from the JWT cookie.
Track metadata (name, artists, art) is denormalized onto the notes row at
save time so the Library view renders straight from Postgres without a
round-trip to Spotify on every load.
You will need a Spotify developer app and a Postgres database (Neon is what production uses).
git clone https://github.com/codyhxyz/spotify-notes.git
cd spotify-notes
npm install
cp .env.example .env.localFill in .env.local:
DATABASE_URL— Postgres connection string (Neon pooled URL works).SPOTIFY_CLIENT_ID/SPOTIFY_CLIENT_SECRET— from the Spotify developer dashboard. Addhttp://localhost:3000/api/auth/callback/spotifyas a redirect URI on the app.AUTH_SECRET— generate withopenssl rand -base64 32. The legacyNEXTAUTH_SECRETname still works.AUTH_URL—http://localhost:3000for local dev. Auto-detected on Vercel; legacyNEXTAUTH_URLstill works.
Apply the schema. Migrations are plain SQL files; run them in numbered order:
psql "$DATABASE_URL" -f migrations/001_initial.sql
psql "$DATABASE_URL" -f migrations/002_track_metadata.sql
psql "$DATABASE_URL" -f migrations/003_spotify_accounts.sql(Or paste the contents of each into the Neon SQL editor.)
Then:
npm run devOpen http://localhost:3000 and sign in with Spotify.
app/
page.tsx # landing / sign-in
home/page.tsx # now-playing + note editor
home/library/page.tsx # searchable gallery of all your notes
components/ # SettingsModal, EulaModal, shared UI
api/
auth/[...nextauth]/ # NextAuth Spotify provider
notes/route.ts # GET / PUT / DELETE single notes (PUT supports
# optimistic concurrency via expected_updated_at)
notes/list/route.ts # cursor-paginated, hydrated with track metadata
users/route.ts # EULA-accept row
spotify/ # server-side proxy: playback, track, play, pause,
# next, previous. The Spotify access token lives
# only in the JWT cookie.
lib/
auth.ts # NextAuth options; stores the Spotify grant at sign-in
db.ts # Drizzle client (postgres-js)
db/schema.ts # users, spotify_accounts, notes tables
spotify.ts # server-side Spotify Web API client + token refresh
origin.ts # Origin/Referer-based CSRF guard for write routes
util/
apiutils.ts # browser wrappers around /api/spotify/*
components.tsx # SVG icons + clickable timestamp chip
theme.ts # theme switcher
migrations/
001_initial.sql # users + notes schema
002_track_metadata.sql# denormalized track metadata + list index
003_spotify_accounts.sql # OAuth tokens out of the cookie, into Postgres
proxy.ts # gates /home/* on a NextAuth session
Deployed to Vercel. Pushes to master auto-deploy to production.
Built by codyh.xyz.