specs
Reservation Management

Reservation Management — House of Legends

Documented: 2026-05-11


Overview

Staff manage reservations via the admin dashboard — view list, filter, and take actions (cancel, refund, check-in).


Reservations Table

reservations: defineTable({
  eventId: v.id("experienceEvents"),
  customerFirstName: v.string(),
  customerLastName: v.string(),
  customerEmail: v.string(),
  customerPhone: v.string(),
  ticketType: v.union(
    v.literal("DINNER_THEATRE"),
    v.literal("EXPERIENCE_ONLY"),
  ),
  quantity: v.number(),
  addOns: v.record(v.string(), v.number()),
  subtotal: v.number(),
  totalAmount: v.number(),
  dayOfWeekSurcharge: v.number(),
  smallPartySurcharge: v.number(),
  paymentStatus: v.union(
    v.literal("PENDING"),
    v.literal("PAID"),
    v.literal("REFUNDED"),
    v.literal("FAILED"),
    v.literal("CANCELLED"),
    v.literal("REFUND_PENDING"),
  ),
  paymentGateway: v.optional(v.string()),
  onePayOrderId: v.optional(v.string()),
  onePayTransactionId: v.optional(v.string()),
  vaNumber: v.optional(v.string()),
  qrCode: v.optional(v.string()),
  qrCodeUrl: v.optional(v.string()),
  paymentExpiresAt: v.optional(v.number()),
  bookingExpiresAt: v.optional(v.number()),
  checkedInAt: v.optional(v.number()),
  createdAt: v.number(),
})
  .index("by_event", ["eventId"])
  .index("by_status", ["paymentStatus"])
  .index("by_email", ["customerEmail"]);

Reservation List (/dashboard/reservations)

Table Columns

ColumnSource
IDreservation._id (short)
Guest${firstName} ${lastName}
EmailcustomerEmail
PhonecustomerPhone
EventexperienceEvents lookup
TypeticketType
Qtyquantity
TotaltotalAmount formatted
StatuspaymentStatus badge
DatecreatedAt formatted

Filters

  • Status: PENDING, PAID, CANCELLED, REFUNDED
  • Date range: Created between dates
  • Event: Specific experience or all
  • Search: Name, email, phone

Status Badges

StatusBadge ColorMeaning
PENDINGYellowAwaiting payment
PAIDGreenPayment confirmed
REFUND_PENDINGOrangeRefund requested
REFUNDEDGrayRefund completed
CANCELLEDRedCancelled
FAILEDRedPayment failed

Reservation Detail (Drawer)

Opens on row click:

Guest Info

  • Full name, email, phone
  • Booking created timestamp

Event Info

  • Experience name
  • Date + time
  • Venue

Ticket Info

  • Ticket type (Dinner Theatre / Show Only)
  • Quantity
  • Unit price

Add-ons

  • List of add-ons with quantities

Pricing Summary

  • Subtotal
  • Day-of-week surcharge
  • Small party surcharge
  • Total

Payment Info

  • Gateway (OnePay)
  • Order ID
  • Transaction ID
  • VA Number (if bank transfer)
  • QR code preview

Status History

  • Created
  • Payment confirmed (if PAID)
  • Checked in (if applicable)

Actions

ActionMutationCondition
Cancelreservations.cancelPENDING or PAID
Refundreservations.refundPAID only
Check-incheckIns.createPAID not yet checked in
Resend confirmationnotifications.sendConfirmationAny status

Cancel Flow

  1. Staff clicks "Cancel"
  2. Confirmation dialog
  3. reservations.cancel called
  4. Status → CANCELLED
  5. event.bookedCount decremented
  6. Notification sent to guest (if PAID → refund flow)

Refund Flow

  1. Staff clicks "Refund"
  2. Confirmation dialog
  3. reservations.refund called
  4. Status → REFUND_PENDING
  5. OnePay refund API called
  6. Status → REFUNDED on success
  7. Notification sent to guest

Check-in

Located at /dashboard/checkin:

  • QR scanner (camera)
  • Manual lookup by reservation ID

On scan/lookup:

  • Shows guest details + party size
  • "Check In" button
  • Creates checkIns record
  • Updates reservation.checkedInAt

Backend Functions

FunctionPurpose
reservations.listAll reservations with filters
reservations.getByIdSingle reservation detail
reservations.cancelCancel + release seats
reservations.refundProcess refund
checkIns.createRecord check-in
notifications.sendConfirmationResend confirmation email/WhatsApp