🇮🇳
🇮🇳
Republic Day Special Offer!Get 20% OFF on all courses
Enroll Now
P
Prakalpana
📚Learn
Code Your Future
System Design⏱️ 22 min read📅 Jan 7

LLD: Design BookMyShow - Movie Ticket Booking System

PM
Priya MenonTech Lead at Flipkart
📑 Contents (13 sections)

📌Problem Statement

Design an online movie ticket booking system like BookMyShow or Fandango.

📌Requirements

Functional

  • Browse movies by city
  • View show timings
  • Select seats and book
  • Make payment
  • Cancel booking
  • Non-Functional

  • Handle concurrent seat selection
  • No double booking
  • Support multiple cities/theaters
  • 📌Class Design

    Enums

    public enum SeatType {
    REGULAR, PREMIUM, VIP
    }
    public enum BookingStatus {
    PENDING, CONFIRMED, CANCELLED
    }
    public enum PaymentStatus {
    PENDING, SUCCESS, FAILED, REFUNDED
    }

    Core Entities

    public class Movie {
    private String movieId;
    private String title;
    private String description;
    private int durationMinutes;
    private String language;
    private String genre;
    private LocalDate releaseDate;
    }
    public class Theater {
    private String theaterId;
    private String name;
    private String address;
    private City city;
    private List<Screen> screens;
    }
    public class Screen {
    private String screenId;
    private String name;
    private Theater theater;
    private List<Seat> seats;
    }
    public class Seat {
    private String seatId;
    private int row;
    private int column;
    private SeatType type;
    private Screen screen;
    }

    Show and ShowSeat

    public class Show {
    private String showId;
    private Movie movie;
    private Screen screen;
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private Map<String, ShowSeat> showSeats;
    public Show(Movie movie, Screen screen, LocalDateTime startTime) {
    this.showSeats = new HashMap<>();
    for (Seat seat : screen.getSeats()) {
    showSeats.put(seat.getSeatId(), new ShowSeat(seat, this));
    }
    }
    }
    public class ShowSeat {
    private Seat seat;
    private Show show;
    private boolean isBooked;
    private double price;
    private String lockedBy;
    private LocalDateTime lockExpiry;
    public synchronized boolean tryLock(String userId, int lockMinutes) {
    if (isBooked) return false;
    if (lockedBy != null && lockExpiry.isAfter(LocalDateTime.now())) {
    return lockedBy.equals(userId);
    }
    this.lockedBy = userId;
    this.lockExpiry = LocalDateTime.now().plusMinutes(lockMinutes);
    return true;
    }
    public synchronized void unlock() {
    this.lockedBy = null;
    this.lockExpiry = null;
    }
    public synchronized boolean book() {
    if (isBooked) return false;
    this.isBooked = true;
    this.lockedBy = null;
    return true;
    }
    }

    Booking System

    public class Booking {
    private String bookingId;
    private User user;
    private Show show;
    private List<ShowSeat> seats;
    private BookingStatus status;
    private Payment payment;
    private LocalDateTime bookingTime;
    private double totalAmount;
    public Booking(User user, Show show, List<ShowSeat> seats) {
    this.bookingId = UUID.randomUUID().toString();
    this.user = user;
    this.show = show;
    this.seats = seats;
    this.status = BookingStatus.PENDING;
    this.totalAmount = seats.stream()
    .mapToDouble(ShowSeat::getPrice)
    .sum();
    }
    }

    Booking Service with Concurrency

    public class BookingService {
    private static final int LOCK_TIMEOUT_MINUTES = 10;
    private Map<String, Booking> bookings;
    private PaymentService paymentService;
    public Booking initiateBooking(User user, Show show, List<String> seatIds) {
    List<ShowSeat> seats = new ArrayList<>();
    for (String seatId : seatIds) {
    ShowSeat showSeat = show.getShowSeats().get(seatId);
    if (showSeat == null) {
    throw new SeatNotFoundException(seatId);
    }
    if (!showSeat.tryLock(user.getUserId(), LOCK_TIMEOUT_MINUTES)) {
    unlockSeats(seats, user.getUserId());
    throw new SeatNotAvailableException(seatId);
    }
    seats.add(showSeat);
    }
    Booking booking = new Booking(user, show, seats);
    bookings.put(booking.getBookingId(), booking);
    return booking;
    }
    public Booking confirmBooking(String bookingId, PaymentDetails paymentDetails) {
    Booking booking = bookings.get(bookingId);
    Payment payment = paymentService.process(paymentDetails, booking.getTotalAmount());
    if (payment.getStatus() == PaymentStatus.SUCCESS) {
    for (ShowSeat seat : booking.getSeats()) {
    seat.book();
    }
    booking.setStatus(BookingStatus.CONFIRMED);
    booking.setPayment(payment);
    } else {
    unlockSeats(booking.getSeats(), booking.getUser().getUserId());
    throw new PaymentFailedException();
    }
    return booking;
    }
    private void unlockSeats(List<ShowSeat> seats, String userId) {
    for (ShowSeat seat : seats) {
    seat.unlock();
    }
    }
    }

    📌Handling Race Conditions

    The key challenge is preventing double booking:

  • 1Optimistic Locking: Use version numbers in database
  • 2Pessimistic Locking: Lock seats during selection
  • 3Temporary Locks: Lock for X minutes during checkout
  • We use approach 3 with tryLock() method.

    📌Database Schema

    CREATE TABLE bookings (
    booking_id VARCHAR(50) PRIMARY KEY,
    user_id VARCHAR(50),
    show_id VARCHAR(50),
    status VARCHAR(20),
    total_amount DECIMAL(10,2),
    booking_time TIMESTAMP
    );
    CREATE TABLE booking_seats (
    booking_id VARCHAR(50),
    seat_id VARCHAR(50),
    price DECIMAL(10,2),
    PRIMARY KEY (booking_id, seat_id)
    );

    📌Interview Tips

  • Focus on concurrency handling
  • Explain seat locking mechanism
  • Discuss payment failure scenarios
  • Talk about scalability (sharding by city)
  • Asked at Flipkart, Swiggy, and Paytm interviews.

    PM

    Written by

    Priya Menon

    Tech Lead at Flipkart

    🚀 Master System Design

    Join 500+ developers

    Explore Courses →
    Chat on WhatsApp