Zendini: Building a Ticketing Platform for a 538-Seat Theater
The Amish Country Theater seats 538 people a night. Selling those seats is the whole business — and the buying experience is the first impression every guest gets, before the lights go down, before the first joke lands. I wanted that experience to feel like ours: the theater's brand, one clean page per show, a seat picker that works on a phone, and a box office that staff can learn in an afternoon.
Zendini is the ticketing platform I built to do that. It's named like a magician because pulling this off felt like one.

Getting the data model right first
The foundational decision was the event model. A show isn't a date — it's a show, with many performances. In Zendini, "Elvis Forever" is one event with its own artwork, description, and video, and under it live dozens of performances that share everything by default. Master pricing is set once on the event; any individual performance can override a tier for one date without touching the rest. Change a show's description and it changes everywhere, instantly.

538 real seats
The seat picker renders the actual venue — six sections, every row and seat in its true position, drawn as an interactive SVG with color-coded price tiers and live availability. Picking your exact seat from your phone is the moment online ticketing either feels modern or doesn't.

Under the map is the part nobody sees: two people tapping the same seat at the same moment. Seats get a ten-minute hold during checkout, and the final claim happens inside a single database transaction guarded by a unique index — if two checkouts race, exactly one wins and the other gets a clear message instead of a double-sold seat. Payment confirmation is asynchronous: the payment processor's webhook finalizes the order server-side, so a closed laptop lid mid-purchase can't strand a sale in limbo.
The box office is a product too
Half of ticket sales don't start on the website — they're phone orders, walk-ups, comps, and group bookings. So Zendini has a staff-facing point of sale: a today-view dashboard, one unified selling flow for reserved seating and general admission, refunds with reason codes, will-call pickup lists, and QR-coded tickets scanned at the door.

Group sales got real engineering attention because they're how theaters actually fill Tuesday nights: a tour operator puts down a deposit — flat or percentage — then pays the balance in as many partial payments as they need, with the balance tracked and unpaid holds lapsing back into sellable inventory automatically.

Two design languages, one system
The storefront wears the theater's identity — its green, its type, big show artwork, mobile-first. The back office uses what I call the calm kit: navy and glacier blue on off-white, Poppins and Inter, generous whitespace, dense only where staff need density. Guests get a branded experience; staff get a tool that stays out of the way at 6:45pm with a line at the window.
The stack
Next.js 16 on Vercel, Postgres with row-level security on Supabase, Stripe for payments, Resend for ticket delivery, QR codes generated per ticket. The schema is multi-tenant from the first table — organizations own venues, venues own seat maps — so the theater is tenant number one rather than a hardcoded assumption. Eighty commits over about a month, built by me and a squad of AI coding agents, with the seat-hold race conditions and payment webhooks getting the human attention they deserve.
Zendini hasn't launched yet — it's in final pre-launch hardening: live payment keys, the ticketing domain, and the data migration are the last mile. I'm targeting Q1 2027 for the cutover, which is a natural break in the theater's calendar between seasons. The next season goes on sale through it.