Core Entities
Hotel: hotel_id, name, address, star_rating, amenities (JSON array), check_in_time, check_out_time. RoomType: type_id, hotel_id, name (STANDARD, DELUXE, SUITE, PENTHOUSE), capacity (max guests), base_price, amenities. Room: room_id, hotel_id, type_id, number, floor, status (AVAILABLE, OCCUPIED, MAINTENANCE, HOUSEKEEPING), is_active. Booking: booking_id, hotel_id, guest_id, room_id (nullable until check-in), type_id, check_in_date, check_out_date, status (CONFIRMED, CHECKED_IN, CHECKED_OUT, CANCELLED, NO_SHOW), adults, children, total_amount, paid_amount, booking_source (DIRECT, OTA, WALK_IN), created_at. Guest: guest_id, first_name, last_name, email, phone, id_type, id_number, nationality, loyalty_tier (NONE, SILVER, GOLD, PLATINUM). Invoice: invoice_id, booking_id, line_items (JSON: [{desc, qty, rate, amount}]), subtotal, tax, total, issued_at.
Room Availability and Booking
class BookingService:
def get_available_rooms(self, hotel_id: int, check_in: date,
check_out: date, type_id: int,
adults: int) -> list[Room]:
# Find rooms of requested type not booked in the date range
booked_room_ids = self.db.query("""
SELECT DISTINCT room_id FROM bookings
WHERE hotel_id = :h AND room_id IS NOT NULL
AND status IN ('CONFIRMED', 'CHECKED_IN')
AND check_in_date :in
""", h=hotel_id, out=check_out, in=check_in)
return self.db.query("""
SELECT r.* FROM rooms r
JOIN room_types rt ON r.type_id = rt.type_id
WHERE r.hotel_id = :h AND r.type_id = :t
AND r.status = 'AVAILABLE' AND r.is_active = TRUE
AND r.room_id NOT IN :booked
AND rt.capacity >= :adults
""", h=hotel_id, t=type_id, booked=booked_room_ids, adults=adults)
def create_booking(self, request: BookingRequest) -> Booking:
with self.db.transaction():
available = self.get_available_rooms(
request.hotel_id, request.check_in,
request.check_out, request.type_id, request.adults
)
if not available:
raise NoRoomsAvailableError()
booking = Booking(
hotel_id=request.hotel_id,
guest_id=request.guest_id,
type_id=request.type_id,
check_in_date=request.check_in,
check_out_date=request.check_out,
status=BookingStatus.CONFIRMED,
total_amount=self._calculate_total(request)
)
self.repo.save(booking)
return booking
Dynamic Pricing (Revenue Management)
Hotel room prices are not static — they vary by occupancy, season, day of week, and booking lead time. Pricing factors: base_price (from RoomType), occupancy multiplier: if >80% of rooms are booked for a night: apply a 1.2x multiplier. If <30%: apply a 0.9x discount. Day-of-week: weekends are 1.15x on leisure hotels, weekdays 1.15x on business hotels. Lead time: booking 90+ days in advance: 0.9x. Booking within 3 days: 1.3x (last-minute premium). Events: if a major conference is in the city on those dates: 1.5x. Pricing tiers are stored in a PricingRule table and evaluated at booking time. The calculated price is locked in at booking time and stored on the Booking — future pricing changes don't affect confirmed bookings.
Check-In, Housekeeping, and Billing
Check-in flow: (1) Guest arrives, receptionist looks up the booking by booking_id or guest name. (2) Verify guest ID (id_type, id_number). (3) Assign a specific room: pick from available AVAILABLE rooms of the booked type (prefer floors the guest has stayed on before, prefer non-adjacent to noisy rooms if available). (4) Update: booking.room_id = assigned_room, booking.status = CHECKED_IN, room.status = OCCUPIED. Housekeeping state machine: OCCUPIED → HOUSEKEEPING (after check-out or daily service request) → AVAILABLE (after housekeeping complete). The housekeeping app allows staff to mark rooms as cleaned. Room is not reassignable until status = AVAILABLE. Check-out and billing: (1) Retrieve all charges: base room rate (nightly * nights_stayed), additional charges (minibar, room service, spa — added via the folio system during stay). (2) Apply loyalty discounts (GOLD: 5% off, PLATINUM: 10% off). (3) Generate invoice. (4) Process payment (charge to card on file). (5) Update room status to HOUSEKEEPING. Email invoice to guest. Folio charges: during the stay, any service charge (restaurant, spa) is added to the booking’s folio (PostCharge: charge_id, booking_id, description, amount, posted_at, posted_by).
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How do you prevent double-booking in a hotel system when multiple agents book the same room simultaneously?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Two travel agents simultaneously book the last available Deluxe room for the same dates. Without protection: both bookings succeed, the same physical room is double-booked. Solutions: (1) Database-level row locking: at booking time, SELECT room_id FROM rooms WHERE … FOR UPDATE (lock the available room rows). The second transaction blocks until the first commits. After the first transaction commits (assigning room_id to a booking), the second transaction no longer sees that room as available. (2) Pessimistic locking at the room type level: instead of locking individual rooms, lock all rooms of the requested type for the date range. Less granular but simpler. (3) Optimistic locking: add a version column to the Room entity. Include WHERE room_id=:id AND version=:v in the update. If rows_affected=0: another booking claimed the room — retry. (4) Unique constraint: add a unique index on (room_id, check_in_date) — enforced by the database. Note: this is for specific room assignment; before room assignment (booking by type only), use availability checking with transactions. Best practice: separate the booking confirmation (which type, which dates — no specific room) from room assignment (done at check-in). This reduces the critical section to just the check-in moment.”
}
},
{
“@type”: “Question”,
“name”: “How does dynamic pricing work in hotel revenue management?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Revenue management is the practice of adjusting prices to maximize revenue given fluctuating demand. Key signals and their effects on price: (1) Occupancy rate: if 85%+ of rooms are booked for a date: increase price by 20-30% (supply scarcity signal). If <40% occupied: decrease by 10-20% to stimulate bookings. (2) Lead time: customers booking 90+ days in advance get early-bird discounts (hotel prefers revenue certainty). Last-minute bookings (< 3 days) pay a premium (high urgency, less price sensitivity). (3) Day of week: business hotels charge more Mon-Thu; leisure hotels charge more Fri-Sat. (4) Events and seasonality: concerts, conferences, holidays create demand spikes. Pre-load event calendar; apply multipliers for high-demand dates. (5) Competitor pricing: scrape competitor hotel rates and adjust within a competitive band. Implementation: a pricing engine recomputes rates every 5-15 minutes for the next 365 days. Rates are cached in Redis. At booking time: fetch the rate for the check-in date from Redis. The rate is immutable once a booking is confirmed (price lock guarantee). Floor price: no room ever goes below a minimum price (covers cost + margin floor)."
}
},
{
"@type": "Question",
"name": "How do you handle the check-in process for a guest who arrives before their room is ready?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Standard hotel check-in time is 3 PM. If a guest arrives at 10 AM, their room may not be cleaned and available yet. Guest experience options: (1) Early check-in (if a room is ready): assign the room immediately, charge an early check-in fee if the hotel's policy requires it. No fee for loyalty members at GOLD+ tier. (2) Baggage hold: check in the guest administratively (create an early check-in record), hold their luggage at the front desk, allow access to hotel amenities (pool, restaurant). Assign a room as soon as one is ready. Push notification to the guest's phone: "Your room 412 is ready — enjoy your stay." (3) Upgrade to available room: if the guest's booked room type has no available rooms but a higher tier is ready: offer a complimentary upgrade. Implementation: a room-ready queue (priority queue ordered by early arrival time). When housekeeping marks a room as AVAILABLE, the queue assigns it to the longest-waiting early-arrived guest first. Room assignment state: PENDING_ASSIGNMENT (checked in but no room assigned), ROOM_ASSIGNED, CHECKED_IN (full check-in with room key issued)."
}
},
{
"@type": "Question",
"name": "How do you calculate the invoice for a hotel stay with multiple room charges?",
"acceptedAnswer": {
"@type": "Answer",
"text": "An invoice aggregates the base room charge and all incidental charges posted during the stay. Calculation: (1) Room rate per night: fetch the rate for each night (check_in_date to check_out_date – 1 day). For a 3-night stay with different rates: SUM(rate_night_1, rate_night_2, rate_night_3). Dynamic rates mean each night may have a different price. (2) Folio charges: all posted charges during the stay (room service, minibar, spa, parking). Grouped by category on the invoice. (3) Discounts: loyalty tier discount applied as a percentage of the room subtotal. Promotional codes. Corporate rate agreements. (4) Taxes: occupancy tax (varies by city/state, typically 5-15%), VAT (EU), city tax (flat per night per room in many European cities). Tax calculation is jurisdiction-dependent — store tax rates per jurisdiction in a TaxRate table. (5) Payment: if a deposit was paid at booking: credit against the total. Final charge = total – deposit. Invoice format: each line item with description, quantity, unit rate, and amount. Subtotal, taxes itemized separately, total due. Required for business reimbursement and VAT reclaim."
}
},
{
"@type": "Question",
"name": "How do you integrate with OTAs (Booking.com, Expedia) for inventory distribution?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Online Travel Agencies aggregate hotel inventory and sell rooms. Integration requires: (1) Channel manager: a middleware system that syncs the hotel's rate and availability (RA) across all OTA channels simultaneously. When a room is booked directly on the hotel's website, the channel manager decrements availability on all OTAs within seconds to prevent double-booking. (2) OTA connection protocols: most OTAs use XML-based protocols (OTA Alliance standards: OTA_HotelAvailRQ/RS, OTA_HotelResRQ). Newer integrations use REST APIs. (3) Rate parity: OTAs typically require that the hotel's direct price is not lower than the OTA price (rate parity clause). The channel manager enforces this — pushing the same rates to all channels. (4) Booking notification: when a guest books on Booking.com, Booking.com sends a reservation to the channel manager (HTTP push or pull). Channel manager creates a booking in the PMS (Property Management System) with source=OTA and marks the room as unavailable. (5) Reconciliation: daily reconciliation compares the PMS booking list with each OTA's booking report to detect discrepancies (missed notifications, network failures). Automated matching by confirmation number."
}
}
]
}
Asked at: Airbnb Interview Guide
Asked at: Stripe Interview Guide
Asked at: Shopify Interview Guide
Asked at: Uber Interview Guide