Mobile Apps

Collections route app for a rural bank

Built by Cielo Navarrete

An offline-first Android app for a rural bank's field collection officers — built to work a full route with no signal and still post same-day.

  • Builder email verified

    Verification

Project screenshot
Type
Professional
Category
Mobile Apps
Published
Jul 26, 2026
Updated
Jul 26, 2026
Built withFlutterDartSQLiteFirebase
TopicsFintech

About this project

The problem

The bank's collection officers ride routes through towns where signal is a rumor, collecting loan payments on paper route sheets that a branch encoder retypes every evening. Postings landed a day late on good days, transcription errors triggered borrower disputes, and a lost route sheet was a small crisis with interest. The bank wanted collections captured digitally in the field — but any design that assumed connectivity was dead on arrival, because the connectivity does not exist.

My role

Mobile developer, one of two, alongside a backend developer and a business analyst at the software house, for about nine months — my first project with real stakes, eighteen months into my career. Our BA rode actual collection routes twice during requirements, which is why the requirements were good, and I spent a week doing the same with a test device, which is why the sync design got rebuilt.

What I owned

I owned the offline storage model and the sync engine — the two things the app actually is — plus the route and receipt screens. My co-developer owned borrower search, reporting, and the supervisor views. The receipt numbering scheme was mine as well, and I include it because it turned out to be the most consequential design on the project.

Technical & product decisions

The defining decision was building sync as an explicit SQLite outbox with visible per-record states rather than trusting a sync framework's magic — the bank's auditors needed to trace every payment from capture to posting, and 'the framework handles it' is not an audit answer. Conflicts resolve server-wins for reference data, but payments are append-only and never merged: a payment captured twice surfaces as a flagged duplicate for a human, never a silent overwrite. Receipt numbers come from per-device ranges allocated in advance at the branch, so two offline devices can never issue the same official receipt number — that one took an afternoon to build and killed the entire category of duplicate-receipt reconciliation the bank used to do weekly.

Constraints

The bank's core system accepts postings only as an end-of-day batch file — there is no API, and the vendor quoted a number for building one that ended the conversation — so our 'real-time' sync lands in a staging database that becomes a file at 5pm, and the app's honesty about this ('synced' versus 'posted') needed careful interface language. Hardware was whatever the bank could buy: entry-level Android units with 2 GB of RAM, so memory discipline wasn't optional. And field officers wear gloves on motorcycles, which is the kind of requirement no spec document ever contains.

Result & impact

Payments now post the same day they're collected, and the evening encoding shift at the pilot branch simply stopped existing — the encoder moved to reviewing flagged exceptions instead. Transcription disputes went to effectively zero because there's no transcription, and the receipt-range scheme ended duplicate-receipt reconciliation outright. The pilot branch became eleven branches over a year, and the app has survived two rainy seasons of being dropped, which in this deployment context is a performance metric.

Who else worked on it

My co-developer built half the app and caught my worst sync bug in review — a state transition that could strand a payment as permanently 'sending'. The BA's route ride-alongs shaped everything about the interface, the backend developer designed the staging-to-batch bridge and its reconciliation report, and the pilot branch's senior collection officer test-drove every build and rejected two of them, correctly.