<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel>
<title>Build logs — Jason Adams</title>
<link>https://jasonscottadams.com/blog/</link>
<description>War stories from the homelab and the infrastructure trenches. Written by me, occasionally with an AI pair of hands on the keyboard.</description>
<item>
<title>Shipping an app from a backup drive in one night</title>
<link>https://jasonscottadams.com/blog/shipping-an-app-from-a-backup-drive/</link>
<guid>https://jasonscottadams.com/blog/shipping-an-app-from-a-backup-drive/</guid>
<pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate>
<description><![CDATA[<h1>New blog! It works!</h1>
<p>Last year my main machine got wiped and rebuilt, and everything I&#39;d ever worked on went to a 7.3&nbsp;TB drive labeled <code>BACKUP — never format</code>. Somewhere in there was a little React prototype I&#39;d built and abandoned: a bingo card generator for concerts. Type in a band, get a 5×5 grid of similar artists, spot their shirts in the crowd. Cute idea. Dead code.</p>
<p>Last night I resurrected it, rebuilt it, and shipped it to <a href="https://concertshirtbingo.com">concertshirtbingo.com</a> before I went to bed. Here&#39;s what that actually looked like, because the process says a lot about how building software works now.</p>
<h2>The archaeology</h2>
<p>The prototype was 255 lines of React in a single file, sitting in a backup of a backup. It still ran. Even the Last.fm API key in the <code>.env</code> still worked — I checked it before writing a line of new code. Lesson one of infrastructure work applies to side projects too: verify what you have before you rebuild what you don&#39;t need to.</p>
<h2>The research fleet</h2>
<p>Before rebuilding, I had AI research agents fan out in parallel: one auditing whether Last.fm was still the right music-data source in 2026 (it is — but Spotify&#39;s API is now effectively closed to hobby apps, which I didn&#39;t know), one evaluating concert-data APIs, one pricing out LLM-generated content at the edge, and one sweeping prior art. An hour later I had a verified picture I&#39;d have spent a weekend assembling by hand — including live-tested fallback chains: Last.fm to ListenBrainz to Deezer, so no single provider&#39;s death kills the app.</p>
<h2>The build</h2>
<p>The rebuild went from one file to a proper little architecture: seeded deterministic shuffles (so a shared link reproduces your exact card), genre detection driving per-genre visual themes — a Slayer card looks nothing like a Chappell Roan card — and curated square packs with rarity tiers. Tested end-to-end in a real browser against live APIs before deploy.</p>
<h2>The DNS gauntlet</h2>
<p>Then the fun part. The site deployed to Cloudflare Pages in seconds, the registrar nameserver change went through cleanly — and the domain still showed a parked page. For the next hour I got to peel the most complete stack of stale DNS caches I&#39;ve ever personally encountered, in order: the public resolvers (flushed via Google&#39;s and Cloudflare&#39;s purge tools), my router — which it turns out hijacks <em>all</em> port-53 traffic on my LAN and answers from its own cache, lying to every <code>dig @8.8.8.8</code> I threw at it — then macOS&#39;s own <code>mDNSResponder</code>, and finally Chrome&#39;s private resolver cache. Five layers. The site was live on the internet for half an hour before my own house would admit it.</p>
<h2>What it means</h2>
<p>Total wall-clock time from &quot;what&#39;s on this backup drive?&quot; to a working product on its own domain with valid SSL: one evening. The bottleneck wasn&#39;t writing code — an AI pair of hands wrote most of it while I made decisions. The bottleneck was judgment: which data sources to trust, what the product should feel like, and knowing that when DNS lies to you, you check the registry&#39;s whois before you believe any resolver.</p>
<p>Thirty-five years in IT and the job is still the same: it&#39;s always DNS.</p>
]]></description>
</item>
</channel></rss>
