System requirements


Functional:

List functional requirements for the system (Ask the chat bot for hints if stuck.)...


  1. Guaranteed Parking Spot: A user can enter the garage and be guaranteed a parking spot.
  2. Entry Restrictions: A user won't be able to enter if there is no spot left.
  3. Payment Processing: A user can pay with their credit card.
  4. Parking Time Limitation: A user can only be parked in the facility for a limited amount of time.
  5. User Account Management: Users can create accounts to manage their information and transactions.
  6. Spot Reservations: Users can reserve parking spots in advance.
  7. Real-Time Availability: Users can view real-time availability of parking spots prior to entry.
  8. Payment History: Users can see a history of their payments and transactions.
  9. Entry/Exit Logging: The system maintains a log of entry and exit times for all vehicles.
  10. Notifications: Users receive notifications for upcoming reservations or expiration on their spot.




Non-Functional:

List non-functional requirements for the system...


  1. High Availability: The system must ensure minimal downtime and be readily accessible to users at all times, especially during peak hours.
  2. High Consistency: All users should have access to the same data, particularly for payment and spot availability, to prevent confusion and double booking.
  3. Performance: The system must provide a performant real-time reservation map, with quick payment processing to avoid long queues and maintain user satisfaction.


Capacity estimation

Estimate the scale of the system you are going to design...


  • Total Parking Spots: 450 spots
  • Daily Cars Parked: Approximately 800 cars per day
  • Daily Active Users (DAU): Approximately 230 active users



API design

Define what APIs are expected from the system...



  1. User Management
    • POST /user: Creates a new user account.
  2. Parking Spot Management
    • GET /spots?car_size=small: Retrieves available parking spots based on query parameters (e.g., car size could be passed as a query string instead).
    • POST /reserve_spot: Allows users to reserve a spot.
  3. Reserved Spots Management
    • GET /{account_id}/get_spots: Retrieves the spots reserved by a specific user (account).
  4. Payment Management
    • GET /{account_id}/payments: Retrieves previous payments made by the specific user.


Database design

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...






High-level design

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...


  1. Users
    • Attributes:
      • id (Primary Key): Unique identifier for each user
      • name: User's name
      • email: User's email (unique)
      • password: User's hashed password
      • created_at: Timestamp for when the account was created
  2. Spots
    • Attributes:
      • id (Primary Key): Unique identifier for each parking spot
      • location: Physical location of the spot (e.g., Level 1, Space A1)
      • size: Size of the spot (e.g., small, medium, large)
      • status: Current status of the spot (e.g., available, reserved)
      • created_at: Timestamp for when the spot was added
  3. Reservations
    • Attributes:
      • id (Primary Key): Unique identifier for each reservation
      • user_id (Foreign Key): References Users.id
      • spot_id (Foreign Key): References Spots.id
      • reserved_at: Timestamp for when the spot was reserved
      • expires_at: Timestamp for when the reservation expires
  4. Payments
    • Attributes:
      • id (Primary Key): Unique identifier for each payment
      • user_id (Foreign Key): References Users.id
      • amount: Amount paid
      • payment_date: Timestamp for when the payment was made
      • status: Payment status (e.g., completed, pending, failed)

Relationships:

  • Users to Reservations: One user can have multiple reservations (1 to many).
  • Users to Payments: One user can make multiple payments (1 to many).
  • Spots to Reservations: Each reservation corresponds to one parking spot, but one parking spot can be reserved multiple times over time (1 to many).


Request flows

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...



  1. User Requests Available Spots:
    • The user sends a request to the API to fetch available parking spots.
  2. Fetch and Return Available Spots:
    • The request hits your spot management service, which queries the database for available spots and returns this data to the user.
  3. User Reserves a Spot:
    • The user selects a spot and sends a reservation request to the API.
  4. Spot Reservation and Payment:
    • The reservation service processes this request, creates a new reservation entry in the database, and confirms the reservation back to the user.
    • The user then initiates a payment request, which is processed by the payment service.
  5. Record Entry and Exit:
    • When the user enters the parking lot, the system logs their entry time.
    • Upon exiting, the system logs the exit time and updates the spot's status back to available.



Detailed component design

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...


Concurrency Control in Reservations

  1. Resource Locking:
    • When a user initiates a reservation by clicking the "reserve" button, you would start a transaction that locks the resources related to that parking spot in the database.
    • This ensures that while one user is attempting to reserve the spot, no other user can reserve the same spot until the transaction is completed (either by confirming or canceling).
  2. Reservation Timer:
    • Setting a timer of, say, 5 minutes for the reservation is a practical way to allow users to complete their reservation process.
    • If the user does not complete the payment process within this time frame, the reservation should expire.
  3. Expiration Logic:
    • You can add an expires_at column in your Reservations table to store the time until which the reservation is valid.
    • When checking if a spot is available, you would query the database for spots that are either not reserved or have an expired reservation (where the expires_at is less than the current timestamp).
  4. Spot Status Update:
    • Once the reservation is confirmed and the payment is processed, you would mark the spot as reserved in the Spots table. This entry should also link to the Reservations table to maintain the relationship.
    • If the reservation is not confirmed within the allotted time, you should release the spot and update the Spots table back to available.

Sample Flow for Reservation Management

Here's how the flow could look during the reservation process:

  1. User Clicks to Reserve:
    • Begin a transaction.
    • Lock the entry for the selected spot in the database.
    • Set the expires_at time for 5 minutes in the Reservations table.
  2. Check Payment Completion:
    • If payment is completed within the 5-minute window:
      • Mark the spot as reserved.
      • Finalize the transaction.
    • If payment is not completed within the window:
      • Rollback the transaction.
      • Release the lock.
      • Update the spot's status back to available.


Using a pub/sub model combined with WebSockets for real-time updates is an excellent approach for maintaining an updated view of available parking spots on your users' maps. This ensures that users receive immediate feedback about any changes without needing to refresh the page manually.

How the Pub/Sub Model and WebSockets Work Together

  1. Real-time Notifications:
    • When a parking spot's status changes (e.g., a spot becomes reserved or available), your backend service publishes an event notifying all connected clients (users) about the change.
  2. WebSocket Connections:
    • Each client (user) maintains an open WebSocket connection to the server. This allows for bidirectional communication, whereby the server can push updates to the client in real-time.
  3. Event Subscription:
    • Clients subscribe to specific events related to parking spots. For example, a client may subscribe to updates on available spots or their own reservation statuses.
  4. Updating the Client Map:
    • Upon receiving an event through the WebSocket connection, the client-side application can update the visual representation of the parking map dynamically, showing available spots or reserved spots immediately.



Trade offs/Tech choices

Explain any trade offs you have made and why you made certain tech choices...


Benefits of Using MySQL

  1. Structured Data: MySQL is well-suited for structured data, allowing for predefined schemas, which can enforce data integrity through constraints like primary and foreign keys.
  2. Transaction Support: MySQL supports ACID transactions, which guarantee that your data remains consistent even in cases of concurrent access or system failures. This is essential for operations involving payment processing and reservations.
  3. Strong Community and Ecosystem: MySQL has a large community and a mature ecosystem, meaning there's abundant documentation, libraries, and tools available to streamline development.
  4. Query Capabilities: MySQL provides powerful SQL query capabilities, making it easy to perform complex joins and aggregates that can be beneficial for analyzing user behavior or optimizing space usage.
  5. Scalability Options: While it is traditionally thought of as a relational database, the newer versions of MySQL provide options for scaling through sharding or replication when your system grows.

Trade-offs and Limitations

  1. Vertical Scalability: MySQL typically scales vertically (i.e., adding resources to a single server). This can lead to limitations as it becomes harder to scale beyond a single server without significant architectural changes.
  2. Complexity with Relationships: While MySQL handles relationships well, having many associated tables and complex joins can lead to performance issues, especially with very large datasets or high concurrency loads.
  3. Real-time Features: MySQL isn't inherently designed for real-time analytics or event-driven architectures. For real-time functionalities (like the pub/sub model with WebSockets), integrating with other databases or systems (like Redis for caching or a message broker) might be necessary.
  4. Additional Overhead: Managing transactions and maintaining strong consistency comes with some overhead. In high-concurrency environments, this can lead to performance bottlenecks.
  5. Read vs. Write Performance: In write-heavy scenarios (e.g., logging user actions, frequent updates), MySQL could become a bottleneck unless carefully optimized. Creating indexes can help but might degrade performance on updates.



Failure scenarios/bottlenecks

Try to discuss as many failure scenarios/bottlenecks as possible.


Failure Scenarios

  1. Database Failure:
    • Description: This could involve issues like a database server crash, data corruption, or network issues preventing access to the database.
  2. Server Failure:
    • Description: This involves crashes or downtime of the application server(s) hosting your API.
  3. Payment API Failure:
    • Description: This could occur due to external payment service outages, network issues, or integration problems.




Future improvements

What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?


Failure Scenarios

  1. Database Failure:
    • Description: This could involve issues like a database server crash, data corruption, or network issues preventing access to the database.
    • Mitigation Strategies:
      • Redundancy: Use replication (master/slave) setups to ensure that you have a standby database that can take over in case of failure.
      • Backup and Recovery: Implement regular backups to allow recovery of the database in case of corruption or data loss.
      • Monitoring and Alerts: Use monitoring tools to track database health and set up alerts for anomalous behavior.
  2. Server Failure:
    • Description: This involves crashes or downtime of the application server(s) hosting your API.
    • Mitigation Strategies:
      • Load Balancing: Distribute incoming requests across multiple application servers to prevent a single point of failure.
      • Health Checks: Implement automated health checks to detect failed instances and routing traffic away from them.
      • Containerization: Use tools like Docker and orchestration platforms (e.g., Kubernetes) to manage application deployment and recovery efficiently.
  3. Payment API Failure:
    • Description: This could occur due to external payment service outages, network issues, or integration problems.
    • Mitigation Strategies:
      • Retries/Timeouts: Implement retry logic for transient failures with exponential backoff. Set appropriate timeouts to prevent hanging requests.
      • Graceful Fallbacks: If possible, provide alternate payment methods to users if the primary service is unavailable.
      • Logging and Alerts: Log the failures and set up notifications for quick diagnosis and resolution.

Bottleneck Considerations

  1. Database Scaling:
    • Problem: As you correctly noted, vertical scaling might lead to bottlenecks in high-concurrency situations, especially with heavy write operations.
    • Mitigation:
      • Sharding: If needed, consider database sharding to distribute the load across multiple databases.
      • Read Replicas: Use read replicas to offload read operations from the primary database, improving performance for read-heavy workloads.
      • Connection Pooling: Use connection pooling to manage database connections efficiently, reducing the overhead of establishing new connections.
  2. API Server Load:
    • Problem: High traffic on the server might slow down response times for users or cause service outages.
    • Mitigation:
      • Caching: Implement caching strategies (e.g., Redis or in-memory caches) to reduce load on your APIs for frequently requested data.
      • Microservices Architecture: Consider breaking the monolithic structure into smaller, more manageable services that can independently scale.
  3. WebSocket Connections:
    • Problem: As more users connect via WebSockets, maintaining these connections could exhaust server resources.
    • Mitigation:
      • Connection Limits: Implement limits on the maximum number of simultaneous WebSocket connections per instance, with proper scaling of WebSocket servers.
      • Clustered WebSocket Servers: Use clustering strategies to distribute WebSocket connections across multiple servers.