Case Studies

Airline Management System

Design an airline management system — flights, routes, schedules, seats, bookings.

4 min readDesigns · LLD & Patterns

Interview practice: try designing this yourself before reading. Go to the exercise ↓

Problem Statement

Design an airline reservation system supporting:

  • Flight schedules across cities
  • Aircraft and seat layouts (multi-class: economy, business, first)
  • Search by route + date
  • Booking with seat selection
  • Multi-leg itineraries (with layovers)
  • Cancellation and refund per fare rules
  • Check-in and boarding

Requirements

Functional

  • Aircraft types with seat maps (config per class)
  • Flights = (aircraft, route, departure, arrival)
  • Search by origin / destination / date / class
  • Multi-leg itineraries with connections
  • Book a seat for a passenger; validate availability
  • Cancel / refund / change
  • Online check-in within window

Non-Functional

  • No double-booking on a (flight, seat) pair
  • Concurrent search and booking
  • Audit trail
  • Eventual consistency in search index OK

Class Diagram


Aircraft & Seat Map

public enum SeatClass { ECONOMY, BUSINESS, FIRST }

public class Seat {
    public final String id;            // "12A"
    public final int row;
    public final char column;          // 'A', 'B', ...
    public final SeatClass seatClass;

    public Seat(int row, char col, SeatClass cls) {
        this.id = row + String.valueOf(col);
        this.row = row; this.column = col; this.seatClass = cls;
    }
}

public class Aircraft {
    private final String id;
    private final String model;
    private final List<Seat> seats;

    public List<Seat> seatsByClass(SeatClass cls) {
        return seats.stream().filter(s -> s.seatClass == cls).toList();
    }
}

A Boeing 787 is its own Aircraft with a fixed seat map. Different aircraft of the same model could have slightly different layouts.


Flight & Per-Flight Seat State

public enum SeatStatus { AVAILABLE, HELD, BOOKED, BLOCKED }

public class Flight {
    private final String id;
    private final String number;
    private final Aircraft aircraft;
    private final Route route;
    private final ZonedDateTime departure;
    private final ZonedDateTime arrival;
    private FlightStatus status = FlightStatus.SCHEDULED;

    private final ConcurrentMap<String, SeatStateHolder> seatStates = new ConcurrentHashMap<>();

    public Flight(Aircraft aircraft, Route route, ZonedDateTime dep, ZonedDateTime arr) {
        this.id = UUID.randomUUID().toString();
        this.number = generateNumber();
        this.aircraft = aircraft;
        this.route = route;
        this.departure = dep;
        this.arrival = arr;
        for (Seat s : aircraft.getAllSeats()) {
            seatStates.put(s.id, new SeatStateHolder());
        }
    }

    public synchronized boolean reserveSeat(String seatId, String holdId) {
        SeatStateHolder h = seatStates.get(seatId);
        if (h == null || h.status != SeatStatus.AVAILABLE) return false;
        h.status = SeatStatus.HELD;
        h.holdId = holdId;
        return true;
    }

    public synchronized void confirmSeat(String seatId, String holdId) {
        SeatStateHolder h = seatStates.get(seatId);
        if (h == null || !holdId.equals(h.holdId)) throw new IllegalStateException();
        h.status = SeatStatus.BOOKED;
    }

    public synchronized void releaseSeat(String seatId, String holdId) {
        SeatStateHolder h = seatStates.get(seatId);
        if (h != null && holdId.equals(h.holdId)) {
            h.status = SeatStatus.AVAILABLE;
            h.holdId = null;
        }
    }

    public List<Seat> availableSeats(SeatClass cls) {
        return aircraft.seatsByClass(cls).stream()
            .filter(s -> seatStates.get(s.id).status == SeatStatus.AVAILABLE)
            .toList();
    }

    private static class SeatStateHolder {
        SeatStatus status = SeatStatus.AVAILABLE;
        String holdId;
    }
}

Search (Multi-Leg)

public class FlightSearch {
    private final FlightRepository flights;
    private final int MAX_LAYOVERS = 2;

    public List<Itinerary> search(Airport origin, Airport dest,
                                   LocalDate date, SeatClass cls) {
        List<Itinerary> result = new ArrayList<>();
        // Direct flights
        for (Flight f : flights.findByRouteAndDate(origin, dest, date)) {
            if (hasAvailability(f, cls)) result.add(new Itinerary(List.of(f)));
        }
        // 1-stop
        for (Airport hub : possibleHubs()) {
            if (hub.equals(origin) || hub.equals(dest)) continue;
            for (Flight leg1 : flights.findByRouteAndDate(origin, hub, date)) {
                for (Flight leg2 : flights.findByRouteAfter(hub, dest, leg1.getArrival())) {
                    if (validConnection(leg1, leg2)
                            && hasAvailability(leg1, cls)
                            && hasAvailability(leg2, cls)) {
                        result.add(new Itinerary(List.of(leg1, leg2)));
                    }
                }
            }
        }
        return result;
    }

    private boolean validConnection(Flight a, Flight b) {
        Duration layover = Duration.between(a.getArrival(), b.getDeparture());
        return layover.compareTo(Duration.ofMinutes(45)) >= 0
            && layover.compareTo(Duration.ofHours(8)) <= 0;
    }
}

For real airlines, this search becomes a graph problem — Dijkstra or BFS over a flight graph with edges per scheduled flight. Indexing services like AmadeusGDS pre-compute results.


Booking with Atomic Multi-Seat Reservation

public class AirlineService {
    private static final Duration HOLD_TTL = Duration.ofMinutes(10);
    private final Map<String, SeatHold> holds = new ConcurrentHashMap<>();

    public SeatHold holdSeats(Itinerary itin, List<String> seatIds) {
        String holdId = UUID.randomUUID().toString();
        if (itin.segments().size() != seatIds.size())
            throw new IllegalArgumentException("seat per segment");

        // Phase 1: reserve all
        List<Pair<Flight, String>> acquired = new ArrayList<>();
        for (int i = 0; i < itin.segments().size(); i++) {
            Flight f = itin.segments().get(i);
            String sid = seatIds.get(i);
            if (!f.reserveSeat(sid, holdId)) {
                // Rollback
                for (Pair<Flight, String> p : acquired) p.left.releaseSeat(p.right, holdId);
                throw new SeatUnavailableException();
            }
            acquired.add(new Pair<>(f, sid));
        }

        SeatHold hold = new SeatHold(holdId, itin, seatIds, HOLD_TTL);
        holds.put(holdId, hold);
        return hold;
    }

    public Booking confirm(SeatHold hold, Passenger p, Payment payment) {
        if (hold.isExpired()) throw new HoldExpiredException();
        // Process payment
        payment.process();
        // Confirm all seats
        for (int i = 0; i < hold.itinerary.segments().size(); i++) {
            Flight f = hold.itinerary.segments().get(i);
            f.confirmSeat(hold.seatIds.get(i), hold.id);
        }
        Booking b = new Booking(p, hold.itinerary, hold.seatIds, payment);
        holds.remove(hold.id);
        return b;
    }
}

Multi-leg booking is all-or-nothing — if any leg's seat fails, release all.


Cancellation (Strategy)

public interface FareRule {
    boolean allowsCancellation();
    double refundFraction(Duration timeUntilDeparture);
}

public class FlexibleFare implements FareRule {
    public boolean allowsCancellation() { return true; }
    public double refundFraction(Duration t) { return 1.0; }     // full refund anytime
}

public class StandardFare implements FareRule {
    public boolean allowsCancellation() { return true; }
    public double refundFraction(Duration t) {
        if (t.toDays() > 7) return 0.8;
        if (t.toHours() > 24) return 0.5;
        return 0.0;
    }
}

public class NonRefundableFare implements FareRule {
    public boolean allowsCancellation() { return true; }
    public double refundFraction(Duration t) { return 0.0; }
}

Sequence: Book Multi-Leg Flight


Check-in

public class CheckInService {
    public BoardingPass checkIn(Booking b, Flight segment) {
        Duration timeToDeparture = Duration.between(Instant.now(), segment.getDeparture().toInstant());
        if (timeToDeparture.compareTo(Duration.ofHours(24)) > 0) {
            throw new CheckInWindowNotOpenException();
        }
        if (timeToDeparture.compareTo(Duration.ofMinutes(45)) < 0) {
            throw new CheckInClosedException();
        }
        return new BoardingPass(b.getPassenger(), segment, b.seatFor(segment));
    }
}

Edge Cases

CaseHandling
Hold expires mid-paymentRelease all seats; user retries
Multi-leg with one cancelled flightAuto-rebook on next available; or refund
Overbooking (intentional)Compensate bumped passenger; airlines often overbook 5%
Time zone confusionAlways store UTC; render in local TZ at display
Layover too shortSearch filters out connections < 45 min
Aircraft swap (different seat map)Reseat passengers, attempt to preserve class
No-showHold seat through departure; later mark missed

Design Patterns Used

PatternWhere
StateFlightStatus, SeatStatus, BookingStatus
StrategyFare rules (refund policy), search algorithm
FacadeAirlineService
RepositoryFlights, bookings, passengers
ObserverNotify passenger of delays / changes
BuilderItinerary construction
CompositeItinerary is a list of Flight segments — uniform treatment

Interview Tips

  • Distinguish the static seat map (per aircraft type) from per-flight seat state (which seats are booked on this specific flight). Same plane → many flights → independent seat states.
  • Multi-leg booking must be atomic — all legs reserved, or none.
  • Bring up idempotent payment (same as movie booking) and hold TTL for mid-checkout protection.
  • Mention GDS (Global Distribution Systems like Amadeus / Sabre) — that's how real airlines do flight inventory, and it's worth knowing the term.
  • For overbooking, mention the airline industry deliberately overbooks ~5% — it's a real strategy, not a bug.

Practice

Try it yourself

Design the classes for an airline booking and management system.

Your design should cover

  • Flights on routes with schedules and aircraft
  • Search including multi-leg journeys
  • Book several seats for several passengers atomically
  • Seat classes and seat maps per aircraft
  • Cancellation with different refund rules
0 / 8,000 characters · saved in this browser

Finished reading?

Mark it done to track your progress in Designs.