Design Lab / project
Opus's Diecast Emporium
My dad has a wall. Pegboard, floor to ceiling, carded Hot Wheels and Matchbox, boxes underneath, a few thousand pieces and no list of any of it. He wanted a real record, a place to show the good ones, and a way to sell the doubles. So the site is the small part. The interesting part is what feeds it.
The shape of it
One database, two doors.
The public site holds no data of its own. It asks the API for cars at load, and the API only ever answers with rows he has flagged public, and only the safe fields. What he paid, where a car lives, what he wrote in the notes, none of that has a route out. The filtering happens inside the app, not in the UI, so poking the API directly gets you the same answer the page gets.
The private door is the same API behind Authentik. Caddy authenticates, then the app checks the group itself instead of trusting the proxy. If the vhost is ever misconfigured, the app still says no. That door has the full catalogue, the edit form, a deliberately loud publish toggle, CSV in and out.
opusdiecastmi.com Cloudflare Pages
api.opusdiecastmi.com worker2, Caddy, systemd
visitor --> index.html
/vault/ --------> GET /api/public/cars
no auth
only is_public = 1
safe fields only
Opus ------> login.opusdiecastmi.com
(Authentik) ----> /api/vault/*
group re-checked in app
every field, every row
PATCH is_public = publish
photos /api/public/photo/<id>
404 unless that car is public
/api/vault/photo/<id>
anything, gated How cars get in
Film the shelf. That's the data entry.
Typing a few thousand cards into a form was never going to happen. So the input is a phone video: a slow pan across a shelf, two lights from the sides so the blister doesn't glare, one column every couple of seconds. He emails the clips. The rest is a pipeline.
Each clip gets sampled to stills. The clearest frame per card wins, which is often not the first one it appears in.
Brand, series, casting, colour, collector number, card condition. Every row carries a confidence. Unreadable means "unknown," never a guess.
The product photo is cut straight out of the best frame, trimmed, and attached to the row. No separate photo shoot.
A CSV lands in the vault as drafts. Low-confidence rows are flagged Needs ID. Nothing goes public until he flips it.
First real run: three clips, about 75 seconds of footage, 134 draft rows with photos. The same shoot also produces a month of vertical video for his page, which is the point. Catalogue it once or catalogue it twice.
Plain HTML on Cloudflare Pages. No build step. Fetches the public API at load and self-hosts his one Facebook video, no embed script.
Python, stdlib only, no pip on prod. SQLite in WAL mode with a verified backup script, audit table, custom key/value fields so the schema never blocks him.
Authentik with its own brand and login flow, his collection wall as the login background. Caddy forward_auth, group re-checked in the app. 17 auth tests, all green.
Hot Wheels and Matchbox are trademarks of Mattel, Inc. This is a private collector's catalogue and is not affiliated with either.
Got a collection, a shop, a thing that needs a real record?
This is the kind of build Quick IT does. Free 30-minute consult.