Design a Parking Garage
Design a parking garage system with OOP modeling, sensor integration, real-time space tracking, payment processing, and reservation management.
Problem Statement
Design a parking garage management system that tracks available spaces in real time, handles vehicle entry/exit via sensors or ticketing, calculates fees based on duration and vehicle type, supports reservations, and manages multiple floors with different spot sizes (compact, regular, large, handicapped).
Requirements
Functional
- Track real-time availability per floor and spot type (compact, regular, large, handicapped)
- Handle vehicle entry: assign nearest available spot, issue ticket with entry timestamp
- Handle vehicle exit: calculate fee based on duration and vehicle type, process payment
- Support advance reservations with time-window holds
Non-Functional
- Consistency: No double-booking of spots -- strong consistency required
- Latency: Entry/exit gate processing <2 seconds
- Availability: 99.9% -- gates must open even during partial system failure
- Scale: Support 10,000-spot garages with 50,000 entries/exits per day
Core Architecture
-
Spot Allocation Service -- Maintains an in-memory map of all spots and their states (available, occupied, reserved, maintenance). Uses a priority queue per floor to assign the nearest available spot to each vehicle type. Spot assignment is wrapped in a database transaction to prevent double-booking.
-
Entry/Exit Gate Controller -- Interfaces with physical hardware: license plate cameras, ticket dispensers, barrier gates. On entry, requests a spot from the allocation service and issues a ticket. On exit, looks up the ticket, computes the fee, and lifts the barrier after payment.
-
Payment Service -- Computes fees using a rate engine: first hour flat rate, then per-15-minute increments. Supports credit card, mobile pay, and prepaid passes. Integrates with Stripe/payment processor. Generates receipts and handles refunds for overcharges.
- Reservation Manager -- Accepts advance bookings with a time window. Holds the reserved spot starting 15 minutes before the window. Unredeemed reservations release automatically after a grace period, triggering a no-show fee.
Database Choice
PostgreSQL is the primary database. Spots, tickets, and reservations all have strong relational integrity (a spot belongs to a floor, a ticket references a spot and a vehicle). Transactions ensure no double-booking. The spots table uses a status column with row-level locking on assignment. Redis caches the real-time availability counts per floor for the display boards and mobile app, updated via CDC from Postgres.
Key API Endpoints
POST /api/v1/entry
-> Body: \{ license_plate: "ABC123", vehicle_type: "regular" \}
-> Returns: \{ ticket_id: "T-9001", spot: "F2-R34", floor: 2 \}
POST /api/v1/exit
-> Body: \{ ticket_id: "T-9001", payment_method: "credit_card" \}
-> Returns: \{ duration_min: 147, fee_usd: 12.50, receipt_url: "..." \}
Scaling Insight
For multi-garage chains, use a hierarchical allocation model: each garage runs its own Spot Allocation Service locally (so gates work even if the network is down), while a central service aggregates availability across all garages for the mobile app and reservation system. Local-first design ensures gates never block on a remote call.
Key Tradeoffs
| Decision | Option A | Option B | Chosen |
|---|---|---|---|
| Spot assignment | Random available | Nearest to entrance | Nearest -- better user experience, reduces driving time inside garage |
| Consistency | Optimistic locking | Pessimistic row lock | Pessimistic -- simpler, spot contention is low enough that lock wait is negligible |
| Fee model | Flat hourly rate | Tiered per-minute | Tiered -- fairer to short-stay visitors, higher revenue optimization |
Practical Implementation for .NET Developers
In a .NET application, you would typically implement this pattern using the following approach:
ASP.NET Core setup: Create a service class that encapsulates the logic, register it with dependency injection, and inject it into your controllers or minimal API endpoints. The built-in DI container handles lifecycle management.
Entity Framework Core: For database interactions, EF Core provides the ORM layer. Use migrations for schema management and raw SQL for performance-critical queries. Consider Dapper for read-heavy paths where EF Core's overhead matters.
Azure integration: If deploying to Azure, leverage managed services — Azure Cache for Redis, Azure SQL, Azure Service Bus, Azure Cosmos DB. These eliminate operational overhead and provide built-in monitoring through Application Insights.
Testing: Use xUnit with Testcontainers for integration tests that spin up real databases in Docker. Mock external dependencies with NSubstitute. The WebApplicationFactory class lets you test your entire HTTP pipeline in-process.
Monitoring: Add Application Insights telemetry to track request latency, dependency calls, and custom metrics. Use structured logging with Serilog to make production debugging possible:
Log.Information("Processing order {OrderId} for {CustomerId}", orderId, customerId);
This gives you searchable, structured logs in Azure Monitor or Seq.
System-Specific Clarifying Questions
Before designing Parking Garage, ask questions specific to THIS system:
- Who are the primary users? Understanding the user base shapes every technical decision — consumer apps have different requirements than enterprise B2B systems.
- What is the read-to-write ratio? This determines whether you optimize for fast reads (caching, denormalization) or fast writes (write-ahead logs, async processing).
- What is the geographic distribution? Users in one country vs. global users fundamentally changes your data replication and CDN strategy.
- What is the acceptable latency? Some features need sub-100ms responses, others can tolerate seconds. This determines your caching and architecture strategy.
- What is the consistency requirement? Some data (payments, inventory) needs strong consistency. Other data (social feeds, recommendations) can be eventually consistent.
Architecture Deep Dive
The architecture for Parking Garage should be designed around the specific access patterns of the system. Do not apply generic templates — every system has unique hotspots, bottlenecks, and scaling challenges.
Write Path: How does data enter the system? Is it bursty (event-driven, flash sales) or steady (sensor data, logs)? Bursty writes need queuing and backpressure. Steady writes can go directly to the database.
Read Path: How is data consumed? Is it fan-out (one write, many reads like social feeds) or point lookups (one read for specific data like user profiles)? Fan-out reads benefit from pre-computation and caching. Point lookups benefit from efficient indexing.
Hot Spots: Where are the bottlenecks? For Parking Garage, identify the component that will fail first under load and design mitigation strategies: caching, sharding, rate limiting, or async processing.