The smart parking system started as a hackathon project and evolved into a full-featured product. The core challenge: how do you display accurate, real-time parking availability across a multi-level car park without overcomplicating the architecture?
The sensor integration layer was the first decision point. We were working with IR sensors that report occupancy via a microcontroller gateway over MQTT. The MQTT broker (Mosquitto) sits between the hardware layer and the application. Node.js subscribes to MQTT topics and processes occupancy state changes, updating MongoDB and broadcasting via Socket.io to connected clients.
The real-time layer is where most systems get into trouble. The temptation is to push every sensor event to every connected client immediately. At scale this causes problems: network flooding, client-side re-rendering thrash, and amplification of transient sensor glitches (sensors occasionally misfire). We solved this with a debounced event pipeline: sensor events are buffered for 500ms, duplicates are collapsed, and only confirmed state changes are broadcast.
For the booking flow, we used optimistic locking to prevent double-booking. When a user starts a booking, they're issued a reservation token with a 5-minute TTL. If they complete checkout within that window, the slot is theirs. If they abandon the flow, the reservation expires automatically and the slot is released — no manual cleanup required.
What I'd do differently: the analytics dashboard was built after the fact, which meant the data schema wasn't optimised for time-series queries. I'd design the event log schema from the start with analytics in mind, likely separating the operational database from an append-only event store for reporting.