System requirements
Functional:
- Parking Spot Reservation: Users should be able to reserve a parking spot for a specified time duration.
- Payment Processing: Users can pay for their reservation, either at the time of booking or upon arrival.
- Check-In and Check-Out: Users should be able to check in when they arrive and check out when they leave.
- Spot Availability Check: Users can check the availability of parking spots for a specific time.
- Cancellation Policy: Provide users the option to cancel their reservations, with policies on refunds.
- Notifications: Users should receive notifications for reminders and confirmations of their reservations.
Non-Functional:
- Scalability: The system should handle a large number of users and reservations, particularly during peak times.
- Availability: The system should be available 99.9% of the time.
- Consistency: Ensure that no double bookings of parking spots occur.
- Performance: Responses for availability checks and reservations should be processed within a reasonable time (e.g., less than 2 seconds).
- Security: User data and payment information must be securely handled to protect against breaches.
Capacity estimation
- Parking Lots:
- Number of countries: 10
- Average parking lots per country: 100
- Total parking lots: 10*100 = 1000
- Parking Spots:
- Average capacity per parking lot: 200 spots
- Total parking spots: 200*1000 = 200000
- Usage Patterns:
- Assumption: 80% of users use it for short-term parking and average occupancy is 4 hours.
- Assumption: 20% of users use it for long-term parking and average stay is 5 days.
- Reservation Requests:
- Average reservation requests per lot per day: 400
- Total reservation requests per day for the entire system: 1000*400 = 4*10^5
Parking lot will be a static data and most of the storage needs will be for the user and the reservation table. Lets say they roughly take around 500 bytes.
- storage needs for a day = 500*4*10^5
- Storage needs for month = 500 * 4*10^5*30 = 6*10^9 bytes = 6GB of data per month
API design
1. POST /parking Request Body: { "name": "Parking Lot Name", "address": "Parking Lot Address" }
2. GET /parking/{parkingLotId}/availability Returns: { "isAvailable": true }
3. POST /parking/{parkingLotId}/reservations Request Body: { "userId": 1, "parkingSpotId": 123, "reservationStartTime": "2024-08-06T10:00:00Z", "reservationEndTime": "2024-08-06T14:00:00Z", "amount": 20.00 } Returns: { "reservationId": 456, "status": "Reserved" }
4. POST /parking/{parkingLotId}/checkin Request Body: { "userId": 1, "reservationId": 456, "checkInStatus": "Confirmed" } Returns: { "status": "Checked In" }
5. PUT /parking/{parkingLotId}/parkingSpot/{parkingSpotId}/checkout Request Body: { "userId": 1, "checkOutTime": "2024-08-06T14:30:00Z", "amount": 20.00 }
Database design
-- Parking Lot Table
CREATE TABLE Parking_Lot ( id SERIAL PRIMARY KEY, name VARCHAR(50), address VARCHAR(256)); 500 bytes
-- Parking Spot Table
CREATE TABLE Parking_Spot ( id SERIAL PRIMARY KEY, available BOOLEAN, parking_lot_id INTEGER REFERENCES Parking_Lot(id), name VARCHAR(50));
100 bytes
-- User TableCREATE TABLE User ( id SERIAL PRIMARY KEY, name VARCHAR(50), email VARCHAR(50), phone_number VARCHAR(10));
100 bytes
-- Reservation TableCREATE TABLE Reservation ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES User(id), parking_spot_id INTEGER REFERENCES Parking_Spot(id), check_in_time TIMESTAMP, check_out_time TIMESTAMP, amount DECIMAL, payment_status VARCHAR(10), reservation_status VARCHAR(10));
200 bytes
High-level design
We will have both desktop and mobile clients and a load balancer sitting between the clients and the app servers.
We have SQL db which will have primary secondary kind of setup for handling the failover scenarios
Request flows
Client will send the request to the load balanced URL and the LB will route the requests to the application servers based on round robin algorithm to start with.
Application server will process the request and shall create a parking lot,parking spot and check availability. For the payment requests will be routed to the payment gateway. When the user checks in,checks out or pay the amount for which he used the parking lot there will be a notification sent from the notification service . When the user checks for availability then also notifcation service will update the user if there is no parking spot available .
Primary db will handle all the database queries
Detailed component design
We can cache the user details in a
I have used SQL db in a primary secondary kind of configuration. The reason for that it is simple to use and easy . We can also go for NOSQL db like dynamo which can be used if we want high scalability
We can partition the database based on the parking lot ID .This will help improve the query time faster.
We will be using microservices architecture applications where we will have a payment service
separated from the core services where we check the availability and do the reservations.
We will also have a separate notification service .
The benefit of using microservices architecture in place of monolithic is that we can scale the services independently .
We will be using 2 phase commits to handle payment transactions and need to handle compensating transactions when there is failure in the payment processing
We can think of load balancing strategies like we can either use round robin kind of strategy where requests are routed randomly or we can have like a latency or region based routing policy.
We will also have health check service which will keep checking the health of each component of the service . If in case our primary database fails the healthcheck service will send the trigger and we will failover the application to the secondary instances .
We don't have high storage requirements but if needed we can add a cache server like elasticache or memcache between our API servers and the db . But this is only if really required as cache servers are expensive
Trade offs/Tech choices
Explain any trade offs you have made and why you made certain tech choices...
I have used SQL db in a primary secondary kind of configuration .As the storage requirements are not huge and relational databases are easy to implement I have gone with relational database but we can use NoSQL database like a DynamoDB if we forsee that scalability and storage requirements are going to increase in the future
Failure scenarios/bottlenecks
Try to discuss as many failure scenarios/bottlenecks as possible.
- As we are generating a large number of notifications this could be a bottleneck
- Having a relational db might face issues when we want to scale the database
Future improvements
- We can include message broker like AMQ or SQS that will process the messages asynchronously.This will make the system performant as the response time will become faster
- We can think of making our database NoSQL that will make the system highly scalable as relational database has limits when it comes to scalability