10 countries × 100 lots = 1,000 lots; ~200 reservations/lot/day → 200k reservations/day (~2–3 writes/sec). Read:write ≈ 50:1 → ~115 reads/sec. Stay profile: 80% short-term (~4h), 20% long-term (~5 days). Storage: ~128 B/reservation → ~25.6 MB/day → ~280 GB over 2 years including growth and auxiliary data (payments, gate events).
endpoints for the UX
endpoints used by parking lot gates
there can also be endpoints used by administration to add a new parking lot, to manage prices, or manually manage reservations and payments
Different front-end apps will communicate to a single public API gateway in charge of rate limiting and load balancing. WE have three main functions: browsing spots, making reservations and making payments so we will have at least three back end services:
EXCLUDE USING gist (spot_id WITH =, window WITH &&) — the database itself refuses overlapping reservations for the same spot, and availability lookups use the interval index. This replaces both the cache and a separate locking layer: reservations and availability checks hit the same authoritative store.There will be a single database which if needed can be sharded by parking lot ids
SQL database because of the relations between parking_lot, parking_spots and reservations
Tables:
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
Starting with the parking-spots-service ("parking spots service"). The assumed scenario is that a user provides a time window in which they would like to park and we need to respond with a list of available parking spots. The user would then try and make a reservation for one spot for the requested time window.
In any case, the user will choose one or all of: parking lot, time window and we need to make a query to the DB to provide us with a list of spots available in the desired period. The user would then choose the spot/time window combination at which point we would make an entry in the reservations table with a status of "on hold", so no other user can try and book the same slot. After the user completes the payment the status would turn into "reserved".
If the payment doesn't happen within a specified timeout period, the record can be marked as timed-out. When the reservation is put on hold a timer starts, if it times out, the reservation will get a status timed-out and the front end polling mechanism will find it and can tell the user to start all over.
It is possible that a time window is put on hold or reserved by a different user in between the time a user sees it as available and initiates a reservation - in this case we can return an error and a new list of available time windows.
1) Double booking: handled by the DB; in case of overlap return error and offer alternative time slots.
2) Payment flow failures:
2.1) callback lost/delayed, a a hold waits forever - there must be a timeout after which the hold is released; the frontend polls so will find that the reservation was canceled; How will the frontend know why? the reservation will have acanceled status, and an error message
2.2) callback is retried (that's what providers do) - it has to be idenpotent, based on a payment id
2.3) user abandons payment - again a timeout after which the reservation entry is deleted.
3) if the payment provider is down - we have timeouts and a circuit breaker
4) database errors
4.1) shard goes down - sharding limits the damage; each has replicas and an in-built failover
4.2) retryable errors - retry with backoff and jitter
/payments/{id}/callback endpoint verifies the provider's signature before any state change, so a forged callback can't confirm an unpaid reservation.WHERE id = ? AND user_id = ?) to prevent IDOR: user A can't read, cancel, or pay for user B's reservation.