Video in the works
BSafeLink
A school bus trip, from booking and payment to the parent's phone.

About the project
BSafeLink is a school transport app built for the client BSafeLinkr. Parents book a school van, pay monthly and follow the trip live; drivers and schools manage routes and attendance. I lead the build.
BSafeLink is a school transport platform built for the client BSafeLinkr. Parents book a school van for their child, pay every month and follow each trip live. Drivers run their routes and mark attendance, and schools and admins manage it all from a dashboard.
I lead the build. My part is mainly the backend everything runs on, the payments, phone login, notifications and scheduled jobs, plus the redesign of the Flutter parent app. Komal built the backend's foundation and live tracking; the driver app and the web admin are teammates' work.
Because it handles children's data and money, much of the work is about safety: India's DPDP rules for child data, payments that can't be charged twice, driver actions that are safe to retry when the network drops, and an audit log of every admin action.
How it works
Sign up
A parent logs in with a 6-digit OTP, adds a child with consent, and sets pickup and drop addresses.
Book and pay
They book a van and pay through PayU, by auto-pay or from a wallet. Bills go out monthly with reminders and late fines.
Trip day
The driver starts the trip and marks each pickup and drop. Parents follow it live.
Paying cash
If a parent pays the driver in cash, the driver confirms it with a 4-digit code that locks after 5 wrong tries.
Behind the scenes
Scheduled jobs run billing, driver settlements, rechecks of lost payments, document expiry reminders and data retention.
Under the hood
- Backend
- Express 5 and TypeScript with Prisma on Supabase Postgres, covered by 23 end-to-end test suites.
- Payments
- PayU with verified callbacks, a job that rechecks payments whose callback was lost, and wallets for parents and drivers.
- Live tracking
- WebSockets that recheck access every minute and close when a token expires.
- Notifications
- An in-app inbox, Firebase push notifications and admin broadcasts.
- Parent app
- Flutter, with Google Maps and English and Hindi text.
What I did
- Set up the team repo and merged everyone's branches into one codebase
- Extended the backend: driver sign-up, documents and admin checks, driver wallet and monthly settlements, support tickets, admin master data, reports, and an audit log of every admin action
- Built the payments layer: PayU checkout with verified callbacks, a job that rechecks payments whose callback was lost, auto-pay, a parent wallet, late fines, monthly billing with reminders, and cash confirmed with a 4-digit code from the driver
- Real phone login: a 6-digit OTP by SMS, stored hashed, rate limited, with rotating refresh tokens
- A background scheduler for billing, settlements, payment rechecks, document expiry reminders and data retention
- Notifications: an in-app inbox, push notifications and admin broadcasts
- Hardened the API: rate limits, a 503 instead of logging users out when the database is down, and driver actions that are safe to retry offline
- Child-data rules for India's DPDP law: parental consent per child, and account deletion that anonymises data but keeps invoices
- 23 end-to-end backend test suites and a script that rebuilds the whole database in a fresh Supabase project
- Redesigned the Flutter parent app to the designer's mockups, with real Google Maps and English and Hindi text
What was new
- Offline-safe actions: each tap carries a key, so a retry replays the stored result instead of acting twice
- Live-tracking sockets that recheck access every minute and close when a token expires
- Cash collection confirmed with a short-lived code that locks after 5 wrong tries
- Running client work through an AI coding agent, gated by a written list of open questions for the client
Problems I hit, and how I fixed them
After merging the branches, the backend crashed on start because an auth service was missing.
Fix Added it, and made production refuse to start with development login switched on.
Between midnight and 5:30 am IST, bills and trips landed on the wrong day because dates followed the server's clock.
Fix One helper that always returns the Indian business date.
A driver could show an old vehicle because assignments were modelled one-to-one.
Fix Query only the current assignment everywhere.
Ten database connections per process used up Supabase's pooler as soon as two processes ran.
Fix A configurable pool, default 5.
A pickup-only address change left drop trips at the old address.
Fix Each rider gets the right address for their trip type.
When the database was down, users got logged out.
Fix Return 503 with a retry hint instead of 401.
Screenshots
Screenshots in the works
Real screens from BSafeLink go here.
To be clear
I built this with Claude Code as my pair programmer, and most of my commits landed in two intense days. Komal built the backend foundation and the live tracking; I extended and hardened it. The driver app and web admin are teammates' work. The parent app still runs on demo data until the client's keys arrive. bsafelinkr.com is the client's older site, not my work.