System design for hotel booking system
Designing a hotel booking system involves creating a robust platform that allows users to search for hotels, make reservations, manage bookings, and handle payments. Below is a detailed system design using Prisma for database modeling, Express.js for API routes, and a recommended tech stack:
Tech Stack
- Backend: Node.js with Express.js
- Database: PostgreSQL for relational data (users, hotels, bookings), Redis for caching
- ORM: Prisma for database interactions
- Caching: Redis for caching frequently accessed data (session management, search results)
- Authentication: JWT (JSON Web Tokens) for user authentication and authorization
- Messaging: RabbitMQ for handling asynchronous tasks (booking confirmation, payment processing)
- Payment Gateway: Stripe for handling payments securely
- Monitoring: Prometheus and Grafana for monitoring system metrics
System Components
-
Client Applications (Web and Mobile):
- Interfaces for users to search for hotels, view details, make bookings, and manage reservations.
-
Express.js Backend
-
Prisma Models:
// schema.prisma datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @id @default(autoincrement()) username String @unique email String @unique password String bookings Booking[] createdAt DateTime @default(now()) } model Hotel { id Int @id @default(autoincrement()) name String description String? address String imageUrl String? rooms Room[] } model Room { id Int @id @default(autoincrement()) hotelId Int hotel Hotel @relation(fields: [hotelId], references: [id]) type String price Float capacity Int available Boolean @default(true) bookings Booking[] } model Booking { id Int @id @default(autoincrement()) userId Int user User @relation(fields: [userId], references: [id]) roomId Int room Room @relation(fields: [roomId], references: [id]) checkIn DateTime checkOut DateTime totalPrice Float status String // confirmed, pending, cancelled createdAt DateTime @default(now()) }
-
Express API Routes:
// server.js const express = require('express'); const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); const jwt = require('jsonwebtoken'); const bcrypt = require('bcrypt'); const app = express(); app.use(express.json()); // Endpoint for user registration app.post('/register', async (req, res) => { const { username, email, password } = req.body; try { const hashedPassword = await bcrypt.hash(password, 10); const user = await prisma.user.create({ data: { username, email, password: hashedPassword, }, }); res.json(user); } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to register user' }); } }); // Endpoint for user login and JWT generation app.post('/login', async (req, res) => { const { username, password } = req.body; try { const user = await prisma.user.findUnique({ where: { username } }); if (!user) { return res.status(404).json({ error: 'User not found' }); } const passwordMatch = await bcrypt.compare(password, user.password); if (!passwordMatch) { return res.status(401).json({ error: 'Invalid password' }); } const token = jwt.sign({ userId: user.id }, 'secret', { expiresIn: '1h' }); res.json({ token }); } catch (error) { console.error(error); res.status(500).json({ error: 'Login failed' }); } }); // Endpoint for searching hotels app.get('/hotels', async (req, res) => { const { query } = req.query; try { const hotels = await prisma.hotel.findMany({ where: { OR: [ { name: { contains: query || '' } }, { description: { contains: query || '' } }, ], }, }); res.json(hotels); } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to fetch hotels' }); } }); // Endpoint for making a booking app.post('/bookings', async (req, res) => { const { userId, roomId, checkIn, checkOut } = req.body; try { const room = await prisma.room.findUnique({ where: { id: roomId } }); if (!room || !room.available) { return res.status(404).json({ error: 'Room not available' }); } const totalPrice = calculateTotalPrice(room.price, checkIn, checkOut); const booking = await prisma.booking.create({ data: { userId: parseInt(userId), roomId: parseInt(roomId), checkIn, checkOut, totalPrice, status: 'pending', }, }); // Update room availability await prisma.room.update({ where: { id: roomId }, data: { available: false }, }); res.json(booking); } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to make booking' }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); }); function calculateTotalPrice(pricePerNight, checkInDate, checkOutDate) { const days = Math.ceil((new Date(checkOutDate) - new Date(checkInDate)) / (1000 * 60 * 60 * 24)); return pricePerNight * days; }
-
-
Database Layer
- PostgreSQL: Stores user data, hotel details, room information, and booking transactions.
- Redis: Used for caching search results, session management, and improving application performance.
-
Authentication and Authorization
- JWT: Token-based authentication for securing API endpoints and managing user sessions.
-
Payment Gateway
- Stripe: Integrated for handling secure and reliable payment transactions.
-
Messaging
- RabbitMQ: Used for asynchronous tasks such as sending booking confirmations and processing payments.
-
Monitoring and Analytics
- Prometheus and Grafana: Monitor system metrics, track performance, and troubleshoot issues proactively.
Scalability and Fault Tolerance
- Horizontal Scaling: Deploy multiple instances of microservices and use load balancing to handle high traffic and ensure availability.
- Database Sharding: Partition databases to distribute load and scale horizontally as the number of users and bookings increase.
- Redundancy and Backup: Store backups in Amazon S3 and deploy services across multiple availability zones (AZs) for fault tolerance and disaster recovery.
Security
- Data Encryption: Use SSL/TLS for secure data transmission and implement encryption at rest for sensitive information stored in databases.
- Authorization: Implement role-based access control (RBAC) to restrict access to sensitive APIs and operations.
Published on: Jul 10, 2024, 01:20 AM