The Watchlist

A film and TV watchlist I curate in private and publish as a read-only public site. It stores my opinions, and borrows the rest.

Personal project2026Full-stack web appCurrently offline

Overview

The Watchlist is where I track everything I watch: a rating, a one-line take, the odd note, and how I found it. I curate it privately, and it publishes as a clean public site anyone can browse, no account needed.

The problem

I wanted to keep my own ratings and notes on films and shows, and share them, without rebuilding a movie database. Re-storing posters, cast, genres and runtimes for every title is a maintenance trap, and it goes stale the moment the source updates.

Approach

The guiding principle is store opinions, borrow metadata. The database holds only what is mine: rating, status, tags, a short take, and where I discovered each title. Everything heavy (posters, cast, genres, recommendations) is pulled live from TMDB when a page is viewed, so the catalogue is always current and the database stays small.

Key features

  • One admin signs in to search TMDB and save a title; everyone else gets a read-only public site.
  • A public gallery with filters by status, type and tag, plus sorting.
  • Title pages enriched live from TMDB, and a Hall of Fame for the favourites.
  • Person pages that cross-reference an actor against the titles I have logged.

Tech stack

The current rebuild runs on Next.js and React with TypeScript, a Neon Postgres database through Drizzle, and session auth with jose. TMDB supplies the metadata at view time.

Next.jsTypeScriptPostgresDrizzleTailwind CSSTMDB API

Outcome

This is the third rebuild, and the one that finally got the data model right. Earlier versions leaned on a CMS; moving to Postgres and Drizzle made the owner-data-only idea simple to enforce. It is still in active development.

The incident

In July 2026 an AI crawler (Anthropic's ClaudeBot, according to the logs) found the site and did what crawlers do: it followed every link. Title pages link to cast, person pages link to full filmographies, and any TMDB id rendered a page, so the crawl never ran out of URLs. Roughly 350,000 requests in twelve hours, each one rendered on the server, and in two days it burned through months of hosting quota. Vercel paused my whole account, this portfolio included.

The fix was mostly about respecting the CDN. Public pages now render once and serve from cache, curated titles are prebuilt, writes revalidate exactly the pages they touch, and aggressive crawlers are blocked outright. The site is offline while I redeploy it behind those fixes.

The lesson was simple: an unbounded route space plus per-request rendering is an open invitation, and sooner or later something accepts.

Vercel Observability showing 338,000 edge requests over 12 hours, with claudebot accounting for 350,000 requests at a 0.2% cache-hit rate.
Vercel Observability, edge requests by bot over twelve hours. claudebot alone drove 350K requests at a 0.2% cache hit rate (nearly every request a fresh URL), and Firewall Actions sits empty because nothing was there to stop it.