Stagecouch

A multi-tenant streaming platform — two branded Apple TV apps on one backend. Built solo.

January–May 2026 · ~350 commits across four repos

The Internet Archive holds an enormous, messy, wonderful library of live concert recordings — decades of taped shows uploaded by the people who recorded them. I wanted to watch it on my TV. So I built the thing that makes that pleasant, and then I built it as a platform rather than a one-off app.

Stagecouch is two branded Apple TV apps served from a single FastAPI/MongoDB backend:

Two distinct audiences, one codebase. It's a personal, non-commercial project — but I built it the way I'd build something at work.

The decisions I'd defend in an interview

Multi-tenant from the query layer

Every request carries an X-StageCouch-App header, and the backend enforces per-app collection scoping at the query level — the AJ Tapes app physically can't reach into the main catalog. Adding a third app is a configuration change, not a fork.

Media never touches my backend

Audio streams directly from the Internet Archive to the device; Stagecouch serves only metadata, search, and curation. That single decision means a 2,300+ recording catalog costs almost nothing to host and runs comfortably on a small self-hosted VPS. No egress bills, no CDN, no media storage.

A server-driven home screen

Eight algorithmic row builders — staff picks, on-this-day, deep cuts, anniversaries, top-rated recordings, and a diversity-freshness mixer — so the apps stay fresh without shipping a new build.

The hard parts

Real-time audio + GPU

Gapless playback via AVQueuePlayer, with a real-time FFT spectrum analyzer hung off MTAudioProcessingTap and the Accelerate framework (48 bands, 512-sample Hann window, 60 Hz–12 kHz), running off the main thread. The spectrum feeds a library of 25+ Metal fragment shaders I wrote — raymarched fractals, procedural animation, painterly fields.

But here's the restraint that matters: the shipped apps surface only a small, deliberately limited rotation of those shaders, plus a burn-in-prevention pass (drift, dimming, palette evolution, vignetting). Audio-reactive visuals on a television are a burn-in risk most people don't think about. I built many and ship few, on purpose.

Turning filenames into music

The Archive's metadata gives you track_01.flac, not song titles. Resolving real titles meant a three-step pipeline: parse the file metadata, then extract setlists from show descriptions, then — when those fail — a Playwright scraper against etree.org, the taper-trading community's database. Bad-title detection flags candidates by filename pattern, length, and character distribution. Ratings are weighted Bayesian, backfilled from Archive review data.

A React admin tool

For content QA: a home-screen preview that mirrors the tvOS layout, and a recording-detail view with a live side-by-side etree diff that highlights title mismatches.

Stack

Swift 6 SwiftUI AVFoundation Metal Accelerate Python 3.12 FastAPI MongoDB Playwright React 19 TypeScript Tailwind Linux (PM2 + Caddy)

Where it stands

~350 commits across four repos in five months, solo. AJ Tapes is on TestFlight. It started because I wanted to watch old concerts on my TV. It ended up being the most complete thing I've built end-to-end in one project — frontend, real-time DSP, GPU, a data pipeline, a backend platform, and the infra it runs on.