localhost:4000 SCREENSHOT
Citizen app
Request assistance, hold to raise an SOS, track the job, pay and review. Works off-grid: an SOS with no signal becomes a real incident on the device.
One platform connecting stranded drivers, verified mechanics and road-safety authorities — with an emergency path that keeps working when the network does not.
Real screenshots of the running system, set into 3D devices — not mockups.
Every figure on this page was produced by running the thing it describes against a database migrated from empty and seeded. Nothing here is estimated.
The architecture, running
The whole stack as one model, from the four surfaces at the top to the database at the bottom. It turns on its own; open a layer to see what is in it, or press play to watch a real request travel through every one. The readings on it come from the running platform.
Ask about this project
Type a question about the architecture, the testing, the AI, or the scope. The answer comes from a fixed index of facts taken from this repository, scored against your words. There is no language model here, no API key and no request leaving this page.
What it is
Request assistance, hold to raise an SOS, track a job, pay, and review — with a diagnosis step that names a likely cause before dispatch.
Dispatch inbox with ranked offers, the job lifecycle from accept to complete, and settlement recorded against the booking.
Live operational map, road-health scoring, and a confirmation queue for detections that a person — never a model — acts on.
A complete booking over SMS with no app at all, in eight languages,
switched by texting LANG TA.
Off-grid, explained
Most apps fail at the exact moment a breakdown happens: on a highway stretch with no coverage. Here is the path an SOS takes instead, one step at a time.
An SOS has to be held for 1.5 seconds, so a phone in a pocket never calls a responder. A crash the model detects still waits for the person to confirm it.
SosLadder.kt). A rung is tried only if the one above did not carry the SOS, and
exactly one of them owns it.emergency-numbers.js). After them, under Other national helplines (left
out of the drawing for room): 181, Women Helpline (24×7); 1098, Childline — children in
distress (24×7); 14567, Elderline — senior citizens (8 AM–8 PM). A tap hands the number to
the phone's dialler: a voice call can connect where data cannot, and the app only dials.The surfaces
Each role gets its own surface, and all four are served by the same Fastify process (ADR-0001). They are screenshots until you switch to Live platform; then each frame is the running platform itself, and you can sign in and use it.
localhost:4000 SCREENSHOT
Request assistance, hold to raise an SOS, track the job, pay and review. Works off-grid: an SOS with no signal becomes a real incident on the device.
localhost:4000 SCREENSHOT
Availability toggle, rating and job history, the active job, and a dispatch inbox of ranked offers with distance and ETA that expire if not accepted. The screenshot is a seeded mechanic; live, it is whoever signs in.
Detection triage, road-health scoring per segment, edge-device status, and the confirmation queue where a model-raised incident waits for a person (ADR-0005).
localhost:4000 SCREENSHOT
Clustered mechanics, responders and detections over PostGIS geometry, with basemap tiles proxied and cached server-side so no visitor address reaches the tile host.
A fifth surface has no screen at all: POST /v1/telecom/sms completes a booking
from a feature phone with no app, in any of the eight languages, switched by texting
LANG TA.
Live when it is live, and honest when it is not. While the hosted platform at app.roadassistbharat.online answers its health check, the frames above are that platform: sign in and use it. If it stops answering they fall back to screenshots on their own, and a deployment that is not running never gets a LIVE badge. The platform needs a long-lived process (it holds open event streams and runs an offer-expiry sweeper) plus PostgreSQL with PostGIS; it runs on Render with its database on Neon, and one command runs the whole thing locally from the same published image.
How it works
One breakdown, eight screens, in the order a driver meets them. Swipe the post, use the arrow keys, or pick a dot.
Request or escalate Home — SOS, emergency readiness, quick actions
Real screenshots of the running app, captured by scripts/capture-screens.mjs.
dispatch.ts;
the positions on it are not data.ST_DWithin).MATCHING to
ASSIGNED to EN_ROUTE, and every open screen sees it move over a
live event stream.RAKSHA
Edge devices post road-damage detections; the platform scores road health and raises an incident when severity and confidence both clear a threshold — and then waits.
Real Indian road frames, boxed by the trained model — nothing hand-drawn. Each box and its confidence are the model's own output on that frame.
Frames: RDD2022 India subset — Arya et al., CC BY-SA 4.0 · detection boxes are the model's own output
A camera on a patrol vehicle photographs the road as it drives. In this design the images are analysed on the vehicle's edge device, so a stretch with no coverage is still surveyed. The device is simulated in this build; the detector is real.
YOLO11 on RDD2022 across four countries. The training script, dataset manifest and per-epoch metrics are in the repository; the weights are gitignored.
Severity and confidence thresholds decide whether a detection raises an incident.
The roadside diagnosis is a rule table returning rules-1.0.0.
A model-raised incident sits in AWAITING_CONFIRMATION. There is no
transition out of it that does not pass through a human (ADR-0005).
No language model anywhere.
There is no LLM or GPT dependency in any manifest and no chat endpoint called from any
source file — not in the API, the Android client, the web surfaces or the CV pipeline.
npm run no-llm fails the build if one ever appears, and it runs in CI.
AI evidence
| Metric | Value |
|---|---|
| mAP50, 4-country val (800) | 0.586 |
| mAP50-95, 4-country val | 0.287 |
| mAP50, India-clean (392) | 0.500 |
| mAP50-95, India-clean | 0.217 |
| Classes | 4 |
| Training data | India 3.0k (x2) + 2.4k other |
| Epochs (fine-tune) | 20 |
| ONNX export | 10.6 MB |
| Android, 416 px | 0.516 / 0.449 |
Model yolo11n-india-ft-gpu at 640 px, the detector the web scan and the Android
app run. Per-class mAP50 on India-clean: pothole 0.422, road damage 0.578. Potholes are the
weakest class.
Held-out validation only. These are validation figures from the
training run recorded in ai/README.md. They are not production accuracy,
not real-world accuracy, and not a guarantee — the model has never run against live
Indian road imagery at scale, and saying otherwise would be inventing a result.
The pipeline is 39 tests, standard library only, so the logic is checked on every push without a multi-gigabyte install. The detection path stores a hash of each event and never the frame itself (ADR-0006), so an audit trail exists without retaining imagery.
Engineering decisions
Each is enforced by something that fails the build if it regresses.
A crash signal raises an incident that waits in AWAITING_CONFIRMATION
until a person moves it. A false positive that dispatches is worse than a false
negative that asks. ADR-0011 then bounds the mirror failure — nobody arriving — with
a review deadline per severity that escalates attention, never responders.
The SOS ladder falls back data → SMS → 112 → offline queue. The invariant
is that precisely one of them owns the report: a confirmed SMS must not also queue an
API replay; an unconfirmed one must. Getting this wrong sends two responders to one
accident, or none.
Two mechanics accepting one job: SELECT … FOR UPDATE with offer expiry
re-checked under the lock. A duplicate SOS: a unique index on a client-minted
reference. Double settlement: a partial unique index over settled payments. The audit
log is hash-chained, with Postgres RULES making UPDATE and DELETE no-ops.
Five gates run on every push: documented claims must match the measured file; every
file.ts:123 citation must still resolve; module boundaries hold; no
language model enters the system; and no page hands a visitor's address to a third
party. The last one found a live leak the day it was written.
Architecture
The API and every web surface ship in one process. The surfaces are plain HTML, CSS and JavaScript with no build step, so a second deployment unit would add a network hop and a CORS boundary in exchange for nothing.
Citizen PWA, mechanic console, RAKSHA dashboard, live map — plus a native Android client in Kotlin and Compose, and SMS for feature phones.
Fastify, 86 routes, 83 of them under a versioned /v1 contract, Zod validation at every
boundary, JWT with role-based access, and server-sent events for real time.
PostgreSQL 16 with PostGIS. 60 tables, 151 indexes, 5 GiST indexes for geospatial dispatch, 13 migrations, and an append-only audit log.
render.yaml and the as-built note in the architecture
document./v1 API./health
before it frames the live surfaces.Not drawn, because not deployed: the separate emergency deployable, Redis and an event bus. They are in the target architecture, not in the running system.
A client calls the versioned /v1 API: the citizen app, the mechanic console, RAKSHA, the Android client, or the SMS gateway on behalf of a feature phone. Every one of them speaks the same contract.
Security
The security suite is not a checklist. It is a set of attacks that must all fail — a green run means each was attempted and refused, which is a stronger statement than “the code looks right”.
Cross-tenant reads and writes, role escalation and id manipulation — every read is scoped by the caller, and a break-glass read is recorded with its reason.
Forged and alg:none tokens, unsigned webhooks, SQL injection, oversized
input, and error bodies checked for leakage.
The audit chain is verified on read and a forged link is reported as a broken chain.
Postgres RULES make UPDATE and DELETE on the log no-ops.
SECURITY.md;
only the layers it lists as in place. Each red mark is where an attack is refused.alg:none tokens, an edited subject, and a reused
refresh token, which burns its whole family.Under every layer: the live API connects to Postgres as a least-privilege role that can read and write rows but cannot create, alter or drop anything, or rewrite the audit log. Migrations alone run as the owner.
A phone number, or an email address the owner has listed, asks for a one-time code. Requests are rate-limited per number and per connection, so nobody can spray codes at an account.
CI additionally kills PostgreSQL under a running API and asserts the platform is honest
about it — /health returns 503 naming the database while /v1/ping
still returns 200, so a client can tell “you have no network” from
“the platform is unwell” — then rehearses a backup and restore and re-verifies
the audit hash chain on the restored copy.
Evidence
| Suite | What it covers | Assertions | Status |
|---|---|---|---|
| Unit | No I/O; the only suite that runs standalone | 634 | PASS |
| End-to-end | Full citizen and mechanic journeys against a live API | 378 | PASS |
| Concurrency | Races settled by Postgres rather than by timing | 112 | PASS |
| Security | Attacks that must every one be refused | 144 | PASS |
| Gateway security | Telecom path, audit hash chain, OTP limits | 58 | PASS |
| Browser | Real Chrome driven over CDP | 286 | PASS |
| Total | Six suites, zero failures | 1612 | PASS |
| Run separately — not part of the 1612 | |||
| Android | Kotlin unit tests; 27 cover the SOS ladder alone | 356 | PASS |
| CV pipeline | Standard library only, no model download needed | 49 | PASS |
| Razorpay sandbox | Needs a payment account; has never been executed | 22 | NOT RUN |
Tested is not the same as claimed. The 22 Razorpay sandbox checks need a KYC-verified account. They have never run, they are not part of the 1612, and they are never described as passing. Android lint reports zero errors and the release APK builds under R8.
The running system
Produced by scripts/capture-screens.mjs against the live API — regenerable in
about ninety seconds, so they cannot quietly drift from what the product does.
Select any screen to enlarge it.
On the phone — citizen surfaces
On a desktop — mechanic, authority and operations
Recordings
Run it yourself
No account, no cloud, no credentials. It pulls the published image, brings up PostGIS, migrates, seeds, and serves every surface. Running it twice is a no-op rather than an error.
git clone https://github.com/saatwik-1157/roadassist-bharat
cd roadassist-bharat
docker compose -f docker-compose.demo.yml up
Then open http://localhost:4000 — the citizen app, mechanic console, authority
dashboard and live map are all served by that one process.
+917000000000
+919999900001
+919600000000
These are seeded demo accounts. In demo mode the one-time code is returned by the API and fills itself in, so there is no password to publish.
Or use the hosted instance. The same image runs at
app.roadassistbharat.online, against a
managed PostGIS database. There, the accounts the team uses (the authority account among
them) sign in with Sign in with email: the code goes to that person's inbox and is
never shown on screen, so typing the number above gets you nowhere. The on-screen demo code
signs in only the demo numbers: +917000000000 to +917000009999
(the demo citizen is +917000009876), and the mechanics +919600000000 to
+919600000099. Every other number is refused.
Scope
The project distinguishes implemented functionality from future scope, and says which is which. These are named rather than implied:
Latency is measured single-user on one machine. The eight languages ship, but seven are machine-translated and have not been reviewed by native speakers — the strings exist, the quality is unverified, and those are different claims.
The builder
24MIC7131
Full platform
Area The API and database, the web and Android clients, the AI services, CI and the hosted deployment.
Faculty guide: Dr. Nagendra Panini Challa · SWE4004 Cloud Computing and Applications, VIT-AP University.