Requirements
Functional Requirements:
- Spot reservation — Users can search and reserve available spots by vehicle type, time window, and location.
- Payment processing — Pre-payment at reservation time; refund/credit logic for early exits and no-shows.
- Vehicle entry/parking — Gate check-in via QR code, license plate recognition (LPR), or reservation ID.
- Early departure — System logs actual exit time and triggers partial refund processing.
- Gate check-in/out — Physical barrier integration; entry and exit events log timestamps.
- No-show handling — Spots are automatically released after a grace period (e.g., 15 minutes post-start time) and the user is charged a no-show fee.
Non-Functional Requirements:
- Availability: 99.9% uptime — gates must never get stuck due to a backend outage (local fallback cache at gate hardware).
- Latency: Gate open/close decisions under 500ms; reservation search under 200ms.
- Scalability: Handle thousands of concurrent reservations across multiple lots.
- Consistency: Spot allocation must be strictly consistent — no double-booking (distributed lock or optimistic locking with DB transactions).
- Security: PCI-DSS compliance for payments; encrypted license plate data at rest.
- Observability: Real-time occupancy dashboards; alerting on gate failures or payment service degradation.
API Design
SPOT DISCOVERY
GET /spots/available
?lot_id, vehicle_type, start_time, end_time — returns available spots with pricing
GET /spots/{spot_id}
Spot details, current status (available/reserved/occupied)
RESERVATIONS
POST /reservations
Body: {spot_id, user_id, vehicle_id, start_time, end_time} — creates reservation, locks spot
GET /reservations/{reservation_id}
Fetch reservation details and current state
PUT /reservations/{reservation_id}/cancel
Cancel before start_time; triggers refund eligibility check
PAYMENTS
POST /payments
Body: {reservation_id, payment_method_token} — charges user, returns payment_id
POST /payments/{payment_id}/refund
Body: {reason, amount} — partial/full refund on early exit or no-show
GATE CONTROL
POST /gate/check-in
Body: {reservation_id | license_plate | qr_code, gate_id} — validates entry, opens gate
POST /gate/check-out
Body: {reservation_id | license_plate, gate_id} — logs exit time, triggers billing reconciliation
VEHICLES & USERS
POST /users/{user_id}/vehicles
Register vehicle (plate, type: compact/SUV/motorcycle/EV)
GET /users/{user_id}/reservations
Reservation history with statuses
High-Level Design
The system is built as a set of loosely coupled microservices sitting behind an API Gateway that handles authentication, rate limiting, and routing. The core services — Reservation, Payment, Spot Management, Gate, and Notification — each own their own database, communicating asynchronously via a Kafka event bus for non-critical flows and synchronously via direct HTTP/gRPC calls where latency matters (gate validation, payment at checkout). Gate hardware runs a lightweight edge agent with a local cache so physical barriers never depend on backend availability. A Redis layer sits in front of spot availability to serve high-read-volume queries without hitting the database.
Detailed Component Design
Spot Management Service maintains real-time availability in Redis as a sorted set keyed by lot:floor:spot_id with values encoding the occupied time ranges. This allows O(log n) range queries to find free windows. The canonical source of truth is PostgreSQL; Redis is a write-through cache.
No-show handler is a scheduled job (cron every 5 minutes) that queries all reservations with status=CONFIRMED and start_time + grace_period < NOW(). For each match it fires a no_show.triggered Kafka event, which the Reservation Service consumes to update the status and the Payment Service consumes to charge the no-show fee (typically a percentage of the booking). The spot is released back into availability atomically.
Early departure — on gate/check-out, the Gate Service logs the actual exit timestamp. It then computes the unused duration and emits a checkout.early event. The Payment Service calculates the refund amount based on the lot's early-exit policy (e.g. prorated minus a minimum fee) and issues a partial refund via the payment provider's API.
Gate hardware runs a lightweight edge agent that syncs a local SQLite snapshot of all upcoming reservations (next 24h) every few minutes via the Gate Service. This ensures the gate can validate and open in under 200ms even during a network partition. All events are buffered locally and flushed when connectivity resumes.
Vehicle type accommodation — spots are tagged with types: compact, standard, SUV, motorcycle, and EV (which also carry a charger flag). The search API filters availability by vehicle type and the frontend surfaces only compatible spots. EV spots also expose charger status as a live field pulled from the charger management system.
Horizontal scaling
Each microservice is stateless and can be scaled independently behind a load balancer — you add Payment Service instances during peak hours without touching the Gate Service. Kafka partitions are the unit of parallelism on the consumer side; scaling a consumer group is just adding more instances, and Kafka rebalances partition ownership automatically. The main stateful bottlenecks are Redis and PostgreSQL — Redis scales horizontally via clustering and consistent hashing across nodes, while PostgreSQL scales reads through read replicas and handles write contention on hot spots (like a popular lot at peak time) through partition-level distributed locks rather than row-level locks on a single record.