Booking Status Machine

Every booking progresses through a finite set of states. Transitions are enforced in application code and validated by the booking_status column (enum stored as string via HasConversion<string>() in EF Core, with a CHECK constraint at the database level).

booked
confirmed
completed
Admin confirms or payment recorded                24h after session end
Mandatory reason code
cancelled
Can be reached from booked or confirmed
No check-in after session
no_show
Can only be reached from confirmed

4 Booking Channels

Bookings enter the system through four distinct channels, each with different user flows and business characteristics.

Admin Channel 70.6% of volume

Operators create bookings for walk-in and phone customers via the web admin dashboard. This is the dominant channel today and will remain high-volume even as customer self-booking grows.

Field Manager Channel FM App

On-site staff create bookings from the FM mobile app. Field managers are scoped to their assigned fields only — they cannot see or book other fields.

Customer Channel 2.5%, target 15%+

Authenticated customers self-book through the mobile app. Currently the smallest channel, but growing it is a top business priority. Uses slot holds to prevent conflicts during the booking flow.

Contract Channel 6.8%

Automated generation from recurring agreements. Contract bookings have the lowest cancellation rate at 12.7%, making them the most reliable revenue source.

Slot Hold Management

When a customer begins the booking form in the mobile app, a hold is placed on the selected slot to prevent another customer from booking the same time while the first customer is completing their form.

Hold lifecycle: Customer opens booking form → hold created → customer submits within 5 minutes → hold converted to booking. If the customer abandons the form, the hold expires automatically and the slot becomes available again.

Conflict Prevention

Double-booking prevention is enforced at the database level using a UNIQUE index on (field_id, date, start_time) combined with a serializable transaction or INSTEAD OF INSERT trigger that validates no overlapping time ranges. SQL Server will reject conflicting inserts. Even if application code has a bug, the database constraint prevents the double-booking.

In v2, conflict prevention was handled entirely in application code. The contract generator bypassed these checks, leading to 4 data corruption incidents where two bookings occupied the same field and time slot. In v3, the database itself enforces this invariant — no application code path can violate it.

Auto-Transitions (Background Jobs)

Background jobs handle automatic status progression so bookings never get stuck in stale states.

Transition Trigger Purpose
confirmedcompleted 24h after event end time Automatically marks sessions as completed after they occur
bookedcancelled 24h after session date if still unconfirmed Auto-cancels bookings that were never confirmed (no payment, no admin action)
v2 problem solved: 34.8% of bookings in v2 were stuck in stale status — confirmed sessions still showing as "upcoming" weeks after they occurred. Auto-transitions eliminate this entirely, ensuring the v3 target of 0% stale bookings.

Mandatory Fields on Every Booking

Field Type Description
field_id string (max 15 chars) Which field the booking is for
customer_id string (max 15 chars) Who booked (the customer)
creator_id string (max 15 chars) Who created the booking (may differ from customer — e.g., admin booking on behalf of customer)
date DATE Session date
start_time TIME Slot start time
end_time TIME Slot end time
status string (enum stored as string) Current state: booked, confirmed, completed, cancelled, no_show
source string (enum stored as string) Channel: admin, fm, customer, contract, guest
price DECIMAL, NOT NULL, > 0 Mandatory pricing — v2 had 58.3% of bookings with zero price. DB constraint prevents this.
payment_status string (enum stored as string) Payment state: unpaid, partial, paid, refunded

Cancellation

Cancellation is a controlled process with mandatory documentation to support business analysis and reduce cancellation rates.

Business target: Current same-day cancellation rate is 27.1%. The v3 target is 22%. Mandatory reason codes enable analysis of why cancellations happen, and the data will drive policy changes to reduce the rate.