Requirements
Functional Requirements:
End-to-End Reserve Journey: 1. Uあser searches → 2. System holds a spot (Status: PENDING) → 3. User pays → 4. Payment Gateway sends callback → 5. System confirms reservation (Status: CONFIRMED).
Payment Handoff & Callback: The system hands off to a 3rd-party (e.g., Stripe) with a unique SessionID. Once paid, Stripe hits our Webhook endpoint. This ensures we don't rely on the client-side redirect for critical state changes.
Non-Functional Requirements:
Define the system constraints to ensure stability and performance.
- High Availability: The system must be operational 24/7 (99.99% uptime). A downtime means cars cannot enter/exit, leading to physical congestion.
- Scalability: Must support thousands of parking lots and millions of daily transactions.
- Consistency: Strong consistency is required for payments and spot allocation to prevent double-booking.
- Low Latency: Gate entry/exit validation and spot availability checks must happen in real-time (<200ms).
API Design
| Method | Endpoint | Headers | Description |
POST | /v1/reservations | Idempotency-Key | Reserves a spot. Required key to prevent duplicate bookings on retries. |
GET | /v1/reservations/{id} | - | Poll for reservation status. |
POST | /v1/payments/webhook | X-Signature |
Secure callback from payment provider to finalize reservation.
High-Level Design
- API Gateway: Handles Rate Limiting per
LotIDto mitigate Hot-lot surge. - Message Queue (Kafka): Used to decouple the Payment Webhook from the Reservation Service. This handles high bursts of payment confirmations.
- Consistency: Use a Relational DB with
REPEATABLE READisolation to handle overlapping intervals correctly during the "Check Availability" phase.
Detailed Component Design
Handling Hot-lot Surge & Concurrency
To handle high traffic for a specific popular lot ("Hot-lot"), we implement Distributed Rate Limiting at the Gateway level and use Redis distributed locks with a short TTL for the specific LotID_TimeWindow key during the booking process.
Reservation Hold & Expiration (The "Hold" Problem)
When a user starts a booking, we create a temporary hold for 10 minutes.
- Potential Issue: Hold expires before payment finalize.
- Solution: The
Payment Webhookcheck if the hold is still valid. If expired, it triggers an automatic refund process via thePayment Service.
Idempotency & Retries
To ensure a retry of a POST /reservations call doesn't create two bookings:
- The client sends a UUID as an
Idempotency-Key. - The server stores this key in Redis for 24 hours. If a duplicate key arrives, the server returns the previous successful response without re-processing.
Stale Cache & Overlapping Intervals
- Stale Cache: We use a Write-through Cache for spot availability. Any DB update invalidates the Redis entry to ensure users don't see "Available" for a spot that was just booked.
- Intervals: We use SQL queries with
NOT EXSITSand interval overlap logic: - (StartA<EndB) AND (EndA>StartB)
- This ensures no two reservations for the same spot overlap in time.
5. Non-Functional Requirements (NFR Strategy)
- High Availability: Multi-Region active-passive setup with failover via Route 53.
- Scalability: Horizontal Pod Autoscaling (HPA) for microservices based on CPU/Request count.
- Low Latency: Read-replicas for lot metadata and Redis for real-time inventory checks.
- Consistency: Transactional Outbox Pattern to ensure the DB update and Message Queue emission happen atomically.