parking-lot

Problem statement

Develop a parking lot application where we should be able to perform the following operations:

  1. A Parking manager can create parking lots with desired parking slots in each parking lot.

  2. The user (Vehicle owner) can choose any parking lot & can park his vehicle in the nearest parking slot available in that lot (e.g. if parking slots are numbered 1,2,3....n, then we still start from 1 and pick the available one if it’s not in maintenance mode or already parked).

  3. When the user unparks, the response should be successful along with the parking fee that will be calculated as Rs. 10 * the Number of ceiled hours the vehicle has been parked. eg If parked for 1 hour 5 minutes, it will be 10 * 2 = 20

  4. Parking manager can view his current parking lot status (eg which cars are parked in which slots)

  5. The Parking Manager should be able to get the total number of vehicles parked on any day, total parking time and the total fee collected on that day.

  6. The parking manager can put any parking space/slot into maintenance mode and back to working state at any time.

Github Repository

Postman Workspace

Endpoints

1.Create A Parking Lot: POST /parking-lots/:id/slot

2.Park Vehicle, POST /parking-lots/:id/park 3.Unpark Vehicle, POST /parking-lots/:id/unpark

4.Get Parking Lot Status, GET /parking-lots/:id/status

5.Daily Report, GET /parking-lots/:id/report/:date (e.g., /parking-lots/123/report/2023-11-22)

Database Design

parking_lots               slots                               vehicles
--------------------------------------------------------------------------------
id                         id                                     id
uuid                       uuid                                   uuid
name                       parking_lot_id                   registration_number
slot_number                slot_id
is_available               parked_at
is_maintenance             unparked_at

Relationships

  • One-to-Many (parking_lots to slots): A parking lot can have many slots. Each slot belongs to a single parking lot (parking_lot_id foreign key in slots).

  • One-to-One (slots to vehicles): A slot can be occupied by one vehicle at a time (though it can be empty). A vehicle can only occupy one slot at a time (slot_id foreign key in vehicles).

Indexes

  • idx_parking_lots_name (UNIQUE INDEX on parking_lots.name)

  • idx_parking_lots_uuid (UNIQUE INDEX on parking_lots.uuid)

  • idx_slots_uuid (UNIQUE INDEX on slots.uuid)

  • idx_vehicles_uuid (UNIQUE INDEX on vehicles.uuid)

Key Insights

Core Design:

  • Architecture: Leveraged Domain-Driven Design principles for enhanced code maintainability and future extensibility.

Start from domain model(vehicle.go) -> repository(vehicle_repository.go) -> http handler(vehicle_handlers.go) -> main.go

  • Data Integrity and Isolation: Used database transaction level Serializable for maximum isolation on park and unpark. (Good for isolation, But deadlock might occur in rare scenario, we can prevent it by using context with timeout, so that request can timeout after few seconds/ms, and show it to logs).

  • Dependency Management: Prioritized the use of standard Go libraries for core functionalities, minimizing external dependencies. Chose the pgx driver for PostgreSQL connectivity, while maintaining a database/sql compatible interface.

  • Structured error handling with correct response codes. Logging with log/slog.

Security Considerations:

  • Exposed uuid in the client side to keep db column id private. (Alternative way: We can achieve through with DTO’s or GraphQL schema by only querying required fields).

  • Hide sensitive error messages on the client-side, providing generic feedback while internally logging detailed errors for debugging.

  • Wrapped database queries with placeholder like: $1 to prevent sql injection attack.

Nearest Slot Finding Logic

The user (Vehicle owner) can choose any parking lot & can park his vehicle in the nearest parking slot available in that lot (e.g. if parking slots are numbered 1,2,3....n, then we still start from 1 and pick the available one if it’s not in maintenance mode or already parked).

  1. First I checked if a vehicle same registration number already parked or not. Given 409 conflict error if parked.

  2. Then, If a slot is available and not in maintenance mode, I ordered slot_number by ID. Hence, we are finding nearest slot.

SELECT id, uuid FROM slots
WHERE parking_lot_id = $1
  AND is_available = true AND is_maintenance= false
ORDER BY slot_number
LIMIT 1;

In real world scenario If I had distance from each slot to slot, we would use:

Priority Queue (Min Heap) for Dynamic Environment (Frequent Updates)

  • How it Works:

    • Store slots in a min heap where the key is the distance from the entrance.

    • Maintain a separate data structure (e.g., an array or hash set) to track slot availability.

    • When a car enters:

      1. Pop the nearest slot from the min heap.

      2. Check if it's available. If not, repeat.

      3. Mark the slot as unavailable.

    • When a car exits:

      1. Mark the slot as available.

      2. Re-insert the slot into the min heap.

  • Pros: Efficiently retrieves the nearest available slot.

  • Cons: Requires building the heap initially and some overhead for updates.

Hybrid Approaches for Large Lots and Performance is Paramount

Spatial data structures like KD-trees, or, A fancy algorithm.

Last updated