The problem
Bus booking in Nepal is still largely phone calls and paper manifests, which means double bookings and no record when a passenger disputes a seat. This gives operators a seat map that is the single source of truth.
What I built
The hard part of any booking system is the seat hold. A seat is reserved for a short window while payment completes, and the hold is released automatically if it does not.
Routes, departures and vehicles are modelled separately, so an operator can change a vehicle on a departure without rewriting the route or losing the bookings already made against it.
Architecture
Django with PostgreSQL. Seat holds use a select for update inside a transaction, so two people pressing book at the same moment cannot both win the seat.
Celery clears expired holds on a schedule.
Problems worth writing down
Concurrent seat claims
Two simultaneous bookings could both pass the availability check. Row level locking inside the transaction made the check and the claim atomic.
Abandoned checkouts
Held seats stayed unavailable forever. A periodic Celery task now releases anything past its window.