Skip to content
Back to help

Double-booking prevention

The mistake you can’t make

Two clients showing up for the same slot is the worst operational failure in this business: embarrassing, costs you both relationships, no graceful recovery. Goldenhour prevents it structurally so you literally can’t.

The four layers

Defense in depth

Layer 1: Database constraint

Goldenhour’s appointment table has a Postgres exclusion constraint: EXCLUDE USING GIST (account_id WITH =, time_range WITH &&) : two appointments on the same account that overlap in time fail to insert. This is structural. The database itself rejects double-bookings; no application code can override it.

Layer 2: Slot-locking during checkout

When a customer clicks “Book” we mark the slot as “held” for 5 minutes while they complete payment. A second customer reaching the same slot during that window sees it as unavailable and is shifted to a nearby time. If the first customer abandons checkout, the hold expires + the slot becomes available again.

Layer 3: Buffer-time enforcement

Per-service buffer (see /help/buffer-times) is part of the booked range, so a 60-min service with a 15-min buffer reserves 75 min of calendar space. The next bookable slot starts 75 min later, not 60: no back-to-back over-scheduling.

Layer 4: Calendar-sync conflict detection

If you sync to Google Calendar / iCloud (Settings → Calendar sync), goldenhour reads back personal events you add directly to those calendars + treats them as busy. Block out your kid’s recital on your iPhone Calendar; goldenhour will skip showing that slot to bookers.

The race-condition edge case

When two customers click Book at the same exact moment

Sub-second simultaneous bookings hit the slot-lock + the database constraint together. Whoever lands first wins. The second customer sees a clean “That slot just got taken” message with the three nearest alternatives shown immediately.

This recovery has been load-tested with 50 concurrent attempts on the same slot: only one succeeds, the other 49 get the same clean fallback UI within 200ms. Never a double-booked appointment, never a payment without a slot.

Manual blocks

Three ways to mark time as unavailable that aren’t appointments:

  • One-off block: drag on the calendar → “Block this time.” Use for personal appointments, deliveries, lunch breaks.
  • Vacation block: Settings → Vacation → mark a date range. SMS responder also activates for messages received during the window. See /help/vacation-coverage.
  • Recurring block: Settings → Schedule → recurring blocks. Useful for “every Tuesday from 12-1pm is my kid’s pickup.”

Verifying for yourself

To prove the prevention works on your account:

  1. 1.Open your public booking page in two browser windows side-by-side
  2. 2.Click the same slot in both windows
  3. 3.The second window sees “held by another customer” immediately
  4. 4.Complete checkout in the first window: appointment books cleanly
  5. 5.The second window now shows the slot as taken + offers alternatives

Related: calendar sync