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

- Type
- Professional
- Category
- Mobile Apps
- Published
- Jul 26, 2026
- Updated
- Jul 26, 2026
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.