HomeNotesTicket Booking System

Building a Ticket Booking Platform from Scratch: My Role & Technical Journey

Published Jul 18, 2025
Updated Jul 20, 2025
5 minutes read

I’ve been working on a ticket and food booking platform for cinemas at my current company. In this blog, I’ll share my role as an engineer and the technical challenges I tackled.

We were tasked to deliver four key components:

I worked on three of these (everything except the mobile app).

Understanding Vista

Before anything, you need to understand Vista. Vista is a cloud service widely used across the world to manage showtimes, food, and beverages. It includes all the modules needed to run a cinema. We built our platform on top of Vista, leveraging its architecture and customizing it to meet the client’s needs.

Scope of Work

Landing page, a flashy banner, with a quick book option which is dynamic, that is you selecting any 1 option filters out the rest of the options, so we call it Dynamic Quick book, under that is movies listing, again with multi filter selection, under that is misc stuff like offers, a dynamic footer serving content country wise

Performance optimisation

There is no SSR (server side rendering for this page) we do use (generateMetadata), we had one initially for the banner but we saw that it was blocking out main thread as the api was taking too much time so initial load was slow, so we used lazy loading & suspense (love suspense fr) for non essential parts of the page and created a view on the backend so that fetching banners images, movie details from multiple tables isn’t slow + cached all the get api’s

Moving to schedules page, when you click on “book now” it takes you to schedules page, which shows list of all available dates and under that mall wise schedules for movies with the experience it is serving, the date for each date re-fetched every time, which should be optimized to not re-fetch for already fetched data (More work for me!), filters don’t filter the dates showing user dates with empty schedules (Bad UX). Now if you click on any 1 schedule it takes you to seat layout.


Seat Layout

Every auditorium or theatre has a unique seat layout, rendering each one of them correctly matching exactly like the real audi each was very important task as a wrong depiction of the seat layout on the web would be a disaster

I’ve sort of also hacked my way into creating a perfect seat layout, the layout is good now. special mention DMarwah for helping me add a final fix.

The seat layout also has a mini map (which is on of my fav implementations) which allows small screen users to understand the seat layout by giving showing them the entire seating layout in one small view

On the seat layout you can check the schedules using the Side panel the dates and schedules are available tho it doesn’t show the experience (might be good ux to show up on hover)

Now comes the feature development part (client requirements) we want to give users an option to apply Bank offers & Loyalty program offers on Seat layout themselves ! After selecting the seats, extraordinary . Let’s see how bank offers work

Bank offers

We render bank discounts to the user, the user needs to validate their card in order to apply the discount, if the users card is validated we apply the discount, now since the user has not selected seats, they are pre applying the discounts, we check the minimum and maximum number of seats required to apply the discount, with the area category code, then check the new ticket price and update the ticket type code selected by the user

The bank isApplied flag is then turned on and when user continues, to next page, the apply api is called validating the same logic and returning the updated discount to the client.

To integrate this with our payment gateway, since using bank offers require us to pay using card only, dibsy (very good payment gateway, had fun working with the team) created a card tokenisation feature for us allowing us to tokenise the card on seat layout and allowing user to only pay using that card on the checkout page.

  const checkMinimumSeatRequirement = (item) => {
    const sameAreaData = selectedSeats?.reduce((acc, seat) => {
      if (acc[seat.areaName]) {
        acc[seat.areaName].count += 1
        acc[seat.areaName].Price = seat.price
      } else {
        acc[seat.areaName] = {
          count: 1,
          Price: seat?.price,
          areaCategoryCode: seat?.areaCategoryCode,
        }
      }
      return acc
    }, {})

Loyalty program

Loyalty program has few basic validation checks for

Loyalty can be applied at 2 pages, seat layout & checkout

A. Seat Selection Phase (seatLayout = true):

B. Payment/Booking Phase (seatLayout = false):

Promotion offers

Promotion offers which are internal novo cinemas offers are also implemented on this page, but the feature’s flow has been changed from what was discussed during development flow so this is WIP.


Food & Beverages engine

Food and beverages was one of the most challenging state management I have worked on

For this implementation I use one source of truth (cart) and mirror only the UI‑critical pieces we use (fnbPriceDetails).

fnb-diagram.png

Technical Jargon

Adding / removing without modifiers

const immediateUpdateNoModifiers = (item, qtyDelta) =>

opening the dialog box

SituationWhat opens
Item has neither modifiers nor alternatesimmediateUpdateNoModifiers (no dialog)
First time adding, or item has alternatesModifier Modal
Item is already in cart multiple times / combos and user clicks Aggregator Modal (choose which combo line to change)
Item is in cart, + pressed again, but no alternatesAggregator Modal (quick qty)

Selecting modifiers

handleModifierChange(modId, qty, groupId, idx)

Radio‑groups (max = 1) replace any previous choice.

Quantity selectors increment/decrement per key

key = ${itemId}-${modifierId}-${index} -> unique inside modifierSelections.

selectedByGroup keeps which radio is active so the input is checked.

Shows each unique combo for that base item.

Implementation Take‑Aways

That covers the moving parts: state flows, dialog orchestration, validation, quantity guards, and price construction.


Checkout page

After the user selects the food & beverages they want they continue to the checkout page, where we have Payment & Offers

Let’s talk about offers first

  1. Loyalty offers: These are synced with the offers on the home page user can apply, remove grouped offers here
  2. Bank offers: If you have applied a bank offer on the seat layout page your card number’s first and last 4 digit would already be present prompting you to just enter your cvv and expiry and checkout, otherwise you can also remove the offers & pay using other cards, or just apply the offer if you’re here for the first time
  3. Promotions & offers: These are custom offers decided by the team
  4. Other than these we also have voucher code, which can applied on any screen and you will get a voucher discount
  5. Novo wallet : There is a personal wallet for the users which users can use to pay, they can top up their wallet and pay using that
  6. Users can purchase gift cards which can be used at the time of checkout

After applying the offers if your total amount goes to 0 you can just proceed and your ticket will be booked otherwise you need to pay the rest of the amount

Payment

For payment we have the following options

  1. apple pay
  2. google pay
  3. credit card
  4. debit card

Apple pay is the most widely used payment method in Qatar, after deployment we have been monitoring the apple pay transaction status and it has been 97% success rates.

This covers the entire booking flow from seat layout to checkout page, There are 2 other flows, private booking & Kiosk.

For Kiosk systems, We have the entire booking flow with direct food and beverages flow and POS machine integration and writing code in .NET, will write a blog on that soon

This project has been a deep dive into large-scale system design, state management, and performance optimization. It taught me how to balance user experience, business requirements, and technical complexity. In the next blog, I’ll cover private booking flow and our .NET-based kiosk implementation.”