Availability recalculated after each booking without requiring full page reload
Why it matters
When the calendar does not refresh after a successful booking, the just-booked slot still appears green and selectable. A second customer in the same session clicks it, hits a 409 conflict from the server, and sees a generic error. This creates double-booking races, duplicate conflict-handling work, and a confusing 'did my booking go through?' moment that drives support contacts. The defect also misleads the original user, who may refresh and fear their booking failed.
Severity rationale
Low because server-side uniqueness constraints prevent actual double bookings; impact is confined to UX confusion and retry friction.
Remediation
After the booking POST resolves with response.ok, immediately refetch availability (or call queryClient.invalidateQueries(['availability']) with React Query) before showing the success toast. Prefer cache invalidation over manual setSlots so stale data anywhere in the tree clears too. See src/hooks/useBooking.ts:
if (response.ok) {
await queryClient.invalidateQueries({ queryKey: ['availability'] })
toast.success('Booking confirmed!')
}
Detection
-
ID:
live-availability-update -
Severity:
low -
What to look for: Trace the booking success handler. After a successful
POSTto the booking API, look for at least 1 of these update mechanisms: (1) API refetch of availability (e.g.,fetch('/api/availability')after booking response), (2) optimistic UI update (e.g.,setSlots(prev => prev.filter(...))), (3) React Query/SWR invalidation (e.g.,queryClient.invalidateQueries), (4) WebSocket/real-time subscription. Count all booking success paths and verify each triggers a calendar update. Examine files matchingsrc/components/*Booking*,src/components/*Calendar*,src/hooks/*booking*. -
Pass criteria: Count all booking success code paths. 100% of booking success handlers must trigger a calendar data update (refetch, optimistic update, cache invalidation, or real-time push) without requiring a full page reload. At least 1 update mechanism must exist. Report: "Update mechanism: [refetch/optimistic/invalidation/websocket]. X of Y success paths trigger update."
-
Fail criteria: Calendar does not reflect the new booking until the page is manually refreshed by the user.
-
Skip (N/A) when: Calendar is display-only (no bookings are created from the calendar page).
-
Detail on fail: Example:
"After booking a slot successfully, the calendar still shows it as available. User must refresh the page to see the update." -
Cross-reference: Check
data-freshness— live update after booking complements fresh data on view load. -
Cross-reference: Check
performance-load-time— post-booking refetch should not block the UI or cause a full re-render. -
Cross-reference: Check
confirmation-calendar-parity— after update, the calendar time must match the confirmation time. -
Remediation: Refetch availability after a booking:
async function handleBooking(slot) { try { const response = await fetch('/api/appointments', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(slot), }) if (response.ok) { // Refetch availability const availResponse = await fetch('/api/availability') const newSlots = await availResponse.json() setSlots(newSlots) toast.success('Booking confirmed!') } } catch (error) { toast.error('Booking failed') } }
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-calendar-availability·automated