Work/Full-Stack · System Design

Reservation Platform — Zero Double-Bookings

A US restaurant group ran event-hall, catering, and table bookings over the phone — three intake channels, one paper-adjacent process, and regular double-bookings. I replaced it with a 4-app platform where double-booking is structurally impossible.

Role
Full-Stack Engineer (freelance)
Timeline
Ongoing · US client
Team
Solo, end-to-end
Year
2025–present
Reservation platform — availability calendar and booking flow for event halls and tables
PLACEHOLDER — replace with a real booking-flow screenshot.
0
double-bookings under load
21
customer/admin screens
77
shared Zod schemas
72
automated tests

01 — Problem

Three booking channels, one shared calendar

Event halls, catering, and tables compete for the same physical spaces and staff. When intake happens over the phone across three channels, conflicts are found by accident — usually by the customer, on the day. The client needed self-service booking, but self-service makes the concurrency problem worse: now two customers can race for the same slot at 2 a.m.

02 — Core design

An 8-state lifecycle with transactional locking

A reservation isn't a row, it's a state machine: 8 states from draft through confirmation, fulfillment, and cancellation, with every legal transition enumerated and everything else rejected at the API boundary. Invalid transitions aren't bugs to catch in review — they're unrepresentable.

Slot allocation runs inside a database transaction that locks the slot row before checking availability. Two concurrent requests for the last slot serialize at the database; the second one sees it taken. No advisory flags, no check-then-write races — the invariant lives where the data lives.

State diagram of the 8-state reservation lifecycle with locking at the transition boundary
The reservation state machine. PLACEHOLDER diagram — replace with a polished export.

03 — Contracts

One schema, both sides of the wire

The monorepo shares 77 Zod schemas between the Fastify API and all frontend apps — every request validated at the edge, every response typed at the client, one definition each. 72 automated tests cover auth, booking, and audit paths, including concurrency tests that hammer the same slot from parallel connections.

04 — Operations

Slow paths off the request, eyes on production

Confirmations and reminders (Twilio SMS, Resend email) run through BullMQ workers, off the HTTP path — a booking never waits on a text message, and a Twilio outage degrades notifications, not bookings.

The platform ships with a 9-service observability stack — OpenTelemetry traces, Prometheus metrics, Loki logs, Grafana on top — targeting p95 under 500ms. For a solo-built system, dashboards are the second engineer.

Grafana dashboard with correlated metrics, logs, and traces for the reservation API
PLACEHOLDER — replace with a real Grafana screenshot.

05 — Outcome

Phone intake, retired

21 customer and admin screens now handle all three booking channels self-service. Under load tests hammering identical slots, double-bookings: zero. The interesting part isn't the zero — it's that the design makes any other number impossible.

Stack

TypeScriptNext.jsReactFastifyPostgreSQLRedisBullMQTwilioDockerOpenTelemetry

Next case

RcoinX — Real-time Spot Trading