Functional Requirements:
Non-Functional Requirements:
lot_id to distribute the database load.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...
Lots service - handles lots
GET /api/v1/lots
Response {
"requestedAt":"yyyy-mm-dd HH-mm-ss:ss",
"startTime":""yyyy-mm-dd HH-mm-ss:ss",
"endTime":"yyyy-mm-dd HH-mm-ss:ss",
"available": []
}
Reservation service - handles reserving
POST /api/v1/reserve
Body {
"requestedAt":"yyyy-mm-dd HH-mm-ss:ss",
"startTime":""yyyy-mm-dd HH-mm-ss:ss",
"endTime":"yyyy-mm-dd HH-mm-ss:ss",
"lot":"", // Unique identifier of the lot
"vehicle":"" // Unique identifier of the vehicle
}
Response {
"statusCode":200,
"description":"Reservation successful"
}
Gate service - handles checking in and out
POST /api/v1/gate/check-in
Body {
"requestedAt":"yyyy-mm-dd HH-mm-ss:ss",
"vehicle":"" // Unique identifier of the vehicle
}
Response {
"statusCode":200,
"description":"Authorised to enter"
}
POST /api/v1/gate/check-out
Body {
"requestedAt":"yyyy-mm-dd HH-mm-ss:ss",
"vehicle":"" // Unique identifier of the vehicle
}
Response {
"statusCode":200,
"description":"Authorised to enter"
}
Parking service - handles parking of a lot
POST /api/v1/park
Body {
"requestedAt":"yyyy-mm-dd HH-mm-ss:ss",
"vehicle":"" // Unique identifier of the vehicle,
"lot":"", // Unique identifier of the lot
}
Response {
"statusCode":200,
"description":"Parked"
}
Billing service - handles billing
POST /api/v1/billing
Body {
"vehicle":"" // Unique identifier of the vehicle,
"lot":"", // Unique identifier of the lot
"startTime":""yyyy-mm-dd HH-mm-ss:ss",
"endTime":"yyyy-mm-dd HH-mm-ss:ss"
}
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
API Gateway This acts as the single entry point for mobile applications and physical parking gate sensors. It manages authentication, rate limiting, and routing incoming requests to the correct internal microservice.
Compute Layer The business logic is split into stateless microservices (Lots, Reservation, Gate, Parking, and Billing). Deploying these on a containerized orchestration platform like Kubernetes allows you to scale them independently. For instance, you can spin up 50 instances of the Gate service to handle morning rush hour traffic while leaving the Billing service at a normal capacity.
Caching Layer A Redis cluster acts as an in-memory data store. This is strictly required to meet your sub-200 millisecond latency requirement for the physical gate operations.
Database Tier A relational database like PostgreSQL serves as the single source of truth. It is horizontally partitioned using the lot_id to handle the 5,000 global locations and the 1,000 write transactions per second.
Message Queue An asynchronous broker handles delayed background tasks. This prevents the main API threads from getting blocked during payment processing and manages the no-show timeout logic.
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
1. Managing Double Bookings (Strong Consistency) When the POST /api/v1/reserve endpoint is called, the Reservation service must guarantee no other user can claim the spot. The service opens a database transaction and uses pessimistic locking by executing a SELECT FOR UPDATE query on the specific parking spot row. This locks the row at the database level. If a second user attempts to book the same spot a fraction of a second later, their request is forced to wait until the first user completes their payment and the transaction commits.
2. Gate Check-In (Low Latency) Querying a globally distributed relational database will likely exceed your 200-millisecond limit. To solve this, the read path is optimized using the cache. When a reservation is successfully created, the system immediately writes the vehicle ID and the endTime into Redis. When a car pulls up to the physical gate, the Gate service only queries Redis. Memory lookups take single-digit milliseconds. The service immediately returns the 200 status code to open the gate and sends an asynchronous event to update the main database in the background.
3. The 15-Minute No-Show Logic Handling exact time delays requires an event-driven approach. When a reservation is confirmed, the Reservation service drops a token into a delayed message queue scheduled for exactly 15 minutes in the future. Once 15 minutes pass, a background worker consumes the message and checks the main database. If the vehicle has not checked in at the gate, the worker marks the reservation as a "no-show", releases the row lock, frees the spot in the Redis cache, and triggers the Billing service to charge the penalty.