Why I built it
Zara Residence is a music residency in Abuja built around Amapiano and African electronic music. Recurring live events, resident DJs, more a community you join than a venue you visit. It needed more than a landing page: events change, tickets need issuing, members need accounts. The usual answer is a website plus an Eventbrite plus a mailing list plus a spreadsheet at the door. I wanted all of it in one deployable thing.
What it does
The whole platform is a single Cloudflare Worker. The marketing site prerenders to static assets. The member area, the API, and the database live in the same Worker behind it: Hono routes under /api, D1 for registrations and accounts, Sanity as the CMS so event changes don’t need a deploy.
Sign-in is passwordless. You get a code by email, sent over a plain SMTP socket from inside the Worker, so there’s no auth SaaS and no password table to protect. Registering for an event issues a ticket with a unique code, and /t/[code] renders a door-ready ticket view straight from a D1 lookup: event, name, quantity, status. The door team checks tickets with a phone browser. No scanner app, no vendor.
There’s also a small /manage area for the residency team, event setup and registration lists, so operations don’t route through me.
The fun part
The site had to feel like the events do, so a lot of the time went into the interactive layer.
The piece I’m most fond of is the event blueprint. It’s a floor plan of the venue rebuilt as an interactive arena: hover or tap a zone (dance floor, DJ booth, queue lanes, resident lounge, the merch corner) and a spotlight lands on it with a short note about what happens there, each zone with its own accent colour. The popup does some clamping math so it never spills out of the frame on small screens. Below it sits the stage design itself, the actual renders for the night, full-bleed. It turns “venue info” into something people actually explore before buying a ticket.
The residents section leaves a trail of images behind your cursor as you move, and the hero mascot runs through a little WebGL shader for some movement that CSS couldn’t give me. All of it checks prefers-reduced-motion and sits out if you’ve asked it to.
Decisions I’d make again
One Worker, no seams. Static pages, SSR member pages, API routes, and the database deploy as one unit. No separate API service to version against, no CORS, no “the frontend is up but the backend is down.”
Passwordless because the alternative is worse. This audience signs in a few times a year, on a phone, often at an event. A forgotten password is a support queue. An emailed code is one tap. And if SMTP isn’t configured, codes fall back to the Worker logs, so the flow stays testable end to end.
The ticket is a URL. No PDFs, no wallet passes, no QR pipeline. A short code in a link, rendered server-side from the registrations table. It can’t be out of date, it works on any phone, and the door check is “does this page say valid.”
