feat: add real-time seat locking and booking confirmation flow#139
feat: add real-time seat locking and booking confirmation flow#139Johan621 wants to merge 5 commits into
Conversation
|
@Johan621 is attempting to deploy a commit to the niharika-mente's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughChangesThe booking flow now supports seat availability polling and temporary seat locks. Backend routes manage lock, confirm, release, cancellation, and expiration states transactionally, while the booking model and existing queries scope records to confirmed bookings. Seat booking lifecycle
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/actions/booking.actions.ts (1)
29-35: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftRemove the direct-confirm capacity bypass.
createBooking()inserts a confirmed booking without acquiring capacity or checking locked/confirmed seat totals. Any remaining caller can overbook independently of the new state machine. Route this through the same atomic reservation workflow.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/actions/booking.actions.ts` around lines 29 - 35, Update createBooking to stop directly inserting a confirmed Booking record; route new reservations through the existing atomic capacity-reservation workflow, including locked and confirmed seat checks, before creating or confirming the booking. Reuse the established reservation/state-machine method and preserve the current booking inputs and seat count.Source: Coding guidelines
🧹 Nitpick comments (1)
app/api/events/[slug]/register/route.ts (1)
70-81: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShare typed booking contracts across the API and client.
The request/response shapes are still defined ad hoc (anybodies,anyevent casts, andprev as anymerges). Move the lock/confirm/release payloads and availability response into shared types soregister/route.ts,availability/route.ts, andcomponents/BookEvent.tsxcan stop guessing at the schema.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/api/events/`[slug]/register/route.ts around lines 70 - 81, Define shared typed contracts for lock, confirm, and release request payloads plus the availability response, then reuse them across app/api/events/[slug]/register/route.ts (lines 70-81, 116-117, and 129-131), app/api/events/[slug]/availability/route.ts (lines 72-79), and components/BookEvent.tsx (lines 113, 151, and 188). Replace ad hoc any bodies, event casts, and prev as any merges with the shared symbols, preserving the existing action-specific fields and response behavior.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/api/events/`[slug]/availability/route.ts:
- Around line 96-103: Update the catch blocks in
app/api/events/[slug]/availability/route.ts lines 96-103 and
app/api/events/[slug]/register/route.ts lines 290-304 to catch errors as
unknown, retain internal console.error logging, and return the generic 500
response without exposing an error property or exception details.
- Line 55: The booking lifecycle must use server actions rather than prohibited
API routes. In app/api/events/[slug]/availability/route.ts at line 55, move
availability retrieval and expiry into the appropriate lib/actions/*.actions.ts
data-layer action; in app/api/events/[slug]/register/route.ts at line 59, move
lock, confirm, and release transitions into the same server-action layer,
leaving only the permitted event GET API route.
In `@app/api/events/`[slug]/register/route.ts:
- Around line 145-176: The registration flow in
app/api/events/[slug]/register/route.ts, around getSeatStats and Booking.create,
must replace the aggregate-then-insert TOCTOU sequence with an atomic
conditional reservation update against a single event document, preserving
capacity checks and lock behavior. Remove the direct confirmed-booking insertion
in lib/actions/booking.actions.ts around the booking creation action so all
reservations use the centralized atomic invariant.
- Around line 121-123: Update the event lookup flow in the transaction callback
to check whether event exists before reading its slug, returning the existing
missing-event response instead of dereferencing null. Define eventSlug in a
scope that remains available where it is used after the callback, including the
reference near the registration handling logic, while preserving the transaction
behavior for valid events.
- Around line 30-50: Update getSeatStats() to execute the confirmed and locked
Booking.aggregate queries sequentially when using the transaction session,
replacing the Promise.all pattern with separate awaits while preserving both
aggregate pipelines and their results.
In `@components/BookEvent.tsx`:
- Around line 218-225: Update the seats input in BookEvent to include step={1},
and change its onChange normalization to accept only finite integer values,
handling invalid or NaN input consistently before calling setSeats. Preserve the
existing disabled behavior and minimum-seat constraint.
- Around line 61-73: Update the secondsLeft countdown in BookEvent to refresh
from a one-second timer rather than availability?.serverTime changes. Add
timer-driven state or invalidation so the displayed countdown and the existing
lockId expiry effect continue updating and clearing the lock even when
availability polling fails.
In `@database/booking.model.ts`:
- Around line 48-53: Enforce whole-number seat counts across all affected
layers: update the seats schema in database/booking.model.ts to validate
integers, add integer validation to the request handling in
app/api/events/[slug]/register/route.ts, and set the seats input in
components/BookEvent.tsx to step by 1. Preserve the existing minimum-of-one
validation.
- Around line 48-65: Update the booking migration/setup around the model’s
status, seats, and lockExpiresAt fields to backfill legacy records with status
"confirmed", seats 1, and lockExpiresAt null. Detect and remove the older
unconditional unique booking index, then recreate the compound index using the
new partial rule so only applicable records enforce uniqueness.
In `@lib/actions/booking.actions.ts`:
- Around line 85-88: Update getBookingsCountByEventId to aggregate the seats
field for confirmed bookings matching eventId instead of using countDocuments(),
so the returned count represents attendees rather than booking documents.
Preserve the existing confirmed-status filter and return the summed seats value.
---
Outside diff comments:
In `@lib/actions/booking.actions.ts`:
- Around line 29-35: Update createBooking to stop directly inserting a confirmed
Booking record; route new reservations through the existing atomic
capacity-reservation workflow, including locked and confirmed seat checks,
before creating or confirming the booking. Reuse the established
reservation/state-machine method and preserve the current booking inputs and
seat count.
---
Nitpick comments:
In `@app/api/events/`[slug]/register/route.ts:
- Around line 70-81: Define shared typed contracts for lock, confirm, and
release request payloads plus the availability response, then reuse them across
app/api/events/[slug]/register/route.ts (lines 70-81, 116-117, and 129-131),
app/api/events/[slug]/availability/route.ts (lines 72-79), and
components/BookEvent.tsx (lines 113, 151, and 188). Replace ad hoc any bodies,
event casts, and prev as any merges with the shared symbols, preserving the
existing action-specific fields and response behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c5ac0556-22ba-4fbe-af5f-31b620fe7bd0
📒 Files selected for processing (6)
app/api/events/[slug]/availability/route.tsapp/api/events/[slug]/register/route.tscomponents/BookEvent.tsxcomponents/EventDetails.tsxdatabase/booking.model.tslib/actions/booking.actions.ts
Description
This PR improves event booking by adding a temporary seat lock system and live availability updates.
What’s changed
Added booking states: locked, confirmed, cancelled, expired
Added 10-minute temporary lock before final confirmation
Updated register API to support lock, confirm, and release actions
Added availability API to return real-time seat counts
Updated booking UI to show:
available / locked / booked seats
lock countdown timer
confirm and release actions
Updated booking count/list logic to include only confirmed bookings
Why
This prevents overbooking during concurrent bookings and gives users a clearer booking experience.
Tested
Locked seats from one tab and verified availability update in another tab
Confirmed booking after lock
Released lock and verified seat restoration
Checked overbooking conflict behavior
Closes issue #40