Paper

Heart Echoes Music: A 900-Song Storefront With a $26-a-Month Ceiling

The situation

Heart Echoes Music is my own product. It's a direct-to-consumer storefront for a catalog of roughly 900 songs — AI-assisted, human-curated. Fans buy MP3 downloads for $1–$3. Producers buy MIDI packs and stem files for $10–$99. Same catalog, two very different buyers.

I will one day run it as a real business, as a side hustle, and as proof of how I build. Every architectural decision was made as if a paying client were watching, because eventually one would be reading this.

The catalog started life in Airtable, with field names in three different conventions. There was no store.

What was actually wrong

Three things, and only one of them was obvious.

First, the bandwidth math. Music is a heavy product — 50 to 100 MB per file. Three customers downloading the full library in one month means 240 GB of outbound data. Priced on a standard managed platform, a good month — 100 full-catalog customers — models out to roughly a $697 bandwidth bill. Success would have been the expensive part.

Second, the audience split. A fan wants to feel something before spending $2. A producer wants BPM, key, and stem contents before spending $99. One storefront that serves both usually serves neither.

Third, trust. AI-assisted music makes producers nervous: is it musically coherent, is it well-timed, is it clean? "Trust me" is not a product page.

What I built

Storage split by cost behavior. Preview clips and cover art sit on Supabase, next to the database and auth. Full product files sit on Cloudflare R2, where outbound bandwidth is free at any volume. Storing the 80 GB product library costs about $1.05 a month. Supabase Pro is $25. Total infrastructure ceiling: about $26 a month, no matter how much gets downloaded.

Paid files stay private. After Stripe confirms a payment, my server checks the purchase record and the buyer's identity, then generates a presigned download link that expires in minutes. No link-sharing, no open buckets.

One storefront, two faces. Fan Mode is warm and art-forward. Studio Mode is dark and data-dense — BPM, key, ISRC, and producer actions up front. The preference is saved server-side in a cookie, so a returning producer lands straight in Studio Mode. One codebase, one data model, no second site to maintain.

The Airtable-to-PostgreSQL migration got the discipline most people skip. Every audio file on disk was already named with its Airtable record ID, so that ID became a permanent column in the new database — a durable link between each record and its file that survives any renaming. I renamed every Airtable field to snake_case before writing the migration script, so the script needs no field-mapping dictionary. And the script produces a dry-run file first: I read the transformed records with my own eyes before anything touches the database.

Ongoing updates run through the same discipline. Each CSV row declares its intent — INSERT or UPDATE — and the script enforces it. An update aimed at a record that doesn't exist gets flagged and skipped, not silently created. An insert that already exists gets flagged, not overwritten. Every run ends with a reconciliation report: what changed, what was skipped, what didn't match.

The curation is human, and it's written down. Only about 1 song in 5 clears the three-part quality rating — message, music, vocals — and makes it into the store. Every MIDI file passes through Melodyne for transcription, Scaler 2 for harmonic analysis, and DAW quantization before it becomes a product. Songs with vocals get hand-set preview timestamps so the clip opens on the hook; instrumentals start at the 30-second mark automatically. That layer is what backs the "human-curated" claim on every product page.

What changed

  • Roughly 900 songs, each carrying a permanent ID that ties its database record to its audio file — the anchor for a clean Airtable-to-PostgreSQL migration
  • Infrastructure ceiling of about $26 a month, fixed — against a modeled $697 single-month bandwidth bill in the all-in-one setup
  • $0 in server-side media processing: previews are cut locally with FFmpeg before upload
  • Producer leads captured with no account required — an email and an interest type — feeding demand data that decides which songs get MIDI and stem versions first
  • A 30-day early-bird discount window enforced by my server code against the product's release date, not by a coupon setting
  • Product URLs computed from a naming convention, not stored — switching storage providers means changing one environment variable, not 900 database rows

The storefront is close to done, and it is on the shelf for now. I set it down to put my time into RFQ Hunter — the project with the clearer path to revenue — and I will finish Heart Echoes as a side business when the moment is right. The architecture, schema, and curation system are settled; the catalog migration is what is left.

What this says about how I work

I price the failure modes before I build — the storage decision happened in planning, not after a surprise bill. I hold my own product to the same data discipline I'd bill a client for. And scope was set by what produces a first sale, not by what would be fun to build.

That was the brief I gave myself: a store that can't surprise me with a bill.