Home   system-design  

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

System Components

  1. Client Applications (Web and Mobile):

    • Interfaces for users to search for hotels, view details, make bookings, and manage reservations.
  2. 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;
      }
      
  3. 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.
  4. Authentication and Authorization

    • JWT: Token-based authentication for securing API endpoints and managing user sessions.
  5. Payment Gateway

    • Stripe: Integrated for handling secure and reliable payment transactions.
  6. Messaging

    • RabbitMQ: Used for asynchronous tasks such as sending booking confirmations and processing payments.
  7. Monitoring and Analytics

    • Prometheus and Grafana: Monitor system metrics, track performance, and troubleshoot issues proactively.

Scalability and Fault Tolerance

Security

Published on: Jul 10, 2024, 01:20 AM  
 

Comments

Add your comment