Example: Booking System
Availability, reservations, reminders, and no double-bookings. A complete scheduling app with the flow that makes conflicts impossible.
Booking looks simple until two people grab the same slot at once. This example shows the model, the conflict-proof reservation flow, and the reminder machinery.
Data Model
- resources: what gets booked (rooms, tables, staff): name, capacity, opening hours, timezone.
- bookings. One document per reservation:
Booking Document
{
"_meta": {
"cms": 1782166695442,
"created": 1782166695,
"entity": 1,
"expiry": -1,
"guid": "e67919283b4e37c9758326446605ab863bf452cda26f91c2aef74ba31f9a3214",
"removed": 0,
"ums": 1782170295118,
"update_hash": "7b25e0af9163c4d8052ae7f31964bc0d8a5f3c62",
"updated": 1782170295
},
"customer_guid": "b9ee6a631b24e78d1aa48aef0dc067fff7bfbacd24a56ef4ed1f08e537d48b6bd02",
"customer_name": "sami b",
"end": 1782364800,
"reminder_sent": false,
"resource_guid": "e01ff8643394371a8544d2c9f8a1b3e5d70892c4f6a0b8d1e3f5a7c9b2d4e6f8a0b2",
"resource_name": "meeting room 2",
"start": 1782361200,
"status": "confirmed"
}Resource and customer are denormalized onto the booking: calendar views show names without joins (see Storage Examples).
Checking Availability
- Query the resource's bookings overlapping the requested window:
start < requested_endANDend > requested_start. Two range filters on the same query viaquery_bool_range_field. - No overlaps → slot is free. Overlaps → return the conflicting bookings so the UI can show why.
- Generate the day's available slots from opening hours minus confirmed bookings, in the function: not in the page.
No Double-Booking
- The reservation flow first re-checks overlap (never trust the page's earlier check).
- Then it creates the booking with a status transition inside one mutation set: mutations process sequentially per document, so the last check and the write can't interleave (see mutations).
- On conflict: reply 409 with the overlapping booking. See error conventions.
- Cancellation is a status change to
cancelled. Never a delete. The audit trail and no-show stats survive.
Reminders
- A
schedule_repeating_eventruns hourly: query confirmed bookings starting within the next 24h wherereminder_sent = false. - Send each with the email pattern from Email System Setup, then set
reminder_sent = true: idempotent even if the run repeats. - Customers manage their own bookings with
user_current→ term query oncustomer_guid.
