Project showcase · source and image public

Roadside assistance, rebuilt for the roads where coverage fails.

One platform connecting stranded drivers, verified mechanics and road-safety authorities — with an emergency path that keeps working when the network does not.

The platform in 3D: the RAKSHA authority dashboard on a monitor, the citizen app and the mechanic dispatch screen on phones, linked as one process

Real screenshots of the running system, set into 3D devices — not mockups.

1612
Assertions
60
Tables
151
Indexes
86
API routes
8
Languages

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

Every layer, live in 3D

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.

The layers of RoadAssist Bharat stacked as one model, rendered in Blender
RENDER The same model, rendered in Blender. The live scene loads here from the running platform when it answers. Open full screen

Ask about this project

Answers, looked up — not generated

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.

Deterministic: the same question always returns the same answer, and every answer names where in the repository it comes from.

What it is

Four surfaces, one process, and a path that survives no signal

Citizen app

Request assistance, hold to raise an SOS, track a job, pay, and review — with a diagnosis step that names a likely cause before dispatch.

Mechanic console

Dispatch inbox with ranked offers, the job lifecycle from accept to complete, and settlement recorded against the booking.

RAKSHA authority

Live operational map, road-health scoring, and a confirmation queue for detections that a person — never a model — acts on.

Feature phone

A complete booking over SMS with no app at all, in eight languages, switched by texting LANG TA.

Off-grid, explained

What happens when there is no signal

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.

Illustration Demo service area: Gurugram and the NH-48 corridor, where the seed places a simulated fleet VIT-AP University, Amaravati, where the project is built (position approximate) Bright dots are land, faint ones sea. The dotted gold frame is the India bounds the live map opens on. Land: Natural Earth, public domain
Step 1 of 5

A deliberate press

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.

Illustration: the SOS ladder, on a night highway with no data A car stopped on the shoulder with its hazard lights on, where there is no coverage, and a phone showing no data. Below it, the rungs an SOS is tried on, in order: data to the platform, then an SMS carrying the GPS fix, then the phone's dialler opened on 112, and last, kept on the phone until data returns. No coverage No data SOS 1 DataSent to the platform's API 2 SMSA text carrying the GPS fix 3 112The phone's dialler opens on 112 4 Stored on this phoneKept with its reference until data returns
Illustration The Android client's SOS ladder, top to bottom (SosLadder.kt). A rung is tried only if the one above did not carry the SOS, and exactly one of them owns it.
Illustration: the emergency numbers card, tap to call A phone screen headed Emergency. A large red button reads Call 112, for all emergencies: police, fire and ambulance. Below it, the other numbers the app lists: 1033, the national highway helpline run by NHAI; 108, ambulance in most states; 102, ambulance in some states; 100, police; and 101, fire. TAP · tel: OPENS THE DIALLER Emergency a call, not data Call 112 All emergencies (police, fire, ambulance) 1033108102100101 National highway helpline (NHAI) Ambulance (most states) Ambulance (some states) Police Fire
Illustration The numbers the app lists, in its order (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

Four dashboards, one process

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.

These are screenshots of the running system. Start the platform with one command, then switch to Live platform to use the real thing inside these frames.

Citizen app home screen with the hold-to-escalate SOS control

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.

Mechanic console, signed in: availability toggle, rating, active job and new requests

localhost:4000 SCREENSHOT

Mechanic console

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.

localhost:4000 SCREENSHOT
RAKSHA authority dashboard with live map, road health scoring and detections

RAKSHA authority dashboard

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).

Live operational map with clustered mechanics, responders and detections

localhost:4000 SCREENSHOT

Live operational map

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

From breakdown to resolution

One breakdown, eight screens, in the order a driver meets them. Swipe the post, use the arrow keys, or pick a dot.

RoadAssist BharatSWE4004 · VIT-AP
Field report
Citizen home screen with the SOS control and emergency readiness
Diagnosis screen naming a likely cause, labelled a rules engine
Dispatch screen with ranked offers
Live job tracking screen
Off-grid SOS created, stored on the phone
SOS synchronised, with the platform reference
Payment screen
RAKSHA authority dashboard with live map, road health and detection triage

Request or escalate Home — SOS, emergency readiness, quick actions

Real screenshots of the running app, captured by scripts/capture-screens.mjs.

Illustration: how a mechanic is matched and sent A map with a stranded driver's pin on a highway and a search radius drawn around it. Mechanics inside the radius are ranked; the top three receive offers, shown as dashed lines. The first to accept is shown in green, driving to the pin. Mechanics outside the radius are greyed out. Along the bottom, the booking states: matching, assigned, en route. outside the radius 1 2 3 First accept wins Stranded driver search radius · ST_DWithin OFFER WAVE ranked by distance, ETA and rating MATCHING → ASSIGNED → EN_ROUTE
Illustration Drawn to explain dispatch.ts; the positions on it are not data.
Reading the drawing

Nearest first, and only one wins

  1. Within a radius. PostGIS finds the verified mechanics within reach of the driver's pin, on real distance (ST_DWithin).
  2. Ranked, then offered in waves. The best few by distance, ETA and rating get an offer. An offer nobody accepts expires, and the next wave goes to the next best.
  3. First accept wins. Two mechanics accepting one job at once is settled by a row lock in Postgres, not by timing.
  4. On the way. The booking moves from MATCHING to ASSIGNED to EN_ROUTE, and every open screen sees it move over a live event stream.

RAKSHA

Road-safety intelligence, with a human in the loop

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.

RAKSHA authority dashboard showing a live map, road-health scoring and detection triage
Indian road frame 1 of 8, with the road-damage box the trained model drew REC · EDGE-01 YOLO11n · RDD2022-IN

Through the device's eyes

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.

  • YOLO11nDetector on the edge device
  • RDD2022-INIndian road-damage frames
  • ≥ 0.35Confidence to report
  • 65 msPer frame
FRAME 01/08

Frames: RDD2022 India subset — Arya et al., CC BY-SA 4.0 · detection boxes are the model's own output

Illustration: what the edge device does with a frame A drawn road camera frame at dusk. A box labelled pothole is drawn around a hole in the right lane and a smaller box labelled crack in the left lane. The frame is tagged as a simulated edge device running YOLO11n. Below: boxed on the device, reported at a confidence of at least 0.35, and with no signal held on the device and sent once. pothole crack EDGE · SIMULATED YOLO11n Boxed on the device → Reported at confidence ≥ 0.35 No signal: held on the device, then sent once.
Illustration Hand-drawn to explain the step, so not model output. The real frames, boxed by the trained model, are in the feed above.
Illustration: the authority's review queue A drawn console titled detections waiting for a person. One pothole on NH-48 is marked verified by an officer. A crack from a citizen report and another pothole are marked detected, each with Verify and Reject buttons, and a pointer is about to press Verify. Below, an incident sits in AWAITING_CONFIRMATION: no way out of it skips a person. RAKSHA · authority REVIEW QUEUE Detections waiting for a person PotholeNH-48 · edge device VERIFIED by an officer CrackNH-48 · citizen report DETECTED Verify Reject PotholeNH-48 · edge device DETECTED Verify Reject INCIDENT AWAITING_CONFIRMATION No way out of it skips a person · ADR-0005
Illustration Drawn after the authority dashboard's review queue; the rows are not real detections. The dashboard itself is the screenshot above.
Step 1 of 6

A camera sees the road

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.

DETECTION

A model that was trained

YOLO11 on RDD2022 across four countries. The training script, dataset manifest and per-epoch metrics are in the repository; the weights are gitignored.

DECISION

Rules, not inference

Severity and confidence thresholds decide whether a detection raises an incident. The roadside diagnosis is a rule table returning rules-1.0.0.

RESPONSE

A person decides

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

The measured result, and what it is not

MetricValue
mAP50, 4-country val (800)0.586
mAP50-95, 4-country val0.287
mAP50, India-clean (392)0.500
mAP50-95, India-clean0.217
Classes4
Training dataIndia 3.0k (x2) + 2.4k other
Epochs (fine-tune)20
ONNX export10.6 MB
Android, 416 px0.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

Four decisions worth defending

Each is enforced by something that fails the build if it regresses.

01

A model is never allowed to dispatch

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.

Read ADR-0005 →
02

Exactly one channel owns an emergency

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.

Read ADR-0009 →
03

Races are settled by Postgres, not by timing

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.

Read ADR-0010 →
04

The build refuses to let the documents lie

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.

Read ADR-0002 →

Architecture

A modular monolith, on purpose

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.

Clients

Citizen PWA, mechanic console, RAKSHA dashboard, live map — plus a native Android client in Kotlin and Compose, and SMS for feature phones.

API

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.

Data

PostgreSQL 16 with PostGIS. 60 tables, 151 indexes, 5 GiST indexes for geospatial dispatch, 13 migrations, and an append-only audit log.

Illustration: where the platform runs Six clients at the top: the citizen app, the mechanic console, RAKSHA, the live map, the Android app and feature phones over SMS. They reach the platform over HTTPS through Cloudflare, which sits in front of Render. On Render in Singapore, one container runs one Fastify process holding the /v1 API, the web pages, the server-sent event streams and the offer-expiry sweeper. It connects over TLS to Neon in Singapore: PostgreSQL with PostGIS. To one side, this showcase page, static on GitHub Pages, reads the platform's health. CLIENTS one /v1 contract Citizen appPWA Mechanicconsole RAKSHAauthority Live mapoperations AndroidKotlin + Compose Feature phoneSMS, no app HTTPS · /v1 · SSE Cloudflare · in front of Render This page GitHub Pages /health RENDER · SINGAPORE One container, one Fastify process /v1 API Web pages SSE streams Offer-expiry sweeper TLS NEON · SINGAPORE PostgreSQL + PostGIS
Illustration A diagram of the deployment, not a screenshot. Drawn from render.yaml and the as-built note in the architecture document.
Reading the drawing

What runs, and where

  1. Every client, one contract. The citizen app, the consoles, the Android client and the SMS path all call the same versioned /v1 API.
  2. Cloudflare in front. The API takes the caller's address from the header the edge sets, so a client cannot forge its way past a per-address limit.
  3. Render, Singapore. One container and one long-lived Fastify process: the API, every web surface, the event streams and the offer-expiry sweeper.
  4. Neon, Singapore. PostgreSQL with PostGIS, reached over TLS.
  5. This page. Static on GitHub Pages. It asks the platform's /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.

Step 1 of 7

Request

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.

The citizen app and mechanic console side by side over a network graph
Two clients, one contract — the same versioned /v1 API behind both.
Isometric rendering of the deployment topology
Infrastructure, drawn rather than photographed — rendered procedurally as geometry. Nothing photographic is claimed and no stock image with unknown licensing enters the project.

Security

144 attacks, every one refused

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”.

Access

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.

Tokens and input

Forged and alg:none tokens, unsigned webhooks, SQL injection, oversized input, and error bodies checked for leakage.

Integrity

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.

Illustration: the layers a request passes through Nested layers, outermost first. Headers and origins: a strict content security policy with scripts allowed by hash, HSTS and a CORS allow-list. Rate limits per caller, never on an SOS confirm. Sign-in: a one-time code, a short-lived JWT and an HttpOnly cookie. Access: a role gate, then ownership checked at the resource. Input: Zod schemas and parameterised queries. At the core, the audit log, hash-chained and append-only, so editing one row makes every later hash fail. Each layer is marked as a place where an attack is refused. Headers and originsstrict CSP, scripts by hash · HSTS · CORS allow-list Rate limitsper caller · never on an SOS confirm Sign-inone-time code, short-lived JWT, HttpOnly cookie Accessrole gate, then ownership at the resource InputZod schemas, parameterised queries Audit log hash-chained, append-only edit one row and every later hash fails
Illustration Drawn from SECURITY.md; only the layers it lists as in place. Each red mark is where an attack is refused.
What each layer refuses

Outside in, then the record

  1. Headers and origins. An inline script not on the hash list, framing by any site but the showcase, and other websites calling the API with a user's credentials.
  2. Rate limits. Sprayed sign-in codes and booking floods. The call that summons help is never limited.
  3. Sign-in. Forged and alg:none tokens, an edited subject, and a reused refresh token, which burns its whole family.
  4. Access. Another person's booking, vehicle or SOS.
  5. Input. SQL injection, malformed JSON and oversized fields.
  6. Audit log. An edited history, which no longer verifies.

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.

Step 1 of 6

Ask for a code

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

Every suite, and the one that never ran

SuiteWhat it coversAssertionsStatus
UnitNo I/O; the only suite that runs standalone634PASS
End-to-endFull citizen and mechanic journeys against a live API378PASS
ConcurrencyRaces settled by Postgres rather than by timing112PASS
SecurityAttacks that must every one be refused144PASS
Gateway securityTelecom path, audit hash chain, OTP limits58PASS
BrowserReal Chrome driven over CDP286PASS
TotalSix suites, zero failures1612PASS
Run separately — not part of the 1612
AndroidKotlin unit tests; 27 cover the SOS ladder alone356PASS
CV pipelineStandard library only, no model download needed49PASS
Razorpay sandboxNeeds a payment account; has never been executed22NOT 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.

Recordings

See the system in motion

RoadAssist Bharat in 30 seconds

A short film: real app footage and real screenshots, with the drawn scenes tagged as illustrations. Every figure on screen comes from app/docs/measured.json. Vertical cut for phones.

LIVE PREVIEW

Citizen journey

Sign in, diagnose, dispatch, track, pay — recorded against the running system.

LIVE PREVIEW

RAKSHA replay

65 real detections replayed through the ingest path, twice, to show the replay is idempotent.

Run it yourself

The whole platform, one command

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.

Citizen

+917000000000

Authority

+919999900001

Mechanic

+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

Scope, by design

The project distinguishes implemented functionality from future scope, and says which is which. These are named rather than implied:

iOSAndroid AutoIVR USSDSatelliteMesh networking ERSS-112 handoff (stubbed)Kubernetes TerraformAutoscaling Multi-zoneLoad testing

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

One builder, every layer of the platform

VS

V. Saatwik Sairaam

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.