Distributed Hotel Booking Platform
The Engineering Challenge
Building a reliable booking engine is fundamentally a problem of distributed state and concurrency. When hundreds of users compete for the same limited room inventory, the system must guarantee ACID compliance, prevent double bookings, and maintain low latency.
For this platform, I architected a polyglot microservices ecosystem from scratch. Rather than relying on a monolithic framework, I designed five isolated domain services (Auth, Booking, Hotel, Review, and Notification) using Node.js (TypeScript) and Go, communicating via synchronous REST for strict validation and asynchronous Redis queues for non-blocking operations.
Architectural Philosophy: "Share-Nothing"
Each service operates in a completely independent directory with its own dependencies, its own environmental configuration, and its own isolated MySQL database.
While this approach requires duplicating lightweight assets (like custom error classes and DTOs), it prevents the "distributed monolith" anti-pattern. A change in the Booking Service's database schema or error handling has zero risk of accidentally breaking the Hotel Service.

Solving Core Technical Problems
1. Concurrency Control: The Double-Booking Problem
To guarantee idempotency during the checkout flow, I implemented a two-tier locking strategy that handles both distributed traffic spikes and row-level data integrity.
- Layer 1: Distributed Locking (Redis Redlock): When a booking is initiated, the system acquires a distributed lock via Redlock scoped to the booking
hotelIdwith a TTL. This acts as a coarse-grained traffic filter, preventing a stampede of concurrent requests for the same property from overwhelming the database simultaneously. - Layer 2: Pessimistic Row-Level Locking (MySQL): During the actual payment confirmation phase, the Booking Service utilises a strict pessimistic lock within a Prisma
$transaction(on the idempotency key). This guarantees that even if a client retries a network request, the database serialises the operations, making double-billing or double-booking impossible.

2. Eventual Consistency & Asynchronous Workers
Synchronous third-party API calls (like SMTP email dispatch) degrade primary API response times. To solve this, the Notification Service acts as an isolated background worker.
When a user registers or confirms a booking, the Auth/Booking services push a MailPayload to a BullMQ (Redis) queue and immediately return a 200 OK to the client. The Notification Service consumes these events, injects dynamic data into Handlebars (.hbs) templates, and dispatches the emails. If the queue push fails, the system logs the error and gracefully degrades rather than blocking the user's critical path.
3. Data Integrity & Anti-Spoofing (Review Service)
In a distributed system, foreign keys cannot enforce relationships across different databases. To ensure users cannot submit fraudulent reviews for hotels they never visited, the Go-based Review Service employs a strict Anti-Spoofing Gateway Pattern.
When a review payload is received, the service completely ignores the client-provided userId and hotelId. Instead, it makes a synchronous backend HTTP call to the Booking Service using the booking_id. If the booking is valid, it extracts the authoritative IDs directly from the Booking Service response, effectively neutralizing malicious payload injection.
Furthermore, to maintain high throughput, the Review Service writes the review to its local DB and flags it with is_synced: false, scaffolding an Outbox Pattern for eventual consistency aggregation with the Hotel Service.
Engineering Retrospective & Next Steps
Building this project provided valuable hands-on experience in managing microservice boundaries and balancing complexity with developer velocity. Practical next steps for the codebase include:
- Containerization: Wrapping all services into a unified
docker-composesetup to simplify local setup and service orchestration. - Observability & Health Checks: Adding centralized log monitoring and standard
/healthendpoints to streamline debugging and monitoring.