
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.htmland bakes Supabase public config intostudio-3a9f7b/config.jsat 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-subscribe,public-subscribe-confirm,public-unsubscribe,admin-publish(verifies the Supabase session, flips episode status, inserts the announcement row, and pings the build hook in one shot), and adeploy-succeededwebhook - Email: Resend, sending from
hello@sgf.workfor 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: DENY, no-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