Music Forest · architecture guide
One app, four ways in. In plain words is the whole privacy story for anyone. Map 1 follows your data outward — the protocol on every wire and the line your notebook never crosses in the clear. The codebase lists what’s in the source. Map 2 is a flowchart of what a person actually does.
No tech knowledge needed — what the app is, and whether your information is safe.
Find music, write notes. Every day, Music Forest brings you the records released on this date — any year — one at a time. You meet a record and keep the ones that stay with you, or set the rest aside. If you want to write something down about one, you can — whatever it is — in a private notebook that’s yours alone. No feed, no algorithm, no ads.
That private notebook is the part people ask about. Here’s the whole story, in three steps.
Jot down whatever you want about a record. Your own device locks it up right away, like a diary that snaps shut on its own.
We hold your locked notes safe so you never lose them. Only you have the key. Not us, not the company that stores it, not anyone.
When you want to play an album, it opens in Spotify, Apple Music, or wherever you listen. Music Forest just points you there — it never passes along anything about you.
That’s the whole deal. Come for the music; your business stays your business.
Four places your data can be, top (closest to you) to bottom (farthest out). Between each pair is the wire that joins them — a two-way arrow with the protocol it speaks and what rides it in each direction.
The one place your words exist in the clear. Encryption happens here with libsodium — Argon2id stretches your passphrase into a key that wraps the data key; the passphrase and keys stay in memory and are wiped on reload.
in memory
Guest buffer + prefs localStorage
Biometric unlock WebAuthn, device-local
main → Render auto-deploys
build-time · not your data
Flask + gunicorn. Serves the app, reads the public catalog for you, and relays your sealed rows onward. It never holds the key, so it can’t read your notebook.
albums.db · pool.sqlite
Sync relay /api/sync/* — passes ciphertext
Availability + art resolver cached
psycopg (pooled)
⇅ both ways. Down: store & fetch. Up: sealed rows + wrapped key back. Encrypted in both directions.
Durable storage with daily backups. Holds sealed rows, opaque keys, and your login — never anything readable from your notebook.
journal_rows — ciphertext
user_keys — wrapped key, opaque
auth.users — email & login
invited_emails · access_requests
feedback — team-readable, by design
Spotify is the one keyed API (OAuth client token); the rest are keyless and best-effort. When you tap a listen link, your browser goes there directly — and still sends nothing that says it’s you.
Your notebook — your notes and what you keep — is encrypted in your browser. The server, the database, and the people who run Music Forest cannot read it — and no one can reset your password for you.
Your email is visible — it’s how you sign in and how an invite reaches you. But nothing about what you write is ever tied to it in the clear.
Feedback you send is readable by the Music Forest team, on purpose, so it can be acted on. It’s the only thing you author that isn’t sealed.
Availability lookups carry album titles, not you. No profile, no tracking beacon, no “resurfacing.” Connections are pull-only and stay on your machine.
The repo behind it. How it reaches Render is drawn into Map 1 above (the dashed “code in” wire); the catalog databases are too big for git and rsync in on their own.
Private GitHub repository
Flask + SQLite · no-build static PWA · single main branch
server.pyFlask app — JSON API, serves the PWA + cached art, /api/sync/*, security headers.db.pyAll catalog SQL for albums.db — the one file to change for a different DB backend.pooldb.pyReads the unified daily-pool: dedup, availability, confirmed platforms, the doors.journal.pyThe local journal store; the hosted client mirrors it in static/journal-store.js.auth.py · store.pyJWT verify + the SQLite-or-Postgres sync store (the Zone 2↔3 relay).static/The PWA shell — app.js, index.html, style.css, sw.js, plus crypto + sync.tools/Crawlers + pipeline: calendar warmer, prewarmers, MusicBrainz ingest, rsync_pool.sh.data/Catalog + journal DBs (~5 GB) — gitignored, never committed; rsync’d in separately.A flowchart from first arrival to keeping a notebook. Rectangles are screens or steps; diamonds are decisions the app makes; a door is a pull-only exit that keeps your place and returns at zero cost.