The "Parking Lot System" is a classic Low-Level Design (LLD) problem frequently encountered in interviews at top tech companies. It tests a candidate's ability to model real-world entities into clean, object-oriented code, manage relationships, and define clear business logic.

This article breaks down the LLD for a Parking Lot Management System, covering requirements, the class model, database schema, and core C# implementation.

1. Defining the Problem and MVP Features

🎯 The Problem Statement

Design a robust, scalable system to manage a multi-level parking facility. The system must efficiently handle vehicle entry, assign parking spots, generate tickets, process payments, and track overall availability.

✨ Minimum Viable Product (MVP) Features

  1. Ticket Generation: Generate a unique ticket upon vehicle entry, recording the entry time, vehicle, and assigned spot.
  2. Spot Assignment: Assign the most appropriate and nearest available spot to an incoming vehicle based on its type (Car, Bike, EV, etc.).
  3. Payment Processing: Calculate the parking fee based on the duration and vehicle type when the vehicle exits.
  4. Availability Management: Maintain a real-time count of available spots across all levels and types.

2. Object-Oriented Design (OOD): The Class Diagram

The core of the LLD is the Class Diagram, which defines the system's entities, attributes, and relationships.

🧱 Key Classes and Relationships

1. Parking Lot (The Whole)

  • Role: The central management entity, containing all levels and spots.
  • Attributes: Id, Address, Name.
  • Relationship: Composition (Strong ownership $\large{\blacksquare}$) with ParkingFloor.

2. Parking Floor (The Level Manager)

  • Role: Manages spots on a single level.
  • Attributes: Id, LevelNumber.
  • Relationship: Composition (Strong ownership $\large{\blacksquare}$) with ParkingSpot.

3. Parking Spot (The Parkable Unit)

  • Role: Tracks status and type of a single spot.
  • Attributes: Id, SpotType (Enum), IsAvailable: bool.
  • Relationship: Association with Vehicle (when occupied).

4. Vehicle & Ticket (The Session Record)

  • Vehicle Attributes: LicensePlate, Type (Enum).
  • Ticket Attributes: TicketId, EntryTime, ExitTime, Fee, ParkingSpotId.
  • Relationship: Association between Vehicle, Ticket, and ParkingSpot.

3. Database Schema Diagram

The schema (simplified for LLD) translates the Class Diagram into persistent storage tables, focusing on primary and foreign keys.

💾 Core Tables and Links

  • ParkingLot (PK: LotId) → ParkingFloor (PK: FloorId)
  • Link: ParkingFloor.FK_LotId points to ParkingLot.LotId (Defines which floor belongs to which lot).
  • ParkingFloor (PK: FloorId) → ParkingSpot (PK: SpotId)
  • Link: ParkingSpot.FK_FloorId points to ParkingFloor.FloorId (Defines which spot is on which floor).
  • Vehicle (PK: VehicleId) →Ticket (PK: TicketId)
  • Link: Ticket.FK_VehicleId points to Vehicle.VehicleId (Links the transaction to the car).
  • Ticket (PK: TicketId) → Payment (PK: PaymentId)
  • Link: Payment.FK_TicketId points to Ticket.TicketId (Links payment records back to the original session).

4. C# Implementation: Core Business Logic

To implement the core logic, we use Enums and a simplified Service layer that handles the business rules.

A. Enums for Clarity

public enum VehicleType { TwoWheeler, CompactCar, LargeCar, EV }
public enum SpotType { TwoWheeler, Compact, Large, EV }
public enum PaymentMode { Cash, Online, Card }
public enum PaymentStatus { Pending, Paid, Refunded }

B. Core Classes (Simplified)

// The Ticket DTO/Entity
public class Ticket
{
    public string TicketId { get; set; } = Guid.NewGuid().ToString().Substring(0, 6);
    public DateTime EntryTime { get; set; } = DateTime.Now;
    public DateTime? ExitTime { get; set; }
    public decimal Fee { get; set; }
    public string SpotId { get; set; }
    public string LicensePlate { get; set; }
}

public class ParkingSpot
{
    public string SpotId { get; set; }
    public SpotType Type { get; set; }
    public bool IsAvailable { get; set; } = true;
}

public class Vehicle
{
    public string LicensePlate { get; set; }
    public VehicleType Type { get; set; }
}

C. Business Logic: Fee Calculation & Spot Service

The Strategy Pattern (which we previously discussed!) would be ideal here to manage different fee models, but we'll use a simple method for demonstration.

// Simple Fee Calculation Service
public static class FeeCalculator
{
    private const decimal BaseRatePerHour = 5.00m;
    public static decimal CalculateFee(DateTime entryTime, DateTime exitTime, VehicleType type)
    {
        var duration = exitTime - entryTime;
        // Base fee is calculated hourly
        decimal hours = (decimal)duration.TotalHours;
        // Apply a multiplier based on vehicle size
        decimal multiplier = type switch
        {
            VehicleType.TwoWheeler => 1.0m,
            VehicleType.CompactCar => 1.5m,
            VehicleType.LargeCar => 2.0m,
            VehicleType.EV => 1.7m, // EVs might get a slight discount or premium
            _ => 1.0m
        };
        // Fee = BaseRate * Hours * Multiplier
        return Math.Round(BaseRatePerHour * hours * multiplier, 2);
    }
}

// Simplified Parking Spot Manager (Part of a larger ParkingFloor/Lot class)
public class ParkingSpotManager
{
    // Mock database or memory store
    private readonly List<ParkingSpot> _spots = new List<ParkingSpot>
    {
        new ParkingSpot { SpotId = "C101", Type = SpotType.Compact, IsAvailable = true },
        new ParkingSpot { SpotId = "B05", Type = SpotType.TwoWheeler, IsAvailable = true },
        // ... more spots
    };
    public string AssignSpot(VehicleType type)
    {
        // Simple assignment: Find the first available spot of the matching type
        SpotType requiredSpotType = type switch
        {
            VehicleType.TwoWheeler => SpotType.TwoWheeler,
            VehicleType.CompactCar or VehicleType.EV => SpotType.Compact,
            VehicleType.LargeCar => SpotType.Large,
            _ => SpotType.Compact
        };
        var spot = _spots.FirstOrDefault(s => s.Type == requiredSpotType && s.IsAvailable);
        if (spot != null)
        {
            spot.IsAvailable = false; // Occupy the spot
            return spot.SpotId;
        }
        return null; // Lot full or no spot available
    }
}

public class ParkingFloor
{
    public int LevelNumber { get; set; }
    // The spots belonging ONLY to this floor.
    private readonly Dictionary<string, ParkingSpot> _spots = new(); 

    // Constructor/Methods to initialize and manage spots
    public ParkingFloor(int level)
    {
        LevelNumber = level;
    }

    // Method to find and assign a spot only on this floor
    public string AssignSpot(VehicleType type)
    {
        // Implementation logic for finding spot on THIS level...
        // If found, return SpotId; otherwise, return null.
        return null; 
    }
}

// The overall ParkingLot would then contain a List<ParkingFloor>.

D. Entry/Exit Logic (The Service Layer)

public class ParkingService
{
    private readonly ParkingSpotManager _spotManager = new ParkingSpotManager();
    private readonly Dictionary<string, Ticket> _activeTickets = new Dictionary<string, Ticket>();
    public Ticket GenerateTicket(Vehicle vehicle, string operatorId)
    {
        string spotId = _spotManager.AssignSpot(vehicle.Type);
        if (spotId == null)
        {
            Console.WriteLine("Parking Lot Full.");
            return null;
        }
        var ticket = new Ticket
        {
            SpotId = spotId,
            LicensePlate = vehicle.LicensePlate,
            // OperatorId = operatorId (for full implementation)
        };
        _activeTickets.Add(ticket.TicketId, ticket);
        Console.WriteLine($"\n--- TICKET GENERATED ---");
        Console.WriteLine($"Ticket ID: {ticket.TicketId}, Spot: {ticket.SpotId}, Entry: {ticket.EntryTime}");
        return ticket;
    }

    public void ProcessExit(string ticketId, DateTime exitTime)
    {
        if (!_activeTickets.TryGetValue(ticketId, out var ticket))
        {
            Console.WriteLine($"Ticket {ticketId} not found or already processed.");
            return;
        }
        // 1. Calculate Fee
        var mockVehicleType = VehicleType.CompactCar; // Would retrieve from DB using ticket.LicensePlate
        ticket.ExitTime = exitTime;
        ticket.Fee = FeeCalculator.CalculateFee(ticket.EntryTime, exitTime, mockVehicleType);
        // 2. Process Payment (Simplification)
        Console.WriteLine($"\n--- EXIT PROCESSING ---");
        Console.WriteLine($"Vehicle: {ticket.LicensePlate} leaving spot {ticket.SpotId}.");
        Console.WriteLine($"Duration: {(ticket.ExitTime - ticket.EntryTime).TotalHours:F1} hours. Total Fee: {ticket.Fee:C}");
        // 3. Update Spot Availability
        // _spotManager.FreeSpot(ticket.SpotId); // In a real system
        _activeTickets.Remove(ticketId); // Mark as complete
    }
}

This LLD provides a clean, object-oriented foundation that can be easily extended to handle multi-level logic, different fee strategies, and various payment integrations.

✅ Conclusion: Mastering Parking Lot LLD

Designing the Parking Lot Management System is an excellent exercise in applied Low-Level Design (LLD). The key to success lies in clear object modeling and adherence to Object-Oriented Design (OOD) principles.

We successfully structured the system by:

  1. Defining Clear Entities: Establishing core classes like ParkingLot, ParkingFloor, ParkingSpot, Vehicle, and Ticket to manage the real-world components.
  2. Managing Relationships: Using Composition (e.g., ParkingLot owning ParkingFloors) and Association (e.g., a Ticket linking a Vehicle and ParkingSpot) to define structural integrity.
  3. Encapsulating Business Logic: Separating complex rules like fee calculation and spot assignment into dedicated, reusable components (like the FeeCalculator and ParkingSpotManager).

This modular and decoupled design ensures the system is scalable (easy to add new vehicle types or payment strategies) and maintainable, making it a robust solution suitable for a production environment and a strong demonstration of LLD competency in any technical interview.

If you found this guide helpful, don't forget to follow and subscribe to MpCodes for more content on AI, Cloud, and Software Design Insights.

Happy coding! 🎉

A message from our Founder

Hey, Sunil here. I wanted to take a moment to thank you for reading until the end and for being a part of this community.

Did you know that our team run these publications as a volunteer effort to over 3.5m monthly readers? We don't receive any funding, we do this to support the community. ❤️

If you want to show some love, please take a moment to follow me on LinkedIn, TikTok, Instagram. You can also subscribe to our weekly newsletter.

And before you go, don't forget to clap and follow the writer️!