Based on these assumptions, here’s the breakdown:
Define what APIs are expected from the system...
API Endpoint: /accounts
Method: POST
Body:
{
"email": ...
"password: ...
}
Response:
Appropriate Status Code
Body:
{
"userId": ...
}
API Endpoint: /parkingspots
Method: GET
Example Request showing filter parameters:
GET /parkingspots?parking-lot-id=123&start-at=2025-01-16T13:00:00&end-at=2025-01-16T15:00:00&vehicle-type=car
Response:
Appropriate Status Code
Body:
{
"availableSpots: [
{
"spotId": "A1",
"lotId": "123",
"vehicleType": "car",
"reserved": false
},
{
"spotId": "A2",
"lotId": "123",
"vehicleType": "car",
"reserved": false
},
]
}
API Endpoint: /reservations
Method: POST
Authorization Header: JWT
Body:
{
"lotId": 123,
"spotId": "A1",
"startAt": timestamp,
"endAt": timestamp,
"vehicleType": "car"
}
Response
Appropriate Status Code
Body
{
"reservationID": 56464
}
API Endpoint: /reservations
Method: POST
Authorization Header: JWT
Body:
{
"reservationId": 56464,
"paymentMethod": "creditCard",
"paymentToken": token
}
Response:
Appropriate Status Code
{
"transactionId": 123,
"status": "paid"
}
checkIn()
Input: reservation_id, authentication
Output: parking_session_id
checkOut()
Input: parking_session_id, authentication
Output: parking_session_id
cancelReservation()
Input: reservation_id, authentication
Output: cancellation_id
updateReservation()
Input: reservation_id, new_start_at, new_end_at, new_vehicle_type, new_parking_spot_id
Output: reservation_id
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
table: users
columns:
table: parking_lots
columns:
table parking_spots
columns:
table reservations
columns:
table cancllations
columns:
table: parking_sessions
columns:
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design. If you are unfamiliar with the tool, you can simply describe your design to the chat bot and ask it to generate a starter diagram for you to modify...
The high level design is shown in the diagram.
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
One thing I want to highlight is the notification service, which can be used to notify the user when a reserved spot becomes available. Whenever there is a cancellation or another user checks out of a particular spot, the reservation service can place an event on the message queue with the parking_spot_id. The notification service will read those events from the queue, and if there is a user waiting on that spot to become available, the notification service can trigger an appropriate notification to the user such as a push notification or SMS message. The notification service will need access to the read replica of the reservation database to check for users waiting on the spot, and will also need access to the user database to check for the user's notification settings.
I'd also like to highlight the request flow when a user is paying for a reservation. The payment service will be responsible for handling interactions with third party payment gateways, and ensuring any card information provided by the user is stored in a PCI compliant manner. If a payment fails or is later reversed, the payment service should also communicate with the reservation service to make sure any reservation that has been made is cancelled and the user notified of the failure.
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
Given the capacity estimates above, we should be able to concurrently handle reservations in a single reservation database. If the company were to significantly scale up to the point where a single reservation database was no longer sufficient, there would be a few options. The most straightforward would likely be to shard data into multiple reservation databases based on geographic region. Assuming the geographic regions are reasonably large, most users will likely not be booking parking reservations across multiple regions. However for use cases where we did want to present the user a history of all their reservations, and the user had parked in parking lots stored in separate databases, the reservation service would need to be prepared at the application layer to join together the appropriate data.
We could also scale the reservation database horizontally, and in that case we would need to select select appropriate coordination mechanisms among the instances of the reservation database, and choose between consistency or availability. If it is most important that a user never reserve a parking spot that is already booked by someone else, we should favor consistency over availability. If it is most important that a user never attempt to submit a reservation and receive an error message that the reservation could not be completed, we should favor availability.
Given the significant negative user experience of booking a spot that is already reserved, I would recommend favoring consistency. To ensure consistency across multiple instances of the reservation database, any writes creating new reservations need to be written to a sufficient number of databases in the cluster before the write is considered a success and the response is returned by the reservation service to the user. This consistency will come at the cost of increased latency.
The diagram shows separate databases for the authentication service and the payment/reservations services. This separation of the databases will allow each to be scaled independently, and to be optimized for different read/write patterns. The user database can also follow more strict security policies. However, this separation comes with added complexity that may not be warranted at the estimated capacity. By separating this data, the application layer will have additional work to do to ensure appropriate user ids are passed through to the payment/reservation services after user authentication occurs, and the application layer may need to handle joining together data across the separate databases.
Try to discuss as many failure scenarios/bottlenecks as possible.
Any of the items shown in the diagram from the API Gateway down could be a point of failure. To ensure appropriate uptime, we would need to select an appropriate strategy where either a backup API Gateway can be promoted and traffic routed to the promoted API Gateway or where there are multiple active API Gateways at a time and traffic is routed between them.
For each of the services, multiple instances can run at a time so that no one service is a single point of failure. A solution such as Kubernetes can manage ensuring an appropriate number of instances of each service are running at any given time, or the API Gateway would need to be able to discover the instances of each service and be able to direct traffic among the instances appropriately.
For each of the databases, we should have replica databases ready to be promoted if the active database goes down, and appropriate backups kept so that data is not lost on failure of a database instance.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?