Without a server-side availability check before insertion, two users submitting the booking form within milliseconds of each other will both receive success responses for the same slot. Frontend availability guards are client-controlled and can be bypassed entirely with a direct API call. OWASP A04 (Insecure Design) classifies trusting client-side state for server decisions as a structural flaw. A double-booked appointment slot means one customer shows up to find their slot occupied — a support and refund incident that a single server-side query would have prevented entirely.
Critical because the absence of server-side availability enforcement directly produces confirmed double-bookings, a business-critical data integrity failure that requires manual remediation for every occurrence.
Add the availability query in your booking API handler or service layer (e.g., src/app/api/bookings/route.ts) before the insert, not in a React component.
// Server-side only — never trust the client's slot state
const conflict = await db.booking.findFirst({
where: {
slotId: requestedSlotId,
status: { not: 'CANCELLED' }
}
});
if (conflict) throw new ConflictError('Slot unavailable');
const booking = await db.booking.create({ data: { ...bookingData } });
ID: booking-flow-lifecycle.booking-creation.conflict-check
Label: Availability is checked before creation
Severity: critical
What to look for: In the booking creation handler (e.g., POST /api/bookings, createBooking server action), look for a database query that checks if the requested time slot is available before the insertion query. This must be a server-side check, not just frontend validation. Count all code paths that create bookings and verify each one includes an availability check. Enumerate: "X of Y booking creation paths include a pre-insert availability check."
Pass criteria: An explicit availability query (e.g., count where startTime = requested_time AND status != 'CANCELLED') exists and runs before attempting to insert the new booking. The check must be server-side (in an API route, server action, or service layer). At least 1 server-side availability query must execute before every booking insert. Report: "X of Y booking creation paths include server-side availability checks." Do NOT pass when availability is only checked on the frontend (e.g., in a React component or client-side hook) — server-side validation is required.
Fail criteria: The code assumes availability (blind insert), or only checks availability on the frontend (e.g., useEffect or component-level check), or checks happen after the insert. Report: "0 of Y booking creation paths include server-side availability checks." or "Availability check found only in client component [file], not in server handler [file]."
Skip (N/A) when: Never — this is mandatory for any system with time-based slots.
Detail on fail: "No server-side availability check found in the createBooking handler. Relying on frontend checks only is unsafe."
Cross-reference: The slot-availability-recheck check in Conflict Prevention verifies this check is repeated inside the final transaction.
Cross-reference: The concurrent-request-handling check in Conflict Prevention verifies database-level constraints back up this application-level check.
Cross-reference: The overbooking-prevention check in this category verifies capacity-aware availability logic for multi-booking slots.
Remediation: Always query the database for conflicting bookings before creating a new record. Add the check in your booking API handler (e.g., src/app/api/bookings/route.ts) or service layer.
// Check availability first
const conflict = await db.booking.findFirst({
where: {
slotId: requestedSlotId,
status: { not: 'CANCELLED' }
}
});
if (conflict) throw new Error("Slot unavailable");
// Only then create
const booking = await db.booking.create({ data: {...} });