0) Problem Restatement
Design a hotel booking platform like MakeMyTrip where users can search for hotels, view availability, book rooms, and make payments.
1) Requirements
1.1 Functional
- Search hotels by location, dates, and filters (price, rating, amenities).
- View hotel details, photos, reviews, and room availability.
- Book rooms with real-time availability checks.
- Payment processing and confirmation.
- Cancellation and refund handling.
- Hotel partner dashboard (manage inventory, pricing, bookings).
- User reviews and ratings.
1.2 Non-Functional
- High Availability: 99.9% uptime for search and booking.
- Low Latency: Search results < 500ms, booking confirmation < 2s.
- Consistency: No double-booking of rooms.
- Scalability: Handle millions of searches/day, peak traffic during holidays.
- Reliability: Accurate inventory sync across channels.
- Data Integrity: Secure payment and booking records.
1.3 Scale Estimates
- Hotels: 1 million hotels, avg 50 rooms/hotel = 50M rooms.
- Daily searches: 100M searches/day (~1200 searches/sec avg, 5000/sec peak).
- Daily bookings: 1M bookings/day (~12 bookings/sec avg, 50/sec peak).
- Users: 100M registered users.
- Data: Hotel metadata ~100 GB, booking records ~10 TB/year.
1.4) API Specifications
User-Facing APIs
- GET /api/hotels/search - Search hotels by location, dates, and filters
- GET /api/hotels/{hotel_id} - Get detailed hotel information including room types and amenities
- POST /api/hotels/availability - Check real-time room availability for specific dates
- POST /api/bookings - Create a new booking with room hold (returns booking_id and payment_url)
- GET /api/bookings/{booking_id} - Get booking details and status
- POST /api/bookings/{booking_id}/cancel - Cancel booking and initiate refund
Hotel Partner APIs
- PUT /api/partner/inventory - Update room inventory, pricing, and availability
- GET /api/partner/bookings - View bookings for partner's hotels
2) High-Level Architecture
2.1 Overview
- Client → API Gateway → Search Service → Inventory Service → Booking Service → Payment Service → Notification Service.
- Key components: Search with caching, inventory management with locking, async payment processing, and real-time availability updates.
2.2 Flow Diagram
Architecture Diagram
flowchart TB
%% User Interactions
U["User - Web/Mobile"] -->|"1. GET /search?location=X&dates=Y-Z"| AG["API Gateway"]
U -->|"8. POST /book {hotelId, roomType, dates, userId}"| AG
%% Search Flow
AG -->|"2. search(location, dates, filters)"| SS["Search Service"]
SS -->|"3. query hotels + availability"| Cache["Redis Cache (Hot Data)"]
Cache -->|"4. cache miss"| SS
SS -->|"5. fetch from DB"| HotelDB[(Hotel Metadata DB)]
SS -->|"6. check availability"| IS["Inventory Service"]
IS -->|"7. read room counts"| InvDB[(Inventory DB)]
%% Booking Flow
AG -->|"9. POST /book"| BS["Booking Service"]
BS -->|"10. holdRooms(hotelId, roomType, checkIn, checkOut)"| IS
IS -->|"11. Lua: check + decrement all nights"| Redis["Redis (Holds + Per-Night Counters)"]
IS -.->|"12. sweeper releases expired holds"| Redis
BS -->|"13. initiatePayment(bookingId, amount)"| PS["Payment Service"]
PS -->|"14. call gateway"| PG["Payment Gateway (Stripe)"]
PG -->|"15. callback: success/failure"| PS
%% Payment Success Path
PS -->|"16. confirmPayment(bookingId)"| BS
BS -->|"17. confirmBooking(bookingId)"| IS
IS -->|"18. claim hold, decrement all nights (one txn)"| InvDB
BS -->|"19. INSERT booking record"| BookingDB[(Booking DB)]
%% Async Notifications
BS -->|"20. emit bookingConfirmed event"| MQ["Message Queue (Kafka)"]
MQ -->|"21. consume"| NS["Notification Service"]
NS -->|"22. send confirmation email/SMS"| U
%% Partner Dashboard
Hotel["Hotel Partner"] -.->|"update inventory/pricing"| PD["Partner Dashboard API"]
PD -.->|"UPDATE inventory"| IS
IS -.->|"invalidate cache"| Cache
%% Analytics
MQ -.->|"consume for analytics"| Analytics["Analytics Service"]
%% Styling
classDef userFlow fill:#e3f2fd,stroke:#1976d2,stroke-width:2px;
classDef coreService fill:#c8e6c9,stroke:#388e3c,stroke-width:2px;
classDef storage fill:#fff9c4,stroke:#f57f17,stroke-width:2px;
classDef async fill:#f8bbd0,stroke:#c2185b,stroke-width:2px;
class U,AG,Hotel userFlow;
class SS,IS,BS,PS,PD coreService;
class HotelDB,InvDB,BookingDB,Cache,Redis storage;
class MQ,NS,Analytics async;3) Components (what & why)
Client (Web/Mobile)
- Search interface with filters (location, dates, price, rating, amenities).
- Hotel detail pages with photos, reviews, room types, and pricing.
- Booking flow with date selection, room selection, and payment.
API Gateway
- Authentication, rate limiting, request validation.
- Routes to appropriate microservices.
- SSL termination and DDoS protection.
Search Service
- Responsibilities:
- Handle search queries with location, dates, and filters.
- Rank hotels by relevance, price, rating.
- Integrate with Inventory Service for real-time availability.
- Optimization:
- Cache popular searches in Redis (location + dates as key).
- Use Elasticsearch for full-text search and filtering.
- Pre-aggregate data for common queries.
Inventory Service (Core)
- Responsibilities:
- Manage room availability per hotel, room type, and date.
- Handle atomic room allocation (hold and confirm).
- Sync with hotel partner updates.
- Data Structure:
Inventory(hotel_id, room_type, date, available_count, booked_count)- Locking Mechanism:
- Use Redis for temporary holds across all nights of the stay, with a sweeper that releases expired holds.
- Use one DB transaction (all nights, locked in date order) for final booking confirmation.
Booking Service
- Responsibilities:
- Orchestrate booking flow: hold room → payment → confirm.
- Create booking records with user, hotel, dates, and payment info.
- Handle cancellations and refunds.
- State Machine: PENDING → PAYMENT_INITIATED → CONFIRMED / CANCELLED.
Payment Service
- Responsibilities:
- Integrate with external payment gateways (Razorpay, Stripe, PayPal etc).
- Handle async callbacks, retries, and idempotency.
- Process refunds for cancellations.
- Security: PCI-DSS compliance, tokenization, encrypted storage.
Hotel Metadata DB
- Store hotel info: name, location, amenities, photos, reviews, ratings.
- Read-heavy workload; use read replicas and caching.
Inventory DB
- Store room availability per hotel, room type, and date.
- High write load during bookings; use partitioning by hotel_id.
Booking DB
- Store booking records: user_id, hotel_id, room_type, dates, status, payment_id.
- Audit trail for all booking state changes.
Notification Service
- Asynchronous worker consuming from message queue.
- Send booking confirmations, reminders, and cancellation notifications via email/SMS/push.
Partner Dashboard
- Hotel partners manage inventory, pricing, and view bookings.
- Updates trigger cache invalidation for real-time consistency.
4) Data Model (minimal)
Hotel
Hotel(hotel_id, name, location, address, rating, amenities[], photos[], description)
Room Type
RoomType(room_type_id, hotel_id, type_name, capacity, base_price, amenities[])
Inventory (per date)
Inventory(hotel_id, room_type_id, date, total_rooms, available_rooms, price)
Booking
Booking(
booking_id,
user_id,
hotel_id,
room_type_id,
check_in_date,
check_out_date,
num_rooms,
total_price,
status, -- PENDING, CONFIRMED, CANCELLED
payment_id,
created_at,
updated_at
)
User
User(user_id, name, email, phone, preferences[])
Review
Review(review_id, user_id, hotel_id, rating, comment, created_at)
5) Key Flows
5.1 Search Flow
- User enters location (e.g., "Goa"), check-in/check-out dates, and filters.
- Search Service checks Redis cache for matching query.
- On cache miss: Query Elasticsearch for hotels matching location/filters.
- For each hotel, check availability via Inventory Service.
- Rank results by relevance, price, rating, and return to user.
- Cache results in Redis with TTL (5-10 minutes).
5.2 Booking Flow (Happy Path)
- User selects hotel, room type, and dates.
- Client calls Booking Service:
/book {hotel_id, room_type_id, dates, user_id}. - Booking Service calls Inventory Service to hold rooms.
- Inventory Service:
- Atomically reserves the rooms for every night of the stay (check-in up to, but not including, check-out) in Redis — all nights or none.
- Records the hold with a 10-minute expiry.
- Returns hold_id to Booking Service.
- The DB is not touched yet; it is decremented once, at confirmation (Deep Dive A).
- User completes payment on gateway.
- Payment Gateway calls callback URL with success status.
- Payment Service verifies callback and notifies Booking Service.
- Booking Service confirms booking:
- Calls Inventory Service to finalize (remove hold, persist booking).
- Inserts booking record in Booking DB.
- Notification Service sends confirmation email/SMS to user.
5.3 Failure Handling
- Payment Timeout: A sweeper finds holds past their expiry and adds the rooms back to each night's counter. (A plain Redis key TTL is not enough on its own: when a hold key expires, nothing gives the decremented rooms back.)
- Payment Failure: Mark booking as CANCELLED, release the hold immediately (same release script the sweeper uses).
- Payment succeeds after the hold expired: Try to re-reserve the same rooms; if they are gone, auto-refund and tell the user. Extending the hold when the user reaches the payment page makes this rare.
- Double-Booking Prevention: The Redis hold is all-or-nothing across nights; the DB confirm re-checks every night under row locks (or optimistic concurrency with a version field).
5.4 Cancellation Flow
- User requests cancellation → Booking Service validates cancellation policy.
- If allowed:
- Update booking status to CANCELLED.
- Increment
available_roomsin Inventory DB. - Initiate refund via Payment Service.
- Invalidate search cache for affected dates.
6) Deep Dive A: Inventory Management & Overbooking Prevention (~10 mins)
Problem
Multiple users may attempt to book the last available room concurrently. We must prevent overbooking while maintaining high throughput.
Challenges
- Race Condition: Two users check availability (5 rooms available) → both book → oversell.
- Multi-Night Stays: A 3-night stay needs a room on 3 separate
(hotel, room_type, date)rows. Reserving night 1 and 2 but failing on night 3 must not leave rooms stranded — all nights succeed or none do. - Abandoned Holds: Users close the tab mid-payment; their rooms must come back automatically.
- Performance: Locking should not bottleneck high traffic.
Solution: Two-Phase Booking (Redis Hold → DB Confirm)
Combine fast in-memory holds with one authoritative database write at confirmation. The DB count is decremented exactly once — when the booking is confirmed — never at hold time.
Phase 1: Temporary Hold (Redis)
- When: User clicks "Book Now".
- Data: One counter per night,
avail:{hotel}:{room_type}:{date}, loaded from the DB. Each hold is stored ashold:{hold_id}(which nights, how many rooms) and added to a sorted setholds:expiryscored by its expiry time. - Action: A Lua script checks every night of the stay first, and only if all have enough rooms does it decrement them all. Redis runs a Lua script atomically, so no other command can interleave between the check and the decrement.
- Release: A sweeper runs every few seconds, pulls holds whose expiry has passed from
holds:expiry, and runs a release script that adds the rooms back to each night. The same release script is used on payment failure or cancel. - Why not just a key TTL? A TTL deletes the hold key, but nothing adds the decremented rooms back to the per-night counters. Expiry has to *do* something, so it is driven by the sweeper.
- User clicks "Book Now" → Booking Service calls Inventory Service with all nights of the stay
- Inventory Service runs the hold script (atomic all-or-nothing check-and-decrement across nights)
- If successful: return hold_id and expiry to the user
- If failed: Return "Room unavailable" error
- User proceeds to payment page (has 10 minutes to complete; reaching the payment page can extend the hold once)
Phase 2: Confirm Booking (DB)
- When: Payment succeeds (payment gateway callback received).
- Claim the hold: Atomically remove
hold_idfromholds:expiry(ZREMreturns 1 only for the first caller). If it returns 0, the sweeper already released it → try to re-reserve; if that fails, refund. - Persist: One DB transaction locks all night rows for the stay in date order (a fixed lock order prevents deadlocks between overlapping stays), re-checks availability, decrements each night, and inserts the booking.
- Payment gateway sends success callback → Payment Service → Booking Service
- Booking Service claims the hold in Redis (
ZREM holds:expiry hold_id) - BEGIN;
SELECT ... FOR UPDATEon all nights, ordered by date - If every night still has rooms: decrement each night, insert booking record, COMMIT
- If any night is short (DB and Redis drifted — rare): ROLLBACK, release the Redis hold, refund payment
- Phase 1 (Redis): Fast hold for user experience (no user wants to wait on DB row locks during room selection)
- Phase 2 (DB): Final pessimistic lock for correctness (ensures money and inventory are consistent)
- Separation of concerns: Redis handles ephemeral holds, DB holds the permanent record. A reconciliation job periodically rebuilds Redis counters from the DB (
total − booked − active holds) to repair drift.
Two-Phase Booking Flow Diagram
Architecture Diagram
sequenceDiagram
participant User
participant BookingService
participant InventoryService
participant Redis
participant DB
participant PaymentGateway
Note over User,PaymentGateway: PHASE 1: Temporary Hold (Redis)
User->>BookingService: 1. Click "Book Now"
BookingService->>InventoryService: 2. holdRooms(hotel_id, room_type, check_in, check_out, n)
InventoryService->>Redis: 3. Lua: check ALL nights, then decrement ALL nights
alt Every night available
Redis-->>InventoryService: 4. Success, hold_id added to holds:expiry (now + 10 min)
InventoryService-->>BookingService: 5. Return hold_id
BookingService-->>User: 6. Show payment page
else Any night sold out
Redis-->>InventoryService: 4. Failure (nothing decremented)
InventoryService-->>BookingService: 5. Error: Room unavailable
BookingService-->>User: 6. Show "Sold Out"
end
Note over User,PaymentGateway: User has 10 mins to pay, a sweeper releases expired holds
User->>PaymentGateway: 7. Complete payment
PaymentGateway->>BookingService: 8. Callback: Payment Success
Note over User,PaymentGateway: PHASE 2: Confirm Booking (DB)
BookingService->>Redis: 9. ZREM holds:expiry hold_id (claim hold)
BookingService->>DB: 10. BEGIN, SELECT ... FOR UPDATE (all nights, date order)
alt Every night still available in DB
BookingService->>DB: 11. UPDATE each night: available_rooms - n
BookingService->>DB: 12. INSERT booking record
BookingService->>DB: 13. COMMIT
BookingService->>User: 14. Send confirmation (email/SMS)
else Hold already expired or DB short (edge case)
BookingService->>DB: 11. ROLLBACK
BookingService->>PaymentGateway: 12. Initiate refund
BookingService->>User: 13. Booking failed, refund initiated
end:nights nights):
BEGIN TRANSACTION;
-- Lock every night of the stay, always in date order (prevents deadlocks)
SELECT date, available_rooms FROM Inventory
WHERE hotel_id = :hotel AND room_type_id = :room_type
AND date >= :check_in AND date < :check_out
ORDER BY date
FOR UPDATE;
UPDATE Inventory
SET available_rooms = available_rooms - :n
WHERE hotel_id = :hotel AND room_type_id = :room_type
AND date >= :check_in AND date < :check_out
AND available_rooms >= :n;
-- If rows updated != :nights, some night was short: ROLLBACK and refund
INSERT INTO Booking (...) VALUES (...);
COMMIT;
Lua Script for Atomic Multi-Night Hold (Redis)
-- KEYS: one avail:{hotel}:{room_type}:{date} key per night of the stay
-- ARGV[1] = rooms requested, ARGV[2] = hold_id, ARGV[3] = expiry (epoch seconds)
local n = tonumber(ARGV[1])
-- Pass 1: check every night before touching anything
for i = 1, #KEYS do
if (tonumber(redis.call('GET', KEYS[i])) or 0) < n then
return 0 -- some night is sold out; nothing was decremented
end
end
-- Pass 2: all nights have room, so decrement them all
for i = 1, #KEYS do
redis.call('DECRBY', KEYS[i], n)
end
-- Record the hold so the sweeper (or a payment failure) can give the rooms back
redis.call('HSET', 'hold:' .. ARGV[2], 'rooms', n, 'nights', table.concat(KEYS, ','))
redis.call('ZADD', 'holds:expiry', ARGV[3], ARGV[2])
return 1
The release script is the mirror image: ZREM holds:expiry hold_id, and only if that returned 1, INCRBY each night by rooms and delete hold:{hold_id}. Checking the ZREM result means a hold is never released twice, and a confirmed hold is never released.
In a Redis Cluster, all of a hotel's keys must live in the same hash slot for a multi-key script, so use a hash tag: avail:{hotel_123}:deluxe:2024-01-15.
Alternative: Optimistic Concurrency Control
Instead of row-level locks, use a version number approach:
Step 1: Read current stateSELECT available_rooms, version
FROM Inventory
WHERE hotel_id = 'h123' AND room_type_id = 'r456' AND date = '2024-01-15';
--Returns: available_rooms = 5, version = 42
Step 2: Update with version check
UPDATE Inventory
SET available_rooms = available_rooms - 1,
version = version + 1
WHERE hotel_id = 'h123'
AND room_type_id = 'r456'
AND date = '2024-01-15'
AND version = 42 -- Only succeed if version hasn't changed
AND available_rooms > 0;
--Check rows affected:
--1 row affected → Success(you got the booking)
--0 rows affected → Conflict(someone else modified it, retry)
Why it prevents race conditions:
- User A reads version = 42, tries to update WHERE version = 42 → SUCCESS(version now 43)
- User B reads version = 42, tries to update WHERE version = 42 → FAILS(version is now 43)
- User B retries with new version
- Pro: No locking overhead, better concurrency
- Con: Requires retry logic, can have high contention during peak times
- Best for: Low-conflict scenarios (OCC assumes conflicts are rare)
7) Deep Dive B: Search Optimization & Caching (~8 mins)
Problem
With 1200 searches/sec (peak 5000/sec), querying the DB for every search is expensive and slow.
Solution: Multi-Layer Caching
Layer 1: Redis Cache(Hot Queries)
- Key :
search:{location}:{check_in}:{check_out}:{filters_hash} - Value: List of hotel IDs with availability and pricing.
- TTL: 5-10 minutes (balance freshness vs cache hit rate).
- Cache Invalidation: On inventory update (hotel partner changes pricing/availability).
Layer 2: Elasticsearch (Full-Text Search)
- Purpose: Fast filtering by location, amenities, rating, price range.
- Indexing: Hotel metadata indexed with geo-coordinates.
- Query: Geo-proximity search + filters.
- Update: Near real-time indexing (1-2 sec delay acceptable).
Layer 3: Pre-Aggregation (Popular Routes)
- Strategy: For popular destinations (e.g., Goa, Dubai), pre-compute hotel lists for common date ranges.
- Storage: Store in cache with longer TTL (1 hour).
- Refresh: Periodic background job updates cache.
Caching Architecture
Architecture Diagram
flowchart TD
User["User Search Request"] --> API["API Gateway"]
API --> Cache1["L1: Redis Cache"]
Cache1 -->|"cache hit"| Return["Return Cached Results"]
Cache1 -->|"cache miss"| ES["L2: Elasticsearch"]
ES -->|"fetch hotel IDs"| Inv["Inventory Service (Availability Check)"]
Inv -->|"check Redis/DB"| Results["Compute Results"]
Results --> Cache1
Results --> Return
Hotel["Hotel Partner Update"] --> Invalidate["Cache Invalidation"]
Invalidate --> Cache1
classDef cache fill:#fff9c4,stroke:#f57f17,stroke-width:2px;
classDef service fill:#c8e6c9,stroke:#388e3c,stroke-width:2px;
class Cache1,ES cache;
class Inv,Results service;Search Ranking Algorithm
score = w1 * relevance_score // location match
+ w2 * (1 / price) // price preference
+ w3 * avg_rating // user reviews
+ w4 * availability_premium // more rooms = higher score
+ w5 * user_preference_match // personalization
Personalization
- Track user's past bookings, searches, and preferences.
- Boost hotels matching user's preferred amenities (e.g., pool, gym).
8) Deep Dive C: Payment & Idempotency (~7 mins)
Problem
Payment processing is async and may fail, timeout, or be retried. We must ensure exactly-once semantics.
Challenges
- Double Charging: User clicks "Pay" multiple times.
- Network Failure: Payment succeeds at gateway but callback fails.
- Retry Storm: Client retries on timeout, causing duplicate requests.
Solution: Idempotency Key
Implementation
- Client generates idempotency key (UUID) on first payment request.
- Payment Service checks if key exists in Idempotency Store (Redis/DB).
- If exists: Return cached response (no-op).
- If new: Process payment and store result with key.
- INITIATED → PROCESSING → SUCCESS → NOTIFIED / FAILED.
State Machine Diagram
Architecture Diagram
stateDiagram-v2
[*] --> INITIATED: User clicks Pay
INITIATED --> PROCESSING: Call Payment Gateway
PROCESSING --> SUCCESS: Gateway callback (success)
PROCESSING --> FAILED: Gateway callback (failure)
PROCESSING --> TIMEOUT: No callback within 60s
SUCCESS --> NOTIFIED: Confirm Booking
TIMEOUT --> RETRY: Retry (check gateway status)
RETRY --> SUCCESS
RETRY --> FAILED
FAILED --> [*]
NOTIFIED --> [*]Idempotency Store Schema
{
"idempotency_key": "uuid-123",
"booking_id": "booking-456",
"status": "SUCCESS",
"payment_id": "pay-789",
"amount": 5000,
"created_at": "2023-10-15T10:00:00Z",
"response": { ... } // Cached response
}
Webhook Signature Verification
- Payment gateway signs callback with secret key.
- Payment Service verifies signature to prevent spoofing.
Refund Handling
- On cancellation, create refund request with idempotency key.
- Track refund status separately: PENDING → PROCESSED.
9) Scaling & Performance (~5 mins)
Horizontal Scaling
- Search Service: Stateless; scale with load balancer.
- Inventory Service: Partition by hotel_id (consistent hashing).
- Booking Service: Stateless; scale horizontally.
- DB: Shard by hotel_id or geography (e.g., US-West, EU, Asia).
Database Partitioning
- Inventory DB: Shard by
hotel_id, so every night of a stay lives on one shard and the confirm transaction never spans shards. (Sharding by(hotel_id, date)would turn every multi-night booking into a distributed transaction.) - Booking DB: Shard by
booking_idoruser_id. - Hot Partition Problem: Popular hotels (e.g., Taj Mahal Hotel) get many concurrent *writes*, which replicas don't help with. Keep confirm transactions short, let the Redis hold absorb the contention (only holders reach the DB), and serve availability *reads* from cache.
Caching Strategy
- Read-Heavy: Hotel metadata, reviews → Cache in CDN and Redis.
- Write-Heavy: Inventory updates → Write-through cache with invalidation.
CDN for Static Assets
- Hotel photos, videos → store in S3, serve via CloudFront.
Performance Metrics
- P99 Search Latency: < 500ms.
- P99 Booking Latency: < 2s.
- Cache Hit Rate: > 80% for searches.
10) Failure Modes & Recovery
Database Failure
- Read Replica Failover: Promote replica to master.
- Write Failures: Queue writes in Kafka, replay after recovery.
Redis Failure
- Search Cache: Degrade to Elasticsearch (slower but functional).
- Inventory Holds: Fallback to DB-only holds (a
holdstable withexpires_at, same all-nights transaction), then rebuild Redis counters from the DB when it recovers.
Payment Gateway Outage
- Queue Payments: Store in message queue, retry when gateway recovers.
- Fallback Gateway: Integrate multiple gateways (Stripe + PayPal).
Inventory Sync Issues
- Reconciliation Job: Periodically rebuild each Redis counter as
total − booked − active holdsfrom the DB, and alert on drift. - Audit Logs: Track all inventory changes for forensic analysis.
Geo-Redundancy
- Multi-region deployment (US, EU, Asia).
- DNS-based routing to nearest region.
11) Trade-offs & Alternatives
Eventually Consistent vs Strongly Consistent Inventory
- Strong: Use DB locks; slower but no overbooking.
- Eventual: Use Redis; faster but requires reconciliation.
- Choice: Hybrid (Redis for holds, DB for confirms).
SQL vs NoSQL
- SQL: ACID guarantees for bookings and payments.
- NoSQL: Better for hotel metadata (flexible schema).
- Choice: SQL for transactional data, NoSQL for metadata.
Synchronous vs Asynchronous Booking
- Sync: Immediate confirmation, better UX.
- Async: Decouple payment from booking, better resilience.
- Choice: Async with optimistic UI updates.
12) Security & Compliance
Payment Security
- PCI-DSS Compliance: No card data stored; use tokenization.
- TLS: All communication encrypted.
User Data Protection
- GDPR: User consent for data collection, right to deletion.
- Encryption: Encrypt PII (email, phone) at rest.
Rate Limiting
- Prevent scraping and DDoS attacks.
- Use API keys for partners.
Fraud Detection
- Monitor for unusual booking patterns (e.g., 100 bookings in 1 minute).
- Use CAPTCHA for suspicious activity.
13) Interview Time Allocation (45 min)
- 5 min: Requirements & scope (functional, non-functional, scale).
- 10 min: HLD & architecture diagram (components, data flow).
- 5 min: Data model & key flows (search, booking).
- 10 min: Deep dive on inventory management & overbooking prevention.
- 8 min: Deep dive on search optimization & caching.
- 5 min: Scaling, failure handling, and trade-offs.
- 2 min: Security, Q&A, and wrap-up.
14) Summary
- Core Challenges: Inventory consistency (overbooking prevention), search optimization (caching), payment reliability (idempotency).
- Key Components: Search Service (Elasticsearch + Redis), Inventory Service (Redis holds + DB confirms), Booking Service (orchestration), Payment Service (idempotency + async callbacks).
- Scaling Strategy: Horizontal scaling, DB partitioning by hotel_id, multi-layer caching (Redis + Elasticsearch + CDN).
- Correctness: Two-phase booking (Redis hold + DB confirm), row-level locking, idempotency keys for payments.
This design handles millions of searches and bookings per day while ensuring no overbooking and consistent user experience.