StackMoth/Work/Reservation platform
Booking & payments
A booking platform that refuses to sell the same court twice
A reservation, billing and front-desk platform for a Colombo basketball facility operator, live and taking money daily. The interesting engineering is not the booking form. It is everything that makes a double booking impossible.
- Client
- A Colombo basketball facility operator
- Period
- Dec 2024 to Aug 2026, 21 months
- Scale
- About 48,000 lines, 215 commits
- In production
- 1,558 registered users, 3 locations, 9 courts
- Stack
- Express 4.21, TypeScript, Next.js 15, React 18, PostgreSQL
- Payments
- Dialog Genie IPG, multi-merchant
- Tests
- 274 backend tests
- Access
- Live and in daily use. Not linked publicly.
The problem is physical, not clerical
A court sold twice is not a scheduling annoyance. It is two paying customers standing on the same floor at the same time, and a front desk with no good answer.
Half-court and full-court reservations overlap. Two bookings that look completely different in the interface can be the same physical space, so the rule the system has to hold is not "no duplicate rows" but "no overlapping claim on the same court".
Double booking is refused three times over
The platform does not rely on a single check. Three independent layers have to fail before a conflicting reservation can exist:
- A transaction-scoped advisory lock.
pg_advisory_xact_lockserialises requests that could collide, so two simultaneous bookings for the same slot are considered one after the other rather than at once. - Two overlapping partial unique indexes. Half-court and full-court exclusion is encoded as a database invariant. The rule holds even if the application is bypassed entirely, and it survives any future code that forgets it exists.
- Clean failure at the boundary. A
23505unique violation is translated into an HTTP 400, so the last line of defence still produces a comprehensible error rather than a 500.
There is no Redis and no external lock service. The concurrency primitives are PostgreSQL's own, which is a deliberate trade recorded in the repository's documentation under its known production risks rather than left implicit.
Money settles to the right company
The facilities are operated by different legal entities, so payment routing is a correctness problem, not a configuration detail. Payments run through Dialog Genie with merchant selection driven by location, so funds settle to the company that actually owns the booking.
- The server re-queries the payment provider for the authoritative result. Webhooks are treated as a hint to go and look, never as the source of truth.
- Webhook verification is HMAC-SHA256 with a five-minute replay window, compared using
timingSafeEqual.
What a real money incident changed
In July 2026 a payment incident put a set of transactions into a state the system could not describe. The response was a subsystem, not a patch:
- A classification taxonomy, so an incident has a type rather than a comment thread.
- An idempotent incident ledger, so replaying a reconciliation cannot double-count it.
- A
received_under_reviewstate, so the system never tells a customer that a payment failed while their money may in fact have moved. - A
cancellation_sourceprovenance column, so every cancellation records who or what caused it.
The reconciliation that followed covered 46 transactions and is documented in the repository rather than in someone's memory.
One deadline, one definition
A single shared SQL fragment defines the payment deadline. The deadline shown to the customer and the deadline enforced by the system are the same expression, so they cannot drift apart through an edit to one and not the other.
Tested where it would actually break
274 backend tests, including tests that assert on generated SQL text. That is an unusual thing to test, and it exists for a specific reason: a refactor that quietly drops an advisory lock or a partial index would otherwise still pass a suite that only checks behaviour under low concurrency.
AI-assisted, human-accountable. AI tools contributed significantly to the implementation described here. The specification, the review of every change, the production operation and the accountability are mine.
Next case study
CourtRes