All case studies
ShippedTransit · Full-Stack Web2024 — 2025
ScanPayGo
Bus ticketing on a two-stage fare: a deposit holds the seat, the balance is taken only when the ticket is scanned.
Role · Full-stack engineer
Overview
A smart bus ticket booking and validation system, built as an academic project. Passengers register, hold a wallet balance, pick a seat against live availability, and board by having a unique QR code scanned; an admin side manages the fleet, approves refunds, and visualizes seat occupancy.
Problem
A booking is a promise, not a completed journey. Charging the full fare up front turns every no-show into refund work, while charging nothing up front reserves seats for free. Validation has the mirror problem: a ticket code that can be scanned twice is a fare that can be charged twice.
Solution
The fare is split across the two moments that actually matter. Fifteen percent is taken from the passenger's wallet as a deposit when the seat is booked; the remaining balance is deducted only when the ticket's QR code is scanned on boarding. Refunds are requested by the passenger and settled through an explicit admin approval step.
Architecture
A single Flask application over SQLite, serving Bootstrap-rendered views with Flask sessions carrying both passenger and admin authentication. Each ticket is issued with a unique QR code generated by Python's qrcode library, and the scan of that code — not the booking — is the event that settles the outstanding fare, so one code maps to exactly one charge.
Tech stack
- Python
- Flask
- SQLite
- Bootstrap
- qrcode
Engineering decisions
- Fare split into a booking deposit and a scan-time balance, so a held seat is never free and a no-show never requires unwinding a full payment.
- The QR scan is the settlement event rather than the booking: one code, one fare, redeemable once.
- Refunds pass through explicit admin approval instead of automatic reversal, keeping a human in the loop on money leaving the system.