angry tech news podcast website development.

Three hosts who never agree about anything needed a website that looked like it had an opinion. So I built one — a single-page newsprint broadsheet for a weekly tech podcast, with a hidden studio for publishing episodes and a real subscriber flow underneath the layout.

The design

The whole front page is one ~1,500-line index.html with inline CSS and JS. No framework, no build step on the client side. The type does most of the work: Anton for the masthead and section heads, Instrument Serif for the editorial flourishes, JetBrains Mono for metadata and bylines. Every section is numbered like newspaper plates — § I, § II, § III — and the breaking-news ticker, the “1,247 days since the hosts last agreed,” the “Vol. III · No. 147” dateline are all part of selling the bit. The site should feel like an actual publication a podcast happens to live inside.

The stack

  • Frontend: static HTML, hand-written, hosted on Netlify from the repo root
  • Build: Node 22 ESM script that compiles templates/index.template.html and bakes Supabase public config into studio-3a9f7b/config.js at build time so secrets aren’t checked in
  • Data: Supabase — episodes, hot takes, settings, subscribers, announcements, with RLS as the security boundary (the anon key is public on purpose; the database enforces who can do what)
  • Serverless: Netlify Functions for anything that needs a secret or atomicity — public-subscribepublic-subscribe-confirmpublic-unsubscribeadmin-publish (verifies the Supabase session, flips episode status, inserts the announcement row, and pings the build hook in one shot), and a deploy-succeeded webhook
  • Email: Resend, sending from hello@sgf.work for double opt-in confirmations
  • Auth: a Supabase Edge Function hook gates studio sign-ins against an allowlist

The studio

The admin lives at an obfuscated path — /studio-3a9f7b/ — and is a vanilla HTML/JS app. The _headers file sets X-Frame-Options: DENYno-store, and noindex/nofollow on the studio and on /api/*robots.txt disallows both for good measure. It’s not a security model (the allowlist + RLS is), it’s just keeping the surface quiet.

Pretty routing

netlify.toml rewrites /api/* to /.netlify/functions/* so the public-facing URLs read like an actual API rather than vendor internals. Small thing, but it means if I ever move off Netlify Functions the URLs don’t have to change.

What I like about it

The interesting part wasn’t the stack — it’s pretty standard Jamstack — it’s that the site’s voice and the codebase’s voice match. The hosts are loud and opinionated; the typography is loud and opinionated; the admin is hidden behind a path that feels like a back-of-house door at a newsroom. The whole thing reads as one piece, which is the bar I try to hit on every SGF.work-adjacent project.

Leave a Reply

Discover more from Sean Blowers

Subscribe now to keep reading and get access to the full archive.

Continue reading