Requirements
Functional Requirements:
I would divide the system into User API, Reservation Service, Payment Service, Gate/Operations Service, a Scheduler for no-shows and cleanup, a read cache, and a relational database as the source of truth.
Once divided, a login system using email and password must be implemented to allow verification through the database.
A reservation system should be built based on time slots and the internal availability of the parking lot; availability must also be controlled through the system that manages entries and exits.
A payment system should be integrated via API to ensure security, or alternatively, once inside the parking area, users can connect via their phone to a payment device.
In the case of gates, it is useful to have a local edge controller to manage entry/exit, for example via an IoT device with a sensor that allows unlocking when a phone is brought close.
Non-Functional Requirements:
The system must ensure that every state (available spots, reservations, payments, entries/exits) is consistent and up to date.
No vehicle should be assigned to more than one parking spot within the same time window.
Data must remain consistent across the main database, cache, and frontend applications.
The system must remain operational even in case of minor failures (e.g., one DB server, one API gateway, one gate controller).
Scalability:
• Support up to X requests per second during peak traffic.
• Horizontal scaling of APIs and workers via Kubernetes or cloud auto-scaling.
• Sharding by parking lot and/or geographic area.
Performance:
• Availability check / price estimate: < 1–2 s.
• Reservation confirmation: < 2 s.
• Maximum acceptable response time at peak: < 5–8 s.
Security:
• Sensitive data encrypted in transit and (if possible) at rest.
• Access control: each user can only view their own reservations.
• Basic protection against injection, overflow, and brute-force attacks.
API Design
Define the APIs expected from the system. This is your chance to analyze and define the read and write paths so that you can come up with the high-level design...
High-Level Design
The system follows a client-server architecture with microservices and a relational database as the source of truth, with multiple separate components communicating via REST/HTTP APIs or events.
User (Driver/Client): Mobile or web app that allows users to search availability, make reservations, pay, and view status.
API Gateway: Single entry point for all requests, handling authentication, routing, and rate limiting.
Backend Services:
• User Service: Manages registration, login, profile, and vehicle data.
• Reservation Service: Core reservation logic, including check-in/check-out, no-shows, and holds.
• Payment Service: Integrates with external payment gateways (e.g., Stripe).
• Gate/Operations Service: Receives events from gates (arrival/departure) and updates system state.
• Scheduler / No-show Service: Periodic job that cleans expired holds and handles no-shows.
Cache: Redis or similar, used for:
• Recent parking lot availability
• Read-optimized reservation states
Database: RDBMS (PostgreSQL/MySQL) storing:
User, Vehicle, ParkingLot, ParkingSpot, Reservation, PaymentTransaction, GateEvent.
Event Bus / Queue (optional, for advanced architecture):
Used to decouple payments, gate operations, and notifications (e.g., Kafka, SQS, RabbitMQ).
Flow:
The user opens the client → API Gateway → Reservation Service to:
• GET /availability → checks availability (first from cache, then confirmed via DB).
• POST /holds → creates a temporary hold with expiration (e.g., 10 minutes).
The Reservation Service calls the Payment Service to:
• Initiate transaction → redirect to payment gateway → callback when payment is completed.
Payment Service:
• Records success or failure and notifies the Reservation Service (synchronously or via event bus).
Reservation Service:
• Finalizes the reservation atomically in the DB (ACID transaction):
• Updates status → CONFIRMED
• Consumes the hold
• Optionally locks the slot for the time interval
At the Gate:
The Gate/Operations Service handles:
• POST /check-in → registers arrival, marks CHECKED_IN, opens gate if reservation is valid.
• POST /check-out → closes session, calculates any extra charges, marks CHECKED_OUT.
No-show / Cleanup:
The Scheduler scans all reservations in PENDING or CONFIRMED state without CHECKED_IN within X minutes from start_ts → marks them as NO_SHOW and frees the slot.
Detailed Component Design
1. Reservation Service
(Manages holds, reservations, check-in/check-out, no-shows)
How it Works
• Receives requests from the API Gateway (e.g., /availability , /holds , /reservations/finalize , /check-in , /check-out ).
• Interacts with:
• RDBMS to update reservations , payments , gate_events .
• Cache for fast reads of availability and states.
• Follows a state machine for reservations: PENDING_HOLD → PAYMENT_PENDING → CONFIRMED → CHECKED_IN → CHECKED_OUT , with branches for EXPIRED , CANCELLED , NO_SHOW , PAYMENT_FAILED .
Algorithms and Data Structures
• Interval overlap check: For a specific spot, the service verifies if new_start < existing_end and new_end > existing_start for any active reservation or hold in the same slot.
• Bitmap for coarse capacity: Discretizes time into slots (e.g., 5–15 minutes) and uses a bitmap to quickly track free/occupied slots per lot, avoiding latches on thousands of rows.
• Lock/optimistic concurrency: Uses row-level locks on the spot or optimistic versioning ( version / last_modified ) to prevent double-booking the same spot_id in the same window.
Scalability and Capacity
• Sharding by parking_lot_id : Each Reservation Service instance handles only a subset of lots, isolating traffic.
• Read-side caching: /availability queries read from Redis, while commits write only to DB.
• Async for long operations: Some logic (e.g., no-show rechecks, notifications) can be pushed to a queue (Kafka/SQS) to avoid blocking the API.
• Capacity: With a well-indexed RDBMS and sharding, the service can handle hundreds of thousands of reservations/hour, limited more by the DB than the logic.
Trade-offs
• Strong consistency vs. latency: Strict transactions (ACID, row locks) ensure strong consistency but increase peak latency; loosening (e.g., optimistic locks, retries) improves throughput but raises retry rates.
• Bitmap vs. interval tree: Bitmap is fast for “total capacity per slot” checks but less precise for arbitrary reservations; interval trees are more accurate but costlier in memory and CPU.
RDBMS + Slot Allocation Logic
(Source of truth: tables, indexes, structures, allocation policies)
Relevant Logical Schema
• parking_lot : lot_id , capacity , geo , timezone .
• parking_spot : spot_id , lot_id , type , level , status .
• reservation : res_id , spot_id , start_ts , end_ts , status , hold_expires_at .
• spot_hold (optional): hold_id , spot_id , start_ts , end_ts , expires_at .
Allocation Algorithms / Strategies
• First-available: Scans free spots in the interval and picks the first; simple but can lead to uneven filling.
• Nearest to exit / random fair: Filters free spots, then sorts by distance from exit; more complex but improves UX.
• Priority-based: Reserves better spots (nearby, covered, EV) for VIP users or special categories via priority or user_type .
Indexes and Performance
• Primary indexes: (spot_id, start_ts, end_ts) for intervals.
• Index on parking_lot_id, status for fast lot queries.
• Bitmap / aggregates in cache for coarse capacity (e.g., lots with 5-minute slot bitmaps) to avoid COUNT(*) on millions of rows.
Scalability
• DB partitioning by parking_lot_id (sharding) so each lot is self-contained in its shard.
• Read replicas: For reporting and admin UI, use read-only replicas to offload the writer.
• Historical archiving: Move old reservation s to a separate store (e.g., data warehouse) to keep the primary DB lean.
Trade-offs
• RDBMS vs. NoSQL for core: RDBMS provides strong consistency and transactions, ideal for payments and reservations; NoSQL offers better scalability but complicates double-booking prevention and allocation policies.
• Slot granularity: Fine slots (5 minutes) grow bitmap memory; coarse slots (15–30 minutes) use less memory but increase logical collisions for arbitrary windows.
Gate/Operations Service
(Manages physical check-in/check-out, events, gates, no-shows, cleaning)
How it Works
• Receives events from physical gates (ANPR, RFID, sensors, button, app):
• vehicle_arrived / check-in
• vehicle_departed / check-out
• Validates:
• Existence of a reservation
• Match between license plate and reservation.vehicle_id
• CONFIRMED / CHECKED_IN status
• Any rules (e.g., stay time, fees, EV, etc.).
• Updates:
• reservation.status → CHECKED_IN / CHECKED_OUT
• gate_event (timestamp, gate_id, plate, res_id, event_type).
Algorithms and Event Handling
• Plate ↔ reservation matching: Searches DB by plate or res_id with dedicated index; fallback to start_ts / end_ts interval search.
• Event-driven cleanup:
• Schedules periodic jobs:
• clean_expired_holds()
• mark_no_shows() (confirmed reservations never checked in after X minutes from start_ts ).
• Some events trigger background actions (e.g., notifications, logging, extra charge calculations).
Scalability
• Stateless component: Multiple Gate/Operations Service instances register events, written to DB or queued.
• Local edge node: A local controller can handle entries/exits offline, storing events locally and syncing later with the cloud.
• Load reduction: Non-critical events (e.g., stats, analytics) go to a queue/event bus instead of immediate DB writes.
Trade-offs
• Immediate consistency vs. offline: Offline gate operation creates inconsistency windows vs. central DB, but the system must reconcile on reconnection (e.g., validity windows, queue reconciliation).
• Write redundancy: Immediate DB writes for all gate_event s bottleneck the DB; queuing increases complexity but improves scalability.