EP-003: Reservation Management
Business Objective
Reservations are the primary revenue pipeline for any hotel. Every confirmed booking represents committed revenue; every lost or mismanaged booking represents direct financial loss. This epic covers the complete reservation lifecycle from initial booking through check-out, supporting 13 booking sources (OTA, direct, walk-in, corporate), multi-room stays, group bookings with allotments, waitlist management, and real-time availability calculations. In the Indian hospitality market, hotels must handle walk-ins (30-40% of bookings for budget/mid-segment), OTA parity requirements, and GST-compliant invoicing. The system must process 500+ concurrent availability checks during peak booking windows without degradation.
Audience
- Primary: Reservations Agent, Front Desk Agent (create/modify/cancel bookings)
- Secondary: Manager (group bookings, overbooking decisions), Revenue Manager (availability controls, restrictions)
- Tertiary: Guest (via booking engine), OTA Channels (via channel manager)
Scope
In Scope
- Reservation CRUD with 6 statuses: CONFIRMED, CHECKED_IN, CHECKED_OUT, CANCELLED, NO_SHOW, WAITLISTED (plus PENDING for payment-pending bookings)
- 13 booking sources: DIRECT, BOOKING_COM, EXPEDIA, AGODA, MAKEMYTRIP, GOIBIBO, AIRBNB, GDS, CORPORATE, TRAVEL_AGENT, WALKIN, BOOKING_ENGINE, OTHER
- Multi-room reservations (one guest, multiple room types/rooms across dates)
- Confirmation number generation (unique, property-prefixed)
- Guest lookup and linking during reservation creation
- Arrival and departure date management with length-of-stay calculation
- Room assignment (manual or auto-suggest based on preferences)
- Reservation search with filters (date range, status, source, guest name, confirmation number)
- Arrivals board, departures board, in-house guest list
- Group bookings with allotment blocks, rooming lists, cutoff dates
- Waitlist management with offer/accept workflow
- Real-time availability engine (inventory check across date range per room type)
- Inventory holds (temporary lock during booking flow with TTL expiry)
- Availability calendar (daily inventory breakdown per room type)
- Reservation modification tracking (ReservationHistory with changes JSON)
- Cancellation with reason tracking and policy-based charge calculation
- No-show processing
- Payment initiation, verification, webhook handling, refunds (Razorpay integration)
- Payment link generation for pre-arrival payment collection
- Routing rules for charge routing (room, F&B, tax to different folios)
- Overbooking controls
Out of Scope
- Booking engine UI (covered in EP-010)
- Channel manager sync (covered in EP-009)
- Folio management (covered in EP-005 -- Front Desk Operations)
- Dynamic pricing / yield management algorithms (covered in EP-012)
Current Implementation Status
- Backend (reservation-service): Fully built.
ReservationsControllerwithPOST /reservations(5 roles),GET /properties/:propertyId/reservations,GET /reservations/:id,GET /reservations/confirmation/:confirmationNumber,PUT /reservations/:id,DELETE /reservations/:id(cancel withCancelReservationDto),POST /reservations/searchwithSearchReservationsDto,POST /reservations/assign-roomwithAssignRoomDto,POST /reservations/:id/no-show. Arrivals (GET /properties/:propertyId/arrivals?date=), departures, in-house list.@Auditdecorator on create/update/cancel/assign/no-show. - Backend (availability):
AvailabilityController--POST /availability/check(public),GET /availability(public, query params),POST /availability/hold,GET /availability/hold/:holdId,DELETE /availability/hold/:holdId(204),GET /inventory/:propertyId/:roomTypeId?startDate=&endDate=(inventory calendar). - Backend (groups):
GroupsController--POST /groups,GET /properties/:propertyId/groups,GET /groups/:id,PUT /groups/:id,DELETE /groups/:id(cancel with reason),POST /groups/:id/confirm,POST /groups/:id/reservations(add rooms),GET /groups/:id/rooming(rooming list). Group model with type (GROUP, ALLOTMENT, BLOCK), status (TENTATIVE, CONFIRMED, CANCELLED), cutoff date, rooms blocked/confirmed/picked-up. - Backend (waitlist):
WaitlistController--POST /waitlist,GET /waitlist(filter by property, roomType, status),DELETE /waitlist/:id,POST /waitlist/:id/accept. Statuses: WAITING, OFFERED, ACCEPTED, EXPIRED, CANCELLED. - Backend (payments):
PaymentsController--POST /payments/initiate,POST /payments/verify,POST /payments/webhook(Razorpay signature verification),POST /payments/refund,GET /payments/:id/status. - Backend (routing):
RoutingRulesControllerexists for charge routing. - Dashboard: Reservations list page with filters. Calendar view. Groups page. Reservation form with guest lookup, date picker, room type selector, rate plan selector, source dropdown. Amend dialog for modifications. Arrivals/departures/in-house tabs in Front Desk module.
Gap Analysis
- Group Booking UI: Backend is comprehensive (CRUD, confirm, add reservations, rooming list). Dashboard groups page exists but needs polish: allotment block visual (date x room-type grid showing blocked vs. picked-up vs. available), rooming list upload from Excel, group folio summary. Impact: High for MICE (Meetings, Incentives, Conferences, Events) segment hotels.
- Waitlist Management UI: Backend is complete. Dashboard lacks a dedicated waitlist view with offer/accept workflow visualization. Staff must use API directly. Impact: Medium -- hotels with high demand periods need this.
- Overbooking Controls:
OverbookingControllerexists in analytics-service but is not configurable per room type from the dashboard. Hotels need to set overbooking % per room type (e.g., allow 5% overbooking on Standard, 0% on Suite). Impact: High for revenue optimization at city hotels with 90%+ occupancy. - Cancellation Charge Automation: Cancellation policies exist and are linked to rate plans, but the actual charge calculation at cancellation time is not automated. The agent manually enters the cancellation charge. Impact: Medium -- can lead to inconsistent charge application.
- Payment Link Delivery: Payment link generation exists via Razorpay integration. However, sending the link via SMS/WhatsApp is not integrated (notification-service exists but not wired to payment flow). Impact: Medium for pre-arrival payment collection.
- Modification Tracking UI:
ReservationHistorymodel records all changes as JSON. Dashboard lacks a visual modification history timeline on the reservation detail page. Impact: Low -- data exists, UI needed. - Bulk Operations: No bulk cancellation, bulk room assignment, or bulk status update for group bookings. Impact: Medium for group check-in scenarios.
User Stories
| Story ID | Title | Priority | Points | Status | Sprint |
|---|---|---|---|---|---|
| US-003-001 | Create Individual Reservation | P0 | 5 | Built | 2 |
| US-003-002 | Multi-Room Reservation | P0 | 5 | Built | 2 |
| US-003-003 | Reservation Search & Filters | P0 | 5 | Built | 2 |
| US-003-004 | Reservation Modification | P0 | 5 | Built | 3 |
| US-003-005 | Reservation Cancellation with Policy Enforcement | P0 | 5 | Built | 3 |
| US-003-006 | Real-Time Availability Engine | P0 | 8 | Built | 2 |
| US-003-007 | Inventory Hold (Temporary Lock) | P0 | 3 | Built | 2 |
| US-003-008 | Room Assignment | P0 | 5 | Built | 3 |
| US-003-009 | Arrivals / Departures / In-House Boards | P0 | 5 | Built | 3 |
| US-003-010 | No-Show Processing | P0 | 3 | Built | 3 |
| US-003-011 | Confirmation Number Generation & Lookup | P0 | 2 | Built | 2 |
| US-003-012 | Group Booking CRUD | P1 | 8 | Built | 4 |
| US-003-013 | Group Allotment & Rooming List | P1 | 8 | Partial | 5 |
| US-003-014 | Waitlist Management | P1 | 5 | Partial | 5 |
| US-003-015 | Payment Initiation & Verification (Razorpay) | P1 | 8 | Built | 4 |
| US-003-016 | Payment Link Generation & Delivery | P1 | 5 | Partial | 6 |
| US-003-017 | Reservation Modification History | P1 | 3 | Partial | 5 |
| US-003-018 | Overbooking Control Configuration | P2 | 5 | Partial | 8 |
| US-003-019 | Cancellation Charge Auto-Calculation | P2 | 5 | Not Started | 8 |
| US-003-020 | Charge Routing Rules | P2 | 5 | Built | 6 |
| US-003-021 | Bulk Group Check-In & Room Assignment | P2 | 8 | Not Started | 10 |
| US-003-022 | Availability Calendar Visualization | P2 | 5 | Partial | 8 |
Dependencies
- EP-001 (Auth): All reservation operations require authenticated users with appropriate roles.
- EP-002 (Property): Reservations depend on room types, rooms, rate plans, and cancellation policies.
- EP-004 (Guest): Reservations link to guest profiles (guestId FK).
- EP-005 (Front Desk): Check-in/out transitions are handled by front desk service.
- EP-009 (Channel Manager): OTA bookings flow through channel service into reservation service.
Acceptance Criteria (Epic Level)
- Reservations can be created from all 13 booking sources with complete data capture
- Multi-room reservations link multiple room types/rooms to a single confirmation number
- Real-time availability checks complete in < 500ms for 30-day date ranges
- Inventory holds expire after configurable TTL (default 15 minutes)
- Group bookings support allotment blocks with cutoff dates and rooming lists
- Cancellation applies the correct policy-based charges automatically
- No-show processing marks reservations and applies no-show charges
- Payment can be collected via Razorpay (UPI, card, net banking)
- All modifications are tracked in ReservationHistory with before/after JSON
- Waitlist entries can be offered rooms when availability opens and accepted by guest
KPIs / Success Metrics
- Reservation creation success rate: > 99.5%
- Availability check p95 latency: < 500ms
- Double-booking rate: 0% (except controlled overbooking)
- Cancellation policy compliance: 100% (charges match policy rules)
- Group pickup rate tracking: visible per group with cutoff date alerts
- Payment collection rate (pre-arrival): > 60% for advance payment rate plans
Detailed User Stories
US-003-001: Create Individual Reservation
As a reservations agent, I want to create a reservation by selecting guest, dates, room type, and rate plan, So that the hotel has a confirmed booking with all details captured for arrival preparation.
Priority: P0 | Points: 5 | Sprint: 2 | Status: Built
Implementation Status
- Backend:
POST /reservationswithCreateReservationDto. Accepts guestId, propertyId, arrivalDate, departureDate, adults, children, roomReservations (array of roomTypeId + ratePlanId), source, specialRequests, internalNotes, promoCode. Returns created reservation with confirmationNumber, totalAmount, taxAmount, balanceDue.@Auditlogged. Roles: SUPER_ADMIN, ADMIN, MANAGER, RESERVATIONS, FRONT_DESK. - Frontend: Reservation form with guest lookup (search-as-you-type), date range picker, room type selector with availability indicator, rate plan dropdown, source selector (13 options), special requests textarea.
Acceptance Criteria
Scenario: Create a reservation for a returning guest
Given the reservations agent searches for guest "Rajesh Sharma" and finds the profile
When they create a reservation with arrival 2026-04-15, departure 2026-04-18 (3 nights),
room type "Deluxe", rate plan "Rack Rate" at INR 5500/night, source DIRECT,
special requests "High floor, non-smoking"
Then a reservation is created with status CONFIRMED
And a unique confirmation number is generated (e.g., "GPH20260415001")
And totalAmount is INR 16,500 (3 x 5,500) plus applicable GST
And the reservation appears in the arrivals board for April 15
Scenario: Prevent reservation when no availability
Given all Deluxe rooms are sold out for April 20
When the agent attempts to create a reservation for Deluxe on April 20-21
Then the system returns 409 with message "No availability for Deluxe Room on 2026-04-20"
Scenario: Create OTA-sourced reservation
Given a booking is received from Booking.com
When the reservation is created with source BOOKING_COM, sourceReference "BDC-123456"
Then the reservation records the OTA source and reference ID for reconciliation
And the channelId links to the Booking.com channel connection
US-003-002: Multi-Room Reservation
As a reservations agent, I want to book multiple rooms of different types under a single reservation, So that a family or corporate traveler has one confirmation number for their entire stay.
Priority: P0 | Points: 5 | Sprint: 2 | Status: Built
Implementation Status
- Backend:
CreateReservationDtoacceptsroomReservationsas an array, each with roomTypeId, ratePlanId, checkInDate, checkOutDate, adults, children. Creates oneReservationwith multipleRoomReservationrecords. - Frontend: "Add Room" button on reservation form to add additional room lines.
Acceptance Criteria
Scenario: Book two rooms for a family trip
Given a guest requests 1 Deluxe and 1 Standard room for April 10-13
When the agent creates a reservation with 2 room reservations:
- Deluxe, Rack Rate, 2 adults, 0 children
- Standard, Rack Rate, 2 adults, 1 child (extra child charge INR 600/night)
Then one reservation is created with one confirmation number
And totalAmount includes: Deluxe (5500 x 3) + Standard (3500 x 3) + extra child (600 x 3) = INR 28,800 plus GST
And both room reservations are linked to the single reservation record
Scenario: Different date ranges for rooms in same reservation
Given a guest arrives April 10 but their colleague joins on April 11
When the agent creates a multi-room reservation:
- Room 1: April 10-13 (3 nights)
- Room 2: April 11-13 (2 nights)
Then the reservation arrival date is April 10 (earliest) and departure is April 13 (latest)
And each room reservation has its own check-in and check-out dates
US-003-003: Reservation Search & Filters
As a front desk agent, I want to search reservations by confirmation number, guest name, date range, status, or source, So that I can quickly locate any booking in the system.
Priority: P0 | Points: 5 | Sprint: 2 | Status: Built
Implementation Status
- Backend:
POST /reservations/searchwithSearchReservationsDto. Supports filters: confirmation number, guest name (fuzzy), arrival/departure date range, status (array), source (array), groupId. Pagination viaPaginationDto. Also:GET /reservations/confirmation/:confirmationNumberfor exact lookup. - Frontend: Reservation list page with search bar and filter sidebar (date range, status checkboxes, source dropdown).
Acceptance Criteria
Scenario: Search by partial guest name
Given there are 50 reservations, 3 belonging to guests with surname "Sharma"
When the agent searches with guest name "Sharma"
Then 3 reservations are returned matching the surname, ordered by arrival date
Scenario: Filter today's arrivals by OTA source
Given 20 arrivals are expected today from various sources
When the agent filters by date "today" and source ["BOOKING_COM", "MAKEMYTRIP"]
Then only reservations from those two OTA sources are shown
And results include confirmation number, guest name, room type, and source
Scenario: Lookup by confirmation number
Given a guest calls with confirmation number "GPH20260415001"
When the agent calls GET /reservations/confirmation/GPH20260415001
Then the exact reservation is returned with full details including guest, rooms, and payment status
US-003-004: Reservation Modification
As a reservations agent, I want to modify reservation dates, room type, rate plan, or guest count, So that changes are captured with a full audit trail and the guest's updated requirements are met.
Priority: P0 | Points: 5 | Sprint: 3 | Status: Built
Implementation Status
- Backend:
PUT /reservations/:idwithUpdateReservationDto. Captures@CurrentUser()for audit.@Auditdecorator logs changes.ReservationHistorymodel records action "MODIFIED" with changes JSON (old/new values). - Frontend: "Amend" dialog on reservation detail page with editable fields.
Acceptance Criteria
Scenario: Extend stay by 2 nights
Given reservation GPH20260415001 is for April 15-18 (3 nights) at INR 16,500
When the agent extends departure to April 20 (now 5 nights)
Then the reservation is updated with new departure date
And totalAmount is recalculated to INR 27,500 (5 x 5,500) plus GST
And a ReservationHistory record is created: action "MODIFIED",
changes { "departureDate": { "old": "2026-04-18", "new": "2026-04-20" }, "totalAmount": { "old": 16500, "new": 27500 } }
Scenario: Upgrade room type
Given the guest requests an upgrade from Standard to Deluxe
When the agent changes the room type on the reservation
Then availability is checked for Deluxe on the stay dates
And the rate is recalculated at the Deluxe rate
And the modification is recorded with old and new room type
Scenario: Reject modification that exceeds availability
Given all Suite rooms are sold out for April 16
When the agent attempts to upgrade a reservation to Suite for April 15-18
Then the system returns 409 with message "No availability for Suite on 2026-04-16"
And the reservation remains unchanged
US-003-005: Reservation Cancellation with Policy Enforcement
As a reservations agent, I want to cancel a reservation and apply the correct cancellation charges per policy, So that the hotel collects appropriate compensation for late cancellations.
Priority: P0 | Points: 5 | Sprint: 3 | Status: Built
Implementation Status
- Backend:
DELETE /reservations/:idwithCancelReservationDto(includes cancellation reason). Sets status to CANCELLED, records cancelledAt, cancelledBy, cancellationReason.@Auditlogged. Roles: SUPER_ADMIN, ADMIN, MANAGER, RESERVATIONS. - Gap: Cancellation charge is not auto-calculated from the linked cancellation policy. Agent must specify the charge manually.
Acceptance Criteria
Scenario: Cancel reservation with flexible policy (free cancellation)
Given reservation GPH20260415001 has the "Flexible" cancellation policy
and arrival is 10 days away
When the agent cancels with reason "Guest travel plans changed"
Then the reservation status changes to CANCELLED
And cancelledAt and cancellationReason are recorded
And no cancellation charge is applied (10 days > 7-day free cancellation window)
And the room inventory is released back to availability
Scenario: Late cancellation incurs first-night charge
Given reservation GPH20260420001 has the "Flexible" policy and arrival is 2 days away
When the agent cancels with reason "Personal emergency"
Then the reservation is cancelled
And the system indicates a 100% first-night charge applies (within 0-3 day window)
And the cancellation charge amount is recorded for billing
Scenario: Cancel non-refundable reservation
Given the reservation was booked on a "Non-Refundable" rate plan
When the agent cancels the reservation
Then a warning is shown: "This is a non-refundable booking. Full stay charges apply."
And upon confirmation, the reservation is cancelled with full charge retained
US-003-006: Real-Time Availability Engine
As a reservations agent or booking engine, I want to check room availability for a given property, date range, and occupancy, So that only available room types and rates are offered to the guest.
Priority: P0 | Points: 8 | Sprint: 2 | Status: Built
Implementation Status
- Backend:
AvailabilityController-- two availability check endpoints (POST and GET, both@Public()).POST /availability/checkacceptsCheckAvailabilityDto(propertyId, checkInDate, checkOutDate, adults, children, optional roomTypeId, ratePlanId, promoCode).GET /availabilitywith query params (same fields). Returns available room types with rates, room counts, and applicable restrictions. - Inventory Calendar:
GET /inventory/:propertyId/:roomTypeId?startDate=&endDate=returns daily breakdown of total rooms, sold rooms, blocked rooms, available rooms.
Acceptance Criteria
Scenario: Check availability for a 3-night stay
Given the property has 20 Deluxe rooms and 15 are booked for April 15-18
When availability is checked for April 15-18, 2 adults
Then the response includes Deluxe Room with 5 available rooms
And the rate for the Rack Rate plan is returned (INR 5500/night or date-level rate if set)
And room types with zero availability are excluded from results
Scenario: Availability check respects restrictions
Given the Rack Rate has minLOS 3 for April 20-26 (Diwali week)
When availability is checked for April 20-21 (1 night only)
Then the Rack Rate plan is not returned for that search
And other rate plans without the restriction may still appear
Scenario: Promo code applies discounted rate
Given a promo code "SUMMER20" offers 20% off the Rack Rate
When availability is checked with promoCode "SUMMER20"
Then the response includes discounted rates for applicable room types
And the original rate and discount amount are shown for transparency
US-003-007: Inventory Hold (Temporary Lock)
As a booking engine, I want to place a temporary hold on inventory while the guest completes payment, So that the room is not double-booked during the checkout flow.
Priority: P0 | Points: 3 | Sprint: 2 | Status: Built
Implementation Status
- Backend:
POST /availability/holdwithCreateHoldDto-- creates a temporary inventory hold with TTL.GET /availability/hold/:holdIdchecks hold status.DELETE /availability/hold/:holdIdreleases the hold. Returns holdId and expiry timestamp.
Acceptance Criteria
Scenario: Create and release an inventory hold
Given 3 Deluxe rooms are available for April 15-18
When the booking engine creates a hold for 1 Deluxe room
Then a holdId is returned with a 15-minute expiry
And availability now shows 2 Deluxe rooms available
And if the hold is released (DELETE), availability returns to 3
Scenario: Hold expires automatically after TTL
Given a hold was created 16 minutes ago with 15-minute TTL
When the booking engine checks hold status via GET /availability/hold/:holdId
Then the hold status is "expired"
And the inventory is automatically released
US-003-008: Room Assignment
As a front desk agent, I want to assign a specific room to a reservation based on guest preferences, So that the guest gets a room that matches their requests (high floor, non-smoking, connecting).
Priority: P0 | Points: 5 | Sprint: 3 | Status: Built
Implementation Status
- Backend:
POST /reservations/assign-roomwithAssignRoomDto(roomReservationId, roomId). Links a specific Room to a RoomReservation record.@Auditlogged. - Frontend: Room assignment dialog with available rooms list filtered by room type, showing room features.
Acceptance Criteria
Scenario: Assign a high-floor non-smoking room
Given a reservation requests "High floor, non-smoking" and the room type is Deluxe
When the front desk agent views available Deluxe rooms filtered by isSmoking=false
Then rooms on floors 4 and 5 are shown with their features
And the agent assigns room 502 (5th floor, non-smoking, city-view)
And the room reservation record is updated with roomId for room 502
Scenario: Prevent double-assignment of a room
Given room 502 is already assigned to another reservation for overlapping dates
When the agent attempts to assign room 502 to a second reservation
Then the system returns 409 with message "Room 502 is already assigned for these dates"
US-003-009: Arrivals / Departures / In-House Boards
As a front desk agent, I want to view today's arrivals, departures, and in-house guests, So that I can prepare for incoming guests, process checkouts, and manage current occupancy.
Priority: P0 | Points: 5 | Sprint: 3 | Status: Built
Implementation Status
- Backend:
GET /properties/:propertyId/arrivals?date=(both reservation-service and frontdesk-service have this endpoint),GET /properties/:propertyId/departures?date=,GET /properties/:propertyId/in-house. Returns reservation details with guest info, room assignments, and special requests. - Frontend: Three tabs in Front Desk module: Arrivals (today's expected check-ins), Departures (today's expected check-outs), In-House (currently checked-in guests).
Acceptance Criteria
Scenario: View today's arrivals board
Given 12 guests are expected to arrive today
When the front desk agent opens the Arrivals tab
Then 12 reservations are listed with: guest name, confirmation number, room type,
assigned room (if any), arrival time (if noted), special requests, VIP level
And reservations without room assignment are highlighted for action
Scenario: View departures with outstanding balances
Given 8 guests are expected to depart today
When the agent views the Departures tab
Then each departure shows: guest name, room number, balance due, checkout time
And guests with outstanding balance > 0 are flagged in red
Scenario: In-house list shows current occupancy
Given 65 rooms are currently occupied
When the agent views the In-House tab
Then 65 entries are shown with: guest name, room number, check-in date,
expected departure, nights remaining, and folio balance
US-003-010: No-Show Processing
As a front desk agent during night audit, I want to mark reservations as no-show when guests don't arrive by the cutoff time, So that rooms are released and no-show charges are applied per policy.
Priority: P0 | Points: 3 | Sprint: 3 | Status: Built
Implementation Status
- Backend:
POST /reservations/:id/no-show. Sets status to NO_SHOW, records noShowAt timestamp.@Auditlogged. Roles: SUPER_ADMIN, ADMIN, MANAGER, FRONT_DESK.
Acceptance Criteria
Scenario: Process no-show for a confirmed reservation
Given reservation GPH20260415005 is CONFIRMED but the guest has not arrived by midnight
When the night auditor marks the reservation as no-show
Then the reservation status changes to NO_SHOW
And noShowAt timestamp is recorded
And the assigned room (if any) is released
And a no-show charge (typically first night) is applied to the folio
Scenario: Cannot mark an already checked-in reservation as no-show
Given reservation GPH20260415003 has status CHECKED_IN
When the agent attempts to mark it as no-show
Then the system returns 409 with message "Reservation is already checked in"
US-003-011: Confirmation Number Generation & Lookup
As a guest calling the hotel, I want to look up my reservation using the confirmation number, So that the front desk can quickly find my booking without asking for other details.
Priority: P0 | Points: 2 | Sprint: 2 | Status: Built
Implementation Status
- Backend: Confirmation number is auto-generated and stored as unique field.
GET /reservations/confirmation/:confirmationNumberfor direct lookup.
Acceptance Criteria
Scenario: Unique confirmation number generation
Given the property code is "GPH" and the date is April 15, 2026
When a reservation is created
Then a confirmation number is generated in format "GPH{YYYYMMDD}{SEQ}" (e.g., "GPH20260415001")
And the number is unique across all reservations
Scenario: Quick lookup by confirmation number
Given a guest calls with confirmation number "GPH20260415001"
When the agent enters the number in the search field
Then the reservation is immediately displayed with full details
And response time is < 200ms (indexed lookup)
US-003-012: Group Booking CRUD
As a sales manager, I want to create group bookings for conferences, weddings, and corporate events, So that a block of rooms is reserved under a single group with shared billing and contact details.
Priority: P1 | Points: 8 | Sprint: 4 | Status: Built
Implementation Status
- Backend:
GroupsController-- full CRUD.POST /groups(SUPER_ADMIN, ADMIN, MANAGER, RESERVATIONS). Group fields: name, code, type (GROUP/ALLOTMENT/BLOCK), arrivalDate, departureDate, roomsBlocked, roomsConfirmed, roomsPickedUp, contactPerson, contactEmail, contactPhone, companyId, totalValue, cutoffDate, notes, status (TENTATIVE/CONFIRMED/CANCELLED).POST /groups/:id/confirm,DELETE /groups/:id(cancel with reason). - Frontend: Groups page with list, create/edit forms.
Acceptance Criteria
Scenario: Create a group booking for a corporate conference
Given TechCorp wants to book 25 rooms for a 3-day conference on May 10-12
When the sales manager creates a group with name "TechCorp Annual Meet",
type GROUP, 25 rooms blocked, cutoff date April 25, contact "Priya Patel",
linked to company "TechCorp Pvt Ltd"
Then the group is created with status TENTATIVE
And 25 rooms are blocked (not yet assigned to individual reservations)
Scenario: Confirm a tentative group
Given the "TechCorp Annual Meet" group is TENTATIVE and the contract is signed
When the sales manager confirms the group via POST /groups/:id/confirm
Then the group status changes to CONFIRMED
And the blocked room count remains at 25
Scenario: Cancel a group past cutoff date
Given the cutoff date has passed and only 10 of 25 rooms have been picked up
When the manager cancels the remaining 15 blocked rooms
Then the group's roomsBlocked is reduced to 10
And the released rooms return to general availability
US-003-013: Group Allotment & Rooming List
As a sales manager, I want to manage allotment blocks and generate rooming lists for groups, So that individual reservations within the group are tracked and rooms are assigned to named guests.
Priority: P1 | Points: 8 | Sprint: 5 | Status: Partial
Implementation Status
- Backend:
POST /groups/:id/reservationsadds individual reservations to a group.GET /groups/:id/roomingreturns the rooming list (list of reservations with guest names and room assignments). Group tracks roomsConfirmed and roomsPickedUp. - Gap: No allotment grid UI (date x room-type showing blocked/picked-up/available). No Excel upload for rooming list (bulk guest creation + reservation creation). No cutoff date automated release.
Acceptance Criteria
Scenario: Add individual reservations to a group
Given the "TechCorp Annual Meet" group has 25 rooms blocked
When the reservations agent adds a reservation for "Ankit Joshi" to the group
with room type Deluxe, May 10-12, rate plan "Corporate Rate"
Then the reservation is created linked to the group (groupId FK)
And the group's roomsPickedUp increments from 0 to 1
Scenario: View rooming list for a group
Given 15 of 25 rooms have been picked up with named guests
When the manager views GET /groups/:id/rooming
Then 15 entries are returned with: guest name, room type, assigned room (if any),
check-in date, check-out date, rate
And 10 remaining rooms show as unassigned/available for pickup
Scenario: Cutoff date enforcement
Given the cutoff date for the group is April 25
When a new room is attempted to be added on April 26
Then a warning is shown: "Cutoff date has passed. Adding rooms requires manager approval."
US-003-014: Waitlist Management
As a reservations agent, I want to add guests to a waitlist when their desired room type is sold out, So that they are automatically offered a room if availability opens due to cancellations.
Priority: P1 | Points: 5 | Sprint: 5 | Status: Partial
Implementation Status
- Backend:
WaitlistController--POST /waitlist(add guest with propertyId, guestId, guestName, guestEmail, guestPhone, roomTypeId, arrivalDate, departureDate, adults, children, notes).GET /waitlistwith filters (propertyId, roomTypeId, status).DELETE /waitlist/:id(remove).POST /waitlist/:id/accept(accept offer, creates reservation). Statuses: WAITING, OFFERED, ACCEPTED, EXPIRED, CANCELLED. - Gap: No automatic notification when room becomes available (WAITING -> OFFERED transition). No dashboard UI for waitlist management. No prioritization rules (VIP guests first, first-come-first-served, etc.).
Acceptance Criteria
Scenario: Add guest to waitlist for sold-out dates
Given all Deluxe rooms are sold out for Diwali weekend (Oct 20-22)
When the agent adds guest "Meera Iyer" to the waitlist for Deluxe, Oct 20-22
Then a waitlist entry is created with status WAITING and position in queue
And the guest's contact details are recorded for notification
Scenario: Accept a waitlist offer
Given a cancellation opens up 1 Deluxe room for Oct 20-22
and "Meera Iyer" is first on the waitlist
When the entry status is changed to OFFERED and the agent calls POST /waitlist/:id/accept
Then a reservation is created for "Meera Iyer" for Deluxe, Oct 20-22
And the waitlist entry status changes to ACCEPTED
Scenario: Waitlist offer expires if not accepted
Given an offer was made to a waitlist entry 24 hours ago
When the offer TTL expires without acceptance
Then the waitlist entry status changes to EXPIRED
And the next guest in the queue can be offered the room
US-003-015: Payment Initiation & Verification (Razorpay)
As a front desk agent or booking engine, I want to collect payment via Razorpay (UPI, credit card, debit card, net banking), So that advance payments or full payments are captured digitally and reconciled automatically.
Priority: P1 | Points: 8 | Sprint: 4 | Status: Built
Implementation Status
- Backend:
PaymentsController--POST /payments/initiate(creates Razorpay order),POST /payments/verify(verifies payment with Razorpay),POST /payments/webhook(handles Razorpay webhook withx-razorpay-signatureverification),POST /payments/refund,GET /payments/:id/status. Payment model supports modes: CASH, CREDIT_CARD, DEBIT_CARD, UPI, NET_BANKING, WALLET, ROOM_CHARGE, CITY_LEDGER, COMPLIMENTARY, ADJUSTMENT.
Acceptance Criteria
Scenario: Collect advance payment via UPI
Given a guest confirms a reservation with totalAmount INR 16,500
When the agent initiates a payment of INR 5,000 (advance) via Razorpay
Then a Razorpay order is created with amount 500000 (paise)
And the guest pays via UPI (Google Pay / PhonePe)
And the payment webhook confirms the payment
And the reservation's paidAmount updates to INR 5,000, balanceDue to INR 11,500
Scenario: Process a payment refund
Given a reservation with INR 5,000 paid is cancelled within free cancellation window
When the agent initiates a refund via POST /payments/refund
Then the refund is processed through Razorpay
And the payment status changes to REFUNDED
And the reservation's paidAmount is adjusted
Scenario: Webhook handles delayed payment notification
Given a payment was initiated but the guest's bank took 30 seconds to process
When the Razorpay webhook fires with payment.captured event
Then the signature is verified against the webhook secret
And the payment record is updated to COMPLETED status
US-003-016: Payment Link Generation & Delivery
As a reservations agent, I want to generate a payment link and send it to the guest via email or WhatsApp, So that the guest can pay in advance without calling the hotel.
Priority: P1 | Points: 5 | Sprint: 6 | Status: Partial
Implementation Status
- Backend: Payment link can be generated via Razorpay API. Notification service exists with WhatsApp webhook controller and email templates.
- Gap: Payment flow is not wired to notification service. No "Send Payment Link" button on reservation detail page. No SMS delivery option.
Acceptance Criteria
Scenario: Send payment link via WhatsApp
Given a reservation for INR 16,500 has zero advance payment
When the agent clicks "Send Payment Link" and selects WhatsApp
Then a Razorpay payment link is generated for INR 16,500
And a WhatsApp message is sent to the guest's phone with the payment link
And the message includes confirmation number and stay details
Scenario: Payment link expires after 72 hours
Given a payment link was sent 73 hours ago and not used
When the guest clicks the expired link
Then a message shows "This payment link has expired. Please contact the hotel."
And the reservation balance remains unchanged
US-003-017: Reservation Modification History
As a hotel manager, I want to view a timeline of all changes made to a reservation, So that I can audit who changed what and when, especially for dispute resolution.
Priority: P1 | Points: 3 | Sprint: 5 | Status: Partial
Implementation Status
- Backend:
ReservationHistorymodel records every modification: action (CREATED, MODIFIED, CANCELLED, CHECKED_IN, CHECKED_OUT, NO_SHOW), changes (JSON with field-level old/new values), performedBy (userId), performedAt (timestamp). Created via@Auditdecorator. - Gap: No dedicated API endpoint to retrieve history (it's included in reservation detail). No UI timeline visualization on dashboard.
Acceptance Criteria
Scenario: View modification history for a reservation
Given reservation GPH20260415001 was created, then dates were extended, then room was upgraded
When the manager views the reservation history
Then 3 history entries are shown in chronological order:
1. CREATED by "reservations@hotel.com" at 2026-03-01 14:30
2. MODIFIED by "frontdesk@hotel.com" at 2026-03-15 10:00 - departureDate changed from Apr 18 to Apr 20
3. MODIFIED by "frontdesk@hotel.com" at 2026-04-01 09:15 - roomTypeId changed from Standard to Deluxe
And each entry shows the user who made the change and the timestamp
US-003-018: Overbooking Control Configuration
As a revenue manager, I want to configure overbooking limits per room type, So that the hotel can maximize occupancy while controlling the risk of walking guests.
Priority: P2 | Points: 5 | Sprint: 8 | Status: Partial
Implementation Status
- Backend:
OverbookingControllerexists in analytics-service. Basic overbooking percentage tracking. - Gap: Not configurable per room type from dashboard. No walk-list management when overbooking triggers. No historical overbooking analysis (how often did overbooking result in walks).
Acceptance Criteria
Scenario: Set overbooking percentage per room type
Given the property has 20 Deluxe rooms
When the revenue manager sets overbooking to 10% for Deluxe
Then the availability engine allows up to 22 bookings (20 + 10%) for Deluxe
And a warning is shown on the dashboard when occupancy exceeds 100%
Scenario: Zero overbooking for premium rooms
Given the property has 5 Presidential Suites
When the revenue manager sets overbooking to 0% for Presidential Suite
Then the system strictly prevents more than 5 bookings for that room type
US-003-019: Cancellation Charge Auto-Calculation
As a reservations agent, I want the system to automatically calculate cancellation charges based on the linked policy, So that charges are consistent and I don't need to manually look up policy rules.
Priority: P2 | Points: 5 | Sprint: 8 | Status: Not Started
Implementation Status
- Backend: Not implemented. Cancellation policies exist with rule definitions, but the cancellation endpoint does not auto-calculate charges based on days-before-arrival logic.
- Frontend: No auto-calculation display during cancellation flow.
Acceptance Criteria
Scenario: Auto-calculate cancellation charge based on policy
Given a reservation with "Flexible" policy (100% first night within 3 days of arrival)
and arrival is 2 days away, first night rate INR 5,500
When the agent initiates cancellation
Then the system auto-calculates: "Cancellation charge: INR 5,500 (100% of first night)"
And the agent can confirm or override the charge with manager approval
Scenario: Free cancellation within policy window
Given a reservation with "Flexible" policy and arrival is 10 days away
When the agent initiates cancellation
Then the system shows: "No cancellation charge applies (cancelled 10 days before arrival)"
US-003-020: Charge Routing Rules
As a hotel accountant, I want to configure routing rules that split charges across multiple folios, So that room charges go to the corporate folio and personal expenses go to the guest folio.
Priority: P2 | Points: 5 | Sprint: 6 | Status: Built
Implementation Status
- Backend:
RoutingRulesControllerexists with configuration for charge routing (room charges, F&B, tax to separate folios).
Acceptance Criteria
Scenario: Route room charges to corporate folio and F&B to guest folio
Given a corporate reservation has two folios: "TechCorp" (company) and "Personal" (guest)
When a routing rule is set: Room + Tax -> TechCorp folio, F&B + Minibar -> Personal folio
Then room charges are auto-posted to the TechCorp folio
And F&B room service charges are auto-posted to the Personal folio
US-003-021: Bulk Group Check-In & Room Assignment
As a front desk supervisor, I want to check in an entire group at once with pre-assigned rooms, So that a 25-person conference group doesn't create a 30-minute check-in queue.
Priority: P2 | Points: 8 | Sprint: 10 | Status: Not Started
Implementation Status
- Backend: Not implemented. Individual check-in exists but no bulk operation.
- Frontend: Not implemented.
Acceptance Criteria
Scenario: Bulk check-in for a group with pre-assigned rooms
Given the "TechCorp Annual Meet" group has 25 reservations, all with rooms assigned
When the front desk supervisor clicks "Group Check-In"
Then all 25 reservations are checked in simultaneously
And key cards for all rooms are queued for encoding
And a summary is shown: 25 checked in, 0 failed
Scenario: Partial bulk check-in with errors
Given 25 reservations in the group, but 2 rooms are out of order
When bulk check-in is attempted
Then 23 are checked in successfully
And 2 are flagged: "Room 305 is OUT_OF_ORDER - reassign room before check-in"
US-003-022: Availability Calendar Visualization
As a revenue manager, I want to view a visual calendar showing daily availability per room type, So that I can quickly spot sold-out dates, low-demand periods, and plan pricing strategies.
Priority: P2 | Points: 5 | Sprint: 8 | Status: Partial
Implementation Status
- Backend:
GET /inventory/:propertyId/:roomTypeId?startDate=&endDate=returns daily inventory breakdown (total, sold, blocked, available). - Gap: No dashboard calendar UI. No color-coded heat map for occupancy levels. No multi-room-type comparison view.
Acceptance Criteria
Scenario: View 30-day availability calendar
Given the property has 3 room types with varying availability
When the revenue manager opens the availability calendar for April 2026
Then a grid shows: rows = room types, columns = dates (1-30)
And each cell displays available room count, color-coded by occupancy:
Green (< 70%), Yellow (70-90%), Red (> 90%), Black (sold out)
Scenario: Identify demand gap for pricing action
Given mid-week dates (Mon-Wed) consistently show green (low occupancy)
When the revenue manager reviews the calendar
Then they can identify the pattern and navigate to rate management
to create a mid-week promotional rate