Inspiration

Super Typhoon Odette made landfall on December 16, 2021. The UN’s emergency telecommunications cluster ended up setting up internet at 24 sites across the affected islands, and national providers only recovered service across those areas in late March 2022. About three months.

Picture the barangay hall in that stretch. The disaster team knows what walks through the door. One person says there’s flood water at the chapel. Another says the road by the chapel is gone. An hour later a third person says the same thing in different words, and the secretary, with a notebook, has to work out whether that’s one problem or three.

Offline mesh apps like Bridgefy and BitChat already move messages without a signal. A hundred messages is still a hundred messages, though, and somebody has to read all of them. We wanted the phones to do the reading.

We haven’t talked to a barangay disaster officer yet, so that scene is our reconstruction of the problem, not a report from someone who lived it.

Pasabi is Filipino for a message you ask someone to pass along.

What it does

People record short structured observations on their phone: a category like flood, how many people are affected, a short note. Location and time attach themselves. The form works fully offline, in English and Filipino.

When two phones meet, one shows a QR code and the other scans it. A page of observations travels as a short run of frames, most urgent first, and the sender gets a receipt. It works in airplane mode on any two phones with cameras.

Then every phone does the same thing with what it holds. It groups observations of the same kind, place and time into an incident, counts how many separate devices reported it, and ranks it with an urgency score that shows its arithmetic under “why ranked here.”

A station phone at the barangay hall shows the ranked board, and operators can acknowledge or resolve incidents. When any phone reaches the internet, observations upload and a responder dashboard rebuilds the same picture, including what changed since the last sync.

The part we care about most is what the screen refuses to say.

An incident with no trapped-person report reads “Trapped: no report yet,” never “no one trapped.”

A purok nobody has reported from shows as “no reports, this does not mean it is safe.”

The app names upload states exactly (the server either accepted the batch or it didn’t) and nothing in it claims responders were notified, because the app can’t know that.

A station can also sweep one area category by category, and export any incident as a Passport: a document that reads on its own, prints to PDF, and shares by QR so another PASAbi phone rebuilds the incident itself.

How we built it

PASAbi is a TypeScript and React web app built with Vite, installed to the iPhone Home Screen. A service worker and IndexedDB mean every screen opens with no network.

The rule the whole design leans on: incidents are derived, never transmitted. Only immutable observations travel.

Every phone runs the same engine over the observations it holds, so two phones with the same data agree with no coordinator and no merge logic, and the responder dashboard can’t drift from a station board because it runs the same function.

The engine lives in a package of pure TypeScript with no DOM, no React and no clock. The current time is passed in.

Ranking is rule-based and integer-only, and every score exposes its breakdown. There is no AI in the ranking. If this decides who gets help first, someone has to be able to audit it.

For transfer, each page of observations is deflate-compressed with fflate and cut into 500-character frames, then read back in the browser with jsQR.

Data uploads to Supabase Postgres under row-level security. The public key is only safe because those policies allow inserts and one read view, and CI fails the build if a service_role key ever shows up in the bundle.

The web build is hosted on Vercel.

135 automated tests pass in Vitest. The engine has eleven test cases whose expected results we computed by hand, and it produces identical output across 100 random orderings of each.

Challenges we ran into

QR math

The QR math was wrong on paper.

Before building transfer, we ran our own wire format through a size analysis on synthetic data. A page of 60 observations came out at a median of 33 QR frames, each a dense version-22 code, which is a lot to ask of a hand-held camera.

Deflating each page and using 500-character frames brought it to about 18.

That’s a model with an assumed catch rate per frame. Real scanning has streaks from hand shake and glare, and we haven’t measured it on phones.

Bluetooth, built and then deleted

On September 30 we added a native wrapper using Apple’s Multipeer Connectivity so phones could sync over Bluetooth.

On October 1 we removed it.

A web app on an iPhone can’t do phone-to-phone Bluetooth, and nobody on the team was going to run the native build, so it was code that would never meet a real phone.

The transport sat behind an interface, so the engine and the QR path didn’t change.

Negative zero

We wrote eleven test cases by hand before the engine existed, and eight failed on the first run.

-Math.min(0, 20) is negative zero in JavaScript, which compares unequal to 0 and survives into saved snapshots and sync payloads.

If we’d generated the expected values from the engine’s own output, the bug would have been recorded as correct.

What we haven’t proven yet

Every phone-to-phone path goes through QR codes, and none of it has been field-tested on real iPhones.

The run sheet and a transfer log that times every QR transfer are built. The results table is blank.

What exists is automated tests, including one that decodes every frame of a full page in the browser and reassembles it.

Corroboration counts devices, not people, so one person with two phones counts twice. Grouping distances and time windows are starting values that need tuning with a real barangay.

The AI-drafted report form we planned is not built, and the dashboard has no map.

PASAbi is a bridge until official channels come back, not a replacement for them.

Accomplishments that we’re proud of

Three same-spot flood reports from three devices become one strongly corroborated incident, and that’s an automated test case rather than a staged demo.

The Incident Passport round trip is tested the same way: encode, reverse the frames, reassemble, ingest, and the receiving phone’s engine arrives at the same incident with the same counts and timeline.

On synthetic data, a station holding 3,000 observations groups them into about 1,700 incidents well inside our 300 ms budget on a laptop.

We haven’t timed it on a phone.

What we learned

Our first draft said barangays lose connectivity for the first 24 to 48 hours. When we checked Odette, it was days to weeks, and we rewrote the problem statement.

The bugs we actually found came from a test written before the engine existed, or from opening the screen in a browser. Rereading the code turned up very few.

What’s next for PASAbi

A field test on real phones, in airplane mode, with every transfer timed and the results table filled in.

One conversation with a barangay disaster officer about how walk-in reports get logged today, which may change our categories.

After that, tuning the grouping thresholds against real puroks, signed observations, a map on the dashboard, and upload that fires by itself when a phone gets signal.

TEAM: Ian Patrick A. Flores | Jace Matthew M. Catriz | Fiona S. Guiao | Mary Princess Angel L. Dizon | Joey T. Cuison | Mark Jemiel P. Guevarra

Built With

  • fflate
  • github
  • indexeddb
  • jsqr
  • qrcode
  • react
  • row-level-security)
  • supabase-(postgres
  • typescript
  • vercel
  • vite
  • vite-plugin-pwa
  • vitest
  • workbox
Share this project:

Updates

Submission history