Skipping an explicit initial booking status causes payment-confirmation race conditions: if a booking defaults to 'confirmed' at insert time, a failed or pending payment leaves a confirmed reservation with no corresponding charge. Under CWE-841 (improper enforcement of behavioral workflow), the system's state machine collapses at the first edge case. Any downstream job that queries status = 'CONFIRMED' to send reminder emails or mark slots occupied will fire on unconfirmed bookings, producing phantom reservations, double-charges, or capacity miscounts that are extremely difficult to detect after the fact.
Medium because the defect corrupts booking state and triggers downstream side-effects, but does not directly expose customer data or enable unauthorized access.
Set status explicitly in the create call inside your booking service (e.g., src/lib/bookings.ts). Never rely on a database column default for a field whose initial value determines the entire lifecycle state machine.
const booking = await prisma.booking.create({
data: {
customerId,
slotId,
providerId,
status: 'PENDING', // explicit — never trust a DB default here
startTime,
endTime,
}
});
ID: booking-flow-lifecycle.booking-creation.initial-booking-state
Label: Initial booking state is explicit
Severity: medium
What to look for: Examine the booking creation logic — locate the primary createBooking function (typically in src/app/api/bookings/route.ts, src/lib/bookings.ts, src/services/booking-service.ts, or equivalent). Count every code path that creates a booking record and verify each one sets an explicit status field to a non-confirmed state like 'pending', 'initiated', or 'awaiting_payment'. At least 1 explicit status assignment must exist. Before evaluating, extract and quote the exact line(s) where the booking record is created, including the status field value.
Pass criteria: New bookings are created with a distinct "pending" or "initiated" status — the status field must be explicitly set (not relying on a database default). 100% of booking creation paths must set an explicit non-confirmed status. They do not default to 'confirmed' or 'paid' immediately unless no payment or approval is required. The initial status string must be one of: 'pending', 'initiated', 'awaiting_payment', 'draft', 'held', or an equivalent non-confirmed state. Report even on pass: "Initial booking status is set to '[STATUS_VALUE]' in [file:line]."
Fail criteria: Bookings are created directly as 'confirmed' or 'paid' before payment or validation is complete. Or no explicit status is set and the field defaults to null or undefined. Do NOT pass when the status field is omitted from the create call and relies on an implicit database default — explicit is required.
Skip (N/A) when: The project has no booking creation functionality (no booking/reservation model or API endpoint found).
Detail on fail: "Booking records are inserted with status='CONFIRMED' before payment is processed, creating risk for failed payments leaving confirmed bookings."
Cross-reference: The payment-capture-timing check in Payment Integration verifies the authorize-then-capture flow that depends on this initial pending state.
Cross-reference: The cancellation-state-machine check in Lifecycle Management verifies that status transitions from this initial state follow valid paths.
Cross-reference: The transaction-atomicity check in Conflict Prevention ensures this status set happens atomically with related writes.
Remediation: Initialize all bookings in a pending state. Only transition to confirmed after successful payment or explicit approval. Set the status explicitly in the create call in your booking service (e.g., src/lib/bookings.ts or src/services/booking-service.ts).
// Good: explicit initial state
const booking = await prisma.booking.create({
data: {
customerId,
slotId,
providerId,
status: 'PENDING', // Explicit initial state
startTime,
endTime,
}
});