EP-011: Booking Engine
| Field | Value |
|---|---|
| Epic ID | EP-011 |
| Title | Booking Engine |
| Owner | Product -- Direct Revenue & Guest Experience |
| Status | Partial |
| Last Updated | 2026-03-05 |
| Target Release | R3 (Q2 2026) |
1. Business Objective
Deliver a high-conversion, mobile-first booking engine that enables Indian hotel properties to capture direct reservations, reducing OTA dependency and commission costs (typically 15-25% on MakeMyTrip/Goibibo). The engine must support 14 languages for domestic and Southeast Asian travelers, integrate Razorpay for INR/UPI payments, and embed seamlessly into hotel websites. Target: shift 35%+ of bookings to the direct channel within 12 months of deployment.
2. Audience
| Role | Interaction |
|---|---|
| Guest (end-user) | Searches rooms, compares rates, books, pays, manages reservations |
| Loyalty Member | Views points, redeems rewards, accesses member-only rates |
| Revenue Manager | Monitors direct booking performance, manages promo codes |
| Marketing Manager | Embeds booking engine on hotel website, tracks conversion funnel |
| Property Manager | Configures available inventory, rate plans, restrictions |
| Super Admin | Manages multi-property booking engine instances |
3. Scope
3.1 In Scope
- Room search with availability calendar (date picker, guest count, room count)
- Rate plan display with comparison view (Best Available, Advance Purchase, Non-Refundable, Member Rate)
- Room type gallery with photos, amenities, and floor plan indicators
- Guest details form with Indian identity support (Aadhaar, PAN, passport)
- Payment integration via Razorpay (credit/debit card, UPI, net banking, wallet)
- Booking confirmation page with PDF voucher download
- 14 language translations (en, hi, ta, te, kn, mr, bn, gu, ml, pa, id, ms, th, vi)
- Loyalty dashboard (points balance, transaction history, reward catalog, tier status)
- Manage booking (booking lookup by confirmation number + email/phone, view details, amend dates/room, cancel with policy enforcement)
- Spa/treatment booking with therapist availability and service catalog
- Promo code validation with real-time discount calculation
- Urgency indicators: "Only 3 rooms left", "5 people viewing this room"
- Social proof: "12 bookings today"
- Cookie consent banner with GDPR/IT Act compliance
- Three deployment modes: embeddable widget, iframe, standalone
- Mobile-responsive design (mobile-first approach)
- INR currency formatting with GST breakdown display
3.2 Out of Scope
- Channel manager integration (OTA rate parity -- covered in EP-006)
- Group/MICE booking with RFP workflow (covered in EP-007)
- Travel agent portal / B2B booking (future epic)
- Multi-currency / forex conversion (phase 2)
- Flight + hotel bundled packages
4. Current Implementation Status
| Component | Module / File | Status |
|---|---|---|
| Room search & availability | 03-hmp-booking-engine/src/pages/ | Built |
| Rate plan display + compare | SearchResults component | Built |
| Room gallery & amenities | RoomDetail component | Built |
| Guest details form | GuestDetails component | Built |
| Razorpay payment integration | PaymentPage component | Built |
| Booking confirmation | Confirmation component | Built |
| 14 language i18n | src/locales/ (14 JSON files) | Built |
| Loyalty dashboard | LoyaltyDashboard component | Built |
| Manage booking (lookup) | ManageBooking component | Built |
| Manage booking (amend/cancel) | ManageBooking component | Partial |
| Spa booking | SpaBooking component | Built |
| Promo code validation | PromoCode component | Built |
| Urgency indicators | UrgencyBanner component | Built |
| Cookie consent | CookieConsent component | Partial |
| Widget / iframe / standalone | src/embed/ configuration | Built |
| Mock API layer | src/api/mock/ | Built |
| Live backend integration | src/api/live/ | Not Started |
5. Gap Analysis
| # | Gap | Impact | Effort | Priority |
|---|---|---|---|---|
| 1 | Connected to mock API -- needs live backend integration | Entire booking flow is non-functional in production | Critical | P0 |
| 2 | Razorpay payment flow not tested end-to-end with real transactions | Cannot accept actual payments; money flow unverified | Critical | P0 |
| 3 | Manage booking (amend/cancel) needs reservation service wiring | Guests cannot modify bookings post-confirmation | High | P0 |
| 4 | Loyalty points redemption during booking not connected | Members cannot use points for discounts at checkout | High | P1 |
| 5 | Promo code validation is client-side mock | Any promo code is accepted; no server-side validation | High | P0 |
| 6 | Cookie consent needs GDPR/IT Act compliant implementation | Legal exposure; consent not persisted or auditable | Medium | P1 |
| 7 | No real-time availability sync (mock returns static data) | Overbooking risk once live | Critical | P0 |
| 8 | Urgency indicators use random numbers, not real data | Misleading social proof; potential legal issue | Medium | P1 |
6. User Stories Summary
| ID | Title | Priority | Points | Sprint | Status |
|---|---|---|---|---|---|
| US-011-01 | Room Search & Availability Calendar | P0 | 8 | 1 | Built |
| US-011-02 | Rate Plan Display & Comparison | P0 | 8 | 1 | Built |
| US-011-03 | Guest Details & Identity Capture | P0 | 5 | 1 | Built |
| US-011-04 | Razorpay Payment Integration | P0 | 13 | 2 | Partial |
| US-011-05 | Booking Confirmation & Voucher | P0 | 5 | 2 | Built |
| US-011-06 | Live Backend API Integration | P0 | 21 | 3 | Not Started |
| US-011-07 | 14-Language Internationalization | P1 | 8 | 1 | Built |
| US-011-08 | Loyalty Dashboard in Booking Engine | P1 | 8 | 2 | Built |
| US-011-09 | Points Redemption During Booking | P1 | 8 | 4 | Not Started |
| US-011-10 | Manage Booking (Lookup & View) | P0 | 5 | 2 | Built |
| US-011-11 | Manage Booking (Amend & Cancel) | P0 | 13 | 3 | Partial |
| US-011-12 | Spa & Treatment Booking | P2 | 8 | 3 | Built |
| US-011-13 | Promo Code Server-Side Validation | P0 | 5 | 3 | Not Started |
| US-011-14 | Real-Time Urgency & Social Proof | P1 | 5 | 4 | Not Started |
| US-011-15 | Cookie Consent (GDPR/IT Act) | P1 | 5 | 4 | Partial |
| US-011-16 | Embeddable Widget & Deployment Modes | P1 | 8 | 2 | Built |
7. Dependencies
| Dependency | Epic/Service | Type |
|---|---|---|
| Room availability & inventory | EP-004 / property-service | Hard |
| Rate plans & pricing | EP-006 / rate-service | Hard |
| Reservation creation & management | EP-005 / reservation-service | Hard |
| Guest profile creation | EP-003 / guest-service | Hard |
| Loyalty points & tier data | EP-010 / crm-service | Hard |
| Payment processing | EP-008 / billing-service | Hard |
| Notification (confirmation emails) | EP-014 / notification-service | Hard |
| Razorpay merchant account | Infrastructure / Finance | Soft |
| API Gateway routing | EP-001 / api-gateway | Hard |
8. Acceptance Criteria (Epic-Level)
- A guest can search for rooms, select a rate plan, enter details, pay via Razorpay (UPI/card/net banking), and receive a confirmed booking -- all against the live backend.
- The complete booking flow works in all 14 supported languages with correct currency formatting (INR with lakhs notation).
- A loyalty member can see their points balance and redeem points as a discount during the booking payment step.
- A guest can look up an existing booking by confirmation number + email and amend dates or cancel per the cancellation policy.
- Promo codes are validated server-side against the rate-service, with proper error messages for invalid/expired codes.
- The booking engine renders correctly on mobile (320px width and above) and achieves Lighthouse performance score > 80.
- Urgency indicators reflect real-time data from the property-service (actual remaining inventory, actual concurrent viewers).
- Cookie consent is auditable, persisted per session, and compliant with India IT Act 2000 and GDPR for EU visitors.
9. KPIs
| KPI | Target | Measurement |
|---|---|---|
| Booking conversion rate | > 3.5% | Completed bookings / unique sessions |
| Cart abandonment rate | < 65% | Started checkout / completed checkout |
| Mobile booking share | > 55% | Mobile bookings / total bookings |
| Average booking value (INR) | Track and grow +10% QoQ | Total revenue / booking count |
| Page load time (LCP) | < 2.5 seconds | Lighthouse / RUM metrics |
| Direct channel share | > 35% of total bookings | Booking engine / all channels |
| Language utilization | > 20% non-English bookings | Non-English bookings / total |
| Promo code usage rate | 8-15% of bookings | Promo bookings / total bookings |
10. Detailed User Stories
US-011-01: Room Search & Availability Calendar
As a Guest, I want to search for available rooms by selecting check-in/check-out dates, number of guests, and rooms, So that I can find suitable accommodation for my trip.
Priority: P0 | Points: 8 | Sprint: 1 | Status: Built
Implementation Status
Room search is fully built with a date picker (blocked past dates, max 30-night stays), adult/child selectors, and room count selector. The search results page displays available room types with photos, amenities, and starting price. Currently returns mock data; needs live backend wiring (see US-011-06).
Acceptance Criteria
Scenario: Search for rooms with valid dates
Given I am on the booking engine home page for "Hotel Taj Residency"
When I select check-in "2026-04-10", check-out "2026-04-13", 2 adults, 1 child, 1 room
Then the search results page displays available room types for those dates
And each room type shows name, photo, amenity icons, and starting price in INR (e.g., "4,500/night + taxes")
And the total stay duration "3 Nights" is displayed
Scenario: No availability for selected dates
Given the hotel is fully booked for 2026-12-31 (New Year's Eve)
When I search for check-in 2026-12-31, check-out 2027-01-01
Then the results page shows "No rooms available for selected dates"
And suggests alternative dates with availability (nearest available dates)
Scenario: Restrict invalid date selections
Given today is 2026-03-05
When I attempt to select check-in date 2026-03-01 (past date)
Then the date is disabled and not selectable
And check-out date must be at least 1 day after check-in
US-011-02: Rate Plan Display & Comparison
As a Guest, I want to compare different rate plans for a room type, So that I can choose the best value option for my stay.
Priority: P0 | Points: 8 | Sprint: 1 | Status: Built
Implementation Status
Rate plan comparison view is built. Displays up to 4 rate plans per room type: Best Available Rate (BAR), Advance Purchase (pay now, save 15%), Non-Refundable (save 20%), and Member Rate (loyalty members only). Each plan shows base rate, tax breakdown (GST at 12% for rooms 1000-7499 INR, 18% for 7500+ INR), cancellation policy summary, and inclusions. Currently using mock rate data.
Acceptance Criteria
Scenario: Compare rate plans for a Deluxe Room
Given I search for a Deluxe Room for 2 nights
When the results load
Then I see rate plans displayed as cards:
| Plan | Rate/Night | GST (18%) | Total (2N) | Cancellation |
| Best Available | 8,000 INR | 1,440 INR | 18,880 INR | Free until 24h before |
| Advance Purchase | 6,800 INR | 1,224 INR | 16,048 INR | Non-refundable |
| Member Rate | 7,200 INR | 1,296 INR | 16,992 INR | Free until 48h before |
And the Member Rate shows a lock icon with "Login to access" for non-members
Scenario: GST rate selection based on room tariff
Given a Standard Room has a tariff of 5,000 INR per night (below 7,500 INR threshold)
When the rate plan is displayed
Then GST is calculated at 12% (600 INR per night)
And the tax line shows "GST @12%: 600 INR"
Scenario: Highlight best value plan
Given multiple rate plans are displayed
When the Advance Purchase rate offers the lowest total
Then it is highlighted with a "Best Value" badge
And the savings compared to BAR are shown (e.g., "Save 2,832 INR")
US-011-03: Guest Details & Identity Capture
As a Guest, I want to enter my personal details and identity information during booking, So that the hotel can prepare for my arrival and comply with Indian regulations.
Priority: P0 | Points: 5 | Sprint: 1 | Status: Built
Implementation Status
Guest details form captures: full name, email, phone (+91 validation), address, identity document type (Aadhaar, PAN, Passport, Driving License), document number, special requests, and estimated arrival time. Form validation is implemented client-side. GST details (GSTIN, company name, company address) are optional for business travelers claiming input tax credit.
Acceptance Criteria
Scenario: Complete guest details for domestic traveler
Given I have selected a room and rate plan
When I fill in: Name "Arjun Reddy", Email "arjun@email.com", Phone "+91-9876543210", ID Type "Aadhaar", ID Number "1234-5678-9012"
Then all fields pass validation
And the Aadhaar number is formatted as "XXXX-XXXX-9012" (masked for display)
And I can proceed to the payment step
Scenario: Capture GST details for business booking
Given a guest selects "Business Travel" purpose
When they enter GSTIN "29ABCDE1234F1Z5" and company name "TechCorp India Pvt Ltd"
Then the GSTIN is validated against the standard format (15 characters, state code prefix)
And the invoice will be generated with GST input credit details
And the company address auto-populates from GSTIN lookup if available
Scenario: Validate Indian phone number
Given the booking engine is configured for an Indian property
When a guest enters phone number "9876543210" (without country code)
Then the system auto-prepends "+91" and validates the 10-digit format
And rejects numbers not starting with 6, 7, 8, or 9
US-011-04: Razorpay Payment Integration
As a Guest, I want to pay for my booking using UPI, credit/debit card, or net banking via Razorpay, So that I can complete my reservation using my preferred Indian payment method.
Priority: P0 | Points: 13 | Sprint: 2 | Status: Partial
Implementation Status
Razorpay checkout is integrated using Razorpay.js SDK. The payment modal renders with booking amount, and the Razorpay order ID is generated on the client side. However, the server-side order creation (via billing-service -> Razorpay Orders API) is using mock responses. Payment verification (signature validation) is not tested against Razorpay's live/test environment. Webhook handler for payment status updates is scaffolded but untested.
Acceptance Criteria
Scenario: Pay via UPI
Given I am on the payment page with booking total 18,880 INR
When I select "UPI" as payment method and enter UPI ID "arjun@okicici"
Then a Razorpay order is created via the billing-service (POST /api/payments/create-order)
And the Razorpay payment modal opens with amount "18,880.00"
And upon successful payment, the server verifies the Razorpay signature
And the booking status changes to "Confirmed" and confirmation page loads
Scenario: Handle payment failure
Given I attempt to pay 18,880 INR via credit card
When the card is declined by the issuing bank
Then the Razorpay modal shows the bank's decline reason
And the booking remains in "Pending Payment" status for 15 minutes
And I can retry with a different payment method without re-entering guest details
Scenario: Razorpay webhook reconciliation
Given a payment was initiated but the browser closed before confirmation
When Razorpay sends a "payment.captured" webhook to the billing-service
Then the payment is reconciled with the pending booking
And the booking status is updated to "Confirmed"
And a confirmation email is sent to the guest
US-011-05: Booking Confirmation & Voucher
As a Guest, I want to receive a booking confirmation with all details and a downloadable voucher, So that I have a record of my reservation.
Priority: P0 | Points: 5 | Sprint: 2 | Status: Built
Implementation Status
Confirmation page is fully built. Displays booking ID, hotel name, room type, check-in/check-out dates, guest name, total amount with GST breakdown, and payment reference. A "Download Voucher" button generates a PDF with hotel branding. The confirmation email is triggered (via mock notification service). QR code for mobile check-in is generated on the voucher.
Acceptance Criteria
Scenario: Display booking confirmation
Given I completed payment for a booking
When the confirmation page loads
Then I see:
| Field | Value |
| Booking ID | BK-20260410-0042 |
| Hotel | Hotel Taj Residency, Mumbai |
| Room Type | Deluxe King |
| Check-in | 10 Apr 2026, 14:00 |
| Check-out | 13 Apr 2026, 11:00 |
| Total Amount | 18,880 INR (incl. GST) |
| Payment Status | Paid via UPI |
And a QR code is displayed for mobile check-in
Scenario: Download PDF voucher
Given I am on the confirmation page
When I click "Download Voucher"
Then a PDF file "HotelTajResidency-BK-20260410-0042.pdf" downloads
And the PDF includes hotel logo, booking details, GST breakdown, cancellation policy, and QR code
And the GST breakdown shows CGST and SGST (or IGST for inter-state) separately
Scenario: Confirmation email sent
Given the booking is confirmed
When the "booking.confirmed" Kafka event fires
Then the notification-service sends a confirmation email to the guest
And the email contains the same details as the confirmation page
And the PDF voucher is attached to the email
US-011-06: Live Backend API Integration
As a Development Team, I want to replace all mock API calls with live backend service integration, So that the booking engine operates against real hotel inventory, rates, and reservations.
Priority: P0 | Points: 21 | Sprint: 3 | Status: Not Started
Implementation Status
Not started. The booking engine currently uses a mock API layer (src/api/mock/) that returns hardcoded responses for all endpoints. The live API client (src/api/live/) needs to be implemented to call the API Gateway, which proxies to property-service, rate-service, reservation-service, billing-service, guest-service, and crm-service.
Acceptance Criteria
Scenario: Room search calls property-service via API Gateway
Given the booking engine is configured with API Gateway URL "https://api.hotel.com"
And the tenant ID is set in the booking engine configuration
When a guest searches for rooms for 2026-04-10 to 2026-04-13
Then the engine calls GET /api/properties/{propertyId}/availability?checkIn=2026-04-10&checkOut=2026-04-13&adults=2&children=1
And the response contains real room availability from the property-service
And the UI renders actual available room types with live pricing
Scenario: Booking creation calls reservation-service
Given the guest has filled details and completed payment
When the "Confirm Booking" action fires
Then the engine calls POST /api/reservations with guest details, room type, dates, and payment reference
And the reservation-service creates the reservation and returns a confirmation number
And inventory is decremented in real-time
Scenario: Graceful degradation on API failure
Given the API Gateway returns HTTP 503 (service unavailable)
When the guest is on the search results page
Then a user-friendly error message is shown: "We're experiencing technical difficulties. Please try again shortly."
And the booking engine does not display stale mock data
And the error is logged with correlation ID for debugging
US-011-07: 14-Language Internationalization
As a Guest who speaks a regional Indian or Southeast Asian language, I want to use the booking engine in my preferred language, So that I can understand all information and complete my booking confidently.
Priority: P1 | Points: 8 | Sprint: 1 | Status: Built
Implementation Status
Full i18n implementation using react-i18next. All 14 language JSON files are maintained in src/locales/. Language switcher component in the header. Language preference is persisted in localStorage and sent as Accept-Language header to the API. RTL support is not needed for supported languages. Date and number formatting respects locale (e.g., Hindi uses Devanagari numerals optionally).
Acceptance Criteria
Scenario: Switch language to Hindi
Given I am on the booking engine in English
When I click the language selector and choose "Hindi"
Then all UI labels, button texts, and static content render in Hindi (Devanagari script)
And the URL updates to include locale parameter "?lang=hi"
And currency remains "INR" with amount in standard numerals
Scenario: Tamil booking flow end-to-end
Given I set the language to Tamil ("ta")
When I complete the entire booking flow from search to confirmation
Then all pages render in Tamil including form labels, error messages, and confirmation text
And the PDF voucher generates with Tamil text for guest-facing fields
And the confirmation email is sent in Tamil
Scenario: Fallback for missing translations
Given a new feature was added with English strings but Telugu translations are pending
When a Telugu-speaking user encounters the untranslated string
Then the English fallback is displayed for that specific string
And all other Telugu translations continue to display correctly
US-011-08: Loyalty Dashboard in Booking Engine
As a Loyalty Member, I want to view my loyalty status, points balance, and transaction history within the booking engine, So that I can track my rewards without calling the hotel.
Priority: P1 | Points: 8 | Sprint: 2 | Status: Built
Implementation Status
Loyalty dashboard is fully built with: tier badge and progress bar (e.g., "Gold -- 2,400 points to Platinum"), points balance, transaction history (earned, redeemed, expired), reward catalog browser, and membership QR code. Authentication is via JWT token from the auth-service. Currently displays mock loyalty data.
Acceptance Criteria
Scenario: View loyalty dashboard
Given I am logged in as loyalty member "HMP-LY-00042" (Gold tier, 12,500 points)
When I navigate to the loyalty dashboard
Then I see:
| Element | Value |
| Tier Badge | Gold (with gold-colored icon) |
| Points Balance | 12,500 points |
| Tier Progress | "2,500 points to Platinum" with bar at 83% |
| Next Expiry | "1,200 points expire on 2026-06-15" |
And the transaction history shows last 20 transactions with date, type, points, and description
Scenario: Browse reward catalog
Given I am on the loyalty dashboard
When I click "Rewards Catalog"
Then I see available rewards grouped by category (Room, F&B, Spa, Experiences)
And each reward shows name, points cost, description, and "Redeem" button
And rewards I cannot afford (insufficient points) show points needed with dimmed "Redeem" button
Scenario: Unauthenticated access
Given I am not logged in
When I navigate to the loyalty dashboard URL
Then I am redirected to the login page
And after login, I am returned to the loyalty dashboard
US-011-09: Points Redemption During Booking
As a Loyalty Member, I want to apply my loyalty points as a discount during the booking payment step, So that I receive immediate value from my accumulated points.
Priority: P1 | Points: 8 | Sprint: 4 | Status: Not Started
Implementation Status
Not implemented. The payment page has a placeholder "Apply Points" section in the UI, but it is not connected to the crm-service loyalty API. Points balance retrieval, redemption rate calculation, and points deduction on booking confirmation are all pending.
Acceptance Criteria
Scenario: Apply points as discount during checkout
Given I am a Gold member with 10,000 points and the redemption rate is 500 points = 1,000 INR
And my booking total is 18,880 INR
When I click "Apply Points" and choose to redeem 5,000 points (= 10,000 INR discount)
Then the payment summary updates:
| Line Item | Amount |
| Room Charges | 16,000 INR |
| GST @18% | 2,880 INR |
| Loyalty Redemption | -10,000 INR |
| Amount to Pay | 8,880 INR |
And the Razorpay payment modal opens for 8,880 INR
Scenario: Partial points redemption
Given I have 3,000 points and maximum redemption is 50% of booking value
And booking total is 18,880 INR (50% = 9,440 INR)
When I move the points slider to maximum
Then the slider caps at 3,000 points (= 6,000 INR, which is under the 50% cap)
And remaining balance of 12,880 INR must be paid via Razorpay
Scenario: Points deducted only on confirmed payment
Given I applied 5,000 points for a 10,000 INR discount
When the Razorpay payment for the remaining amount fails
Then points are NOT deducted from my balance
And I can retry payment or remove the points redemption
US-011-10: Manage Booking (Lookup & View)
As a Guest, I want to look up my existing booking using confirmation number and email, So that I can review my reservation details.
Priority: P0 | Points: 5 | Sprint: 2 | Status: Built
Implementation Status
Booking lookup is fully built. Guest enters confirmation number (e.g., "BK-20260410-0042") and registered email. The system retrieves and displays full booking details: dates, room type, guest name, amount paid, payment method, booking status, cancellation policy, and hotel contact information. Currently using mock API.
Acceptance Criteria
Scenario: Look up a confirmed booking
Given I have booking "BK-20260410-0042" with email "arjun@email.com"
When I enter these on the Manage Booking page and click "Find Booking"
Then the booking details page loads showing all reservation information
And I see action buttons: "Modify Booking", "Cancel Booking", "Download Voucher"
Scenario: Booking not found
Given I enter confirmation number "BK-INVALID-001" with email "wrong@email.com"
When I click "Find Booking"
Then the system displays "No booking found. Please check your confirmation number and email address."
And after 3 failed attempts, a CAPTCHA is presented to prevent brute-force lookup
Scenario: View cancelled booking
Given booking "BK-20260410-0042" was previously cancelled
When I look it up
Then the booking details show status "Cancelled" with cancellation date
And refund details are displayed (amount, refund reference, expected settlement date)
And "Modify Booking" and "Cancel Booking" buttons are disabled
US-011-11: Manage Booking (Amend & Cancel)
As a Guest, I want to modify my booking dates/room type or cancel my booking per the hotel's policy, So that I have flexibility to change my travel plans.
Priority: P0 | Points: 13 | Sprint: 3 | Status: Partial
Implementation Status
The UI for amend and cancel flows is partially built. The cancel button triggers a confirmation modal showing the cancellation policy and refund amount. The amend flow allows date changes and displays rate differences. However, neither flow is connected to the reservation-service backend. Cancel does not trigger Razorpay refund. Amend does not check live availability or process differential payment.
Acceptance Criteria
Scenario: Cancel a booking within free cancellation window
Given booking "BK-20260410-0042" has policy "Free cancellation until 24 hours before check-in"
And check-in is 2026-04-10 14:00 IST and current time is 2026-04-08 10:00 IST
When I click "Cancel Booking" and confirm
Then the reservation-service updates the booking status to "Cancelled"
And a full refund of 18,880 INR is initiated via Razorpay Refunds API
And I receive a cancellation confirmation email with refund reference number
And the room inventory is released back to available pool
Scenario: Cancel after free cancellation window
Given the same booking but current time is 2026-04-09 16:00 IST (within 24 hours of check-in)
When I click "Cancel Booking"
Then the modal shows: "Cancellation charge: 1 night (9,440 INR). Refund amount: 9,440 INR"
And I must explicitly acknowledge the charge before confirming
And upon confirmation, partial refund is processed for 9,440 INR
Scenario: Amend booking dates with rate difference
Given booking is for 2026-04-10 to 2026-04-13 (3 nights, 18,880 INR)
When I change check-out to 2026-04-15 (5 nights) and the rate is unchanged at 8,000/night + GST
Then the system shows: "Additional amount due: 18,880 INR for 2 extra nights"
And I am redirected to Razorpay to pay the difference
And after payment, the reservation is updated with new dates
US-011-12: Spa & Treatment Booking
As a Guest, I want to book spa treatments and wellness services during the booking flow or from the booking engine, So that I can plan my wellness experience in advance.
Priority: P2 | Points: 8 | Sprint: 3 | Status: Built
Implementation Status
Spa booking module is fully built. Displays treatment catalog with categories (Ayurvedic, Western, Beauty, Fitness), therapist availability calendar, duration, pricing in INR, and description. Guest can select date, time slot, and preferred therapist gender. Currently using mock spa service data.
Acceptance Criteria
Scenario: Book an Ayurvedic massage
Given I am booking a stay at a resort with a spa
When I navigate to "Spa & Wellness" and select "Abhyanga Massage - 60 min" at 3,500 INR
And I choose date 2026-04-11 at 10:00 AM with preference "Female therapist"
Then the time slot availability is checked against the spa schedule
And the spa booking is added to my reservation with total updated
And the confirmation shows spa appointment details alongside room booking
Scenario: Spa time slot unavailable
Given the 10:00 AM slot on 2026-04-11 is fully booked
When I select this time slot
Then the system shows "This time slot is unavailable" and suggests nearby alternatives: 11:00 AM, 2:00 PM, 3:00 PM
And I can select an alternative slot
Scenario: Cancel spa booking independently
Given I have a room booking with an attached spa appointment
When I cancel only the spa appointment (not the room)
Then the spa booking is cancelled with full refund (if > 4 hours before appointment)
And the room booking remains unchanged
And the spa time slot is released for other guests
US-011-13: Promo Code Server-Side Validation
As a Guest, I want to apply a promo code and see the validated discount, So that I can trust the discount is legitimate and will be honored.
Priority: P0 | Points: 5 | Sprint: 3 | Status: Not Started
Implementation Status
Not started. The current promo code field accepts any input and applies a hardcoded 10% discount on the client side. Server-side validation against the rate-service (which stores promo code definitions with validity dates, usage limits, minimum booking value, applicable room types, and discount type/amount) is not implemented.
Acceptance Criteria
Scenario: Apply a valid promo code
Given promo code "MONSOON25" offers 25% off on Deluxe rooms, valid until 2026-09-30, minimum booking 10,000 INR
And my Deluxe Room booking total is 18,880 INR
When I enter "MONSOON25" and click "Apply"
Then the system calls POST /api/rates/promo/validate with code, booking details, and tenant ID
And the discount of 4,000 INR (25% of 16,000 INR room charge, pre-GST) is applied
And the updated total shows 14,880 INR (including recalculated GST)
Scenario: Apply an expired promo code
Given promo code "DIWALI25" expired on 2025-11-15
When I enter "DIWALI25" and click "Apply"
Then the server returns "Promo code has expired"
And no discount is applied
And the input field shows a red error message
Scenario: Promo code usage limit exceeded
Given promo code "FLASH50" has a limit of 100 uses and 100 bookings have already used it
When I enter "FLASH50"
Then the server returns "This promo code has reached its maximum usage limit"
And no discount is applied
US-011-14: Real-Time Urgency & Social Proof
As a Guest, I want to see real-time indicators about room scarcity and booking activity, So that I can make timely booking decisions.
Priority: P1 | Points: 5 | Sprint: 4 | Status: Not Started
Implementation Status
Not started on the data side. UI components exist for urgency banners ("Only 3 rooms left!") and social proof counters ("5 people viewing this room"), but they currently display random numbers generated client-side. Real data requires WebSocket or polling integration with property-service for inventory counts and a session tracking mechanism for concurrent viewers.
Acceptance Criteria
Scenario: Display real room scarcity
Given the property-service reports 2 Deluxe Rooms remaining for 2026-04-10
When the search results load for that date
Then the Deluxe Room card shows a red banner: "Only 2 rooms left!"
And the banner only appears when remaining inventory is <= 5
Scenario: Show concurrent viewers
Given 8 unique sessions are currently viewing the Suite room type for 2026-04-10
When I view the Suite room listing
Then I see "8 people are viewing this room" with a pulsing indicator
And the count updates every 30 seconds via WebSocket
Scenario: Do not show misleading indicators
Given the property has 50 Standard Rooms and 45 are available
When I view the Standard Room listing
Then no scarcity banner is shown (threshold not met)
And no fabricated urgency is displayed
US-011-15: Cookie Consent (GDPR/IT Act)
As a Guest visiting from any jurisdiction, I want to control my cookie preferences, So that my privacy is respected in compliance with GDPR and India's IT Act 2000.
Priority: P1 | Points: 5 | Sprint: 4 | Status: Partial
Implementation Status
A basic cookie consent banner is built that shows on first visit with "Accept All" and "Reject All" buttons. However, granular consent categories (Essential, Analytics, Marketing) are not implemented. Consent is stored in localStorage but not persisted server-side for audit. Third-party scripts (Razorpay, analytics) load regardless of consent choice.
Acceptance Criteria
Scenario: Granular cookie consent
Given a first-time visitor lands on the booking engine
When the cookie consent banner appears
Then I see categories: Essential (always on, greyed out), Analytics (toggle), Marketing (toggle)
And I can selectively enable/disable Analytics and Marketing cookies
And clicking "Save Preferences" persists my choices and dismisses the banner
Scenario: Consent controls third-party scripts
Given I rejected "Analytics" cookies
When the page loads
Then Google Analytics / tracking scripts are NOT loaded
And only essential cookies (session, language preference, CSRF) are set
And Razorpay scripts load only when I reach the payment step (essential for transaction)
Scenario: Consent is auditable
Given I accepted "Analytics" but rejected "Marketing" cookies on 2026-03-05
When the consent record is stored
Then the server receives: { guestSessionId, consentDate, essential: true, analytics: true, marketing: false, ipCountry: "IN" }
And this record is retained for 3 years per GDPR requirements
US-011-16: Embeddable Widget & Deployment Modes
As a Hotel Marketing Manager, I want to embed the booking engine on my hotel's website as a widget, iframe, or standalone page, So that guests can book directly without leaving our website.
Priority: P1 | Points: 8 | Sprint: 2 | Status: Built
Implementation Status
Three deployment modes are fully built. Widget mode provides a floating "Book Now" button that expands into a compact booking form. Iframe mode generates an embeddable <iframe> tag with configurable dimensions and property ID. Standalone mode runs as a full-page application at a dedicated URL. Configuration is managed via src/embed/config.ts with property-specific theming (colors, logo, fonts).
Acceptance Criteria
Scenario: Embed as widget on hotel website
Given the hotel website includes the widget script: <script src="https://book.hmphotel.com/widget.js" data-property="prop-001" data-theme="dark"></script>
When the hotel homepage loads
Then a floating "Book Now" button appears in the bottom-right corner
And clicking it opens a compact booking form overlay with the hotel's theme colors
And the form submits to the booking engine without navigating away from the hotel site
Scenario: Iframe embedding with custom dimensions
Given the hotel marketing page includes <iframe src="https://book.hmphotel.com/embed?property=prop-001&lang=hi" width="100%" height="700"></iframe>
When the page loads
Then the booking engine renders within the iframe in Hindi
And the iframe communicates booking completion to the parent page via postMessage
And cross-origin policies are respected with proper CSP headers
Scenario: Standalone mode with custom domain
Given the booking engine is deployed at "https://book.tajresidency.com"
When a guest navigates to this URL
Then the full booking engine loads with Hotel Taj Residency branding
And all pages (search, results, details, payment, confirmation) are accessible
And the URL structure supports deep linking (e.g., /search?checkIn=2026-04-10)