Deptmaster
A debt-collection platform where no one — not even the administrators — can quietly change the numbers.
Dozens of field collectors, multiple wallets, thousands of client accounts. Every action recorded for good, a mobile app that works with no signal, and code the client owns.
- Automated tests
- 230206 are full scenarios: several people posting events at once, plus stress tests.
- Built and live in
- 3 monthsFrom our first meeting to the system running their business.
- In the field
- No signal neededCollectors post payments anywhere; the app syncs when it's back online.
- Since go-live
- No major bugs reportedBy the client. They've asked only for interface tweaks, which we made.
The problem
Money moving fast, through many hands, with no memory.
Collectors handled cash; some managed accounts; some did both. Wallets were shared, approvals were verbal. When something looked off, nobody could answer: who changed that, when, and from what?
“They came in asking for logs everywhere. We told them: make the data structure the log.”
Change a number and the old one is gone. Who, when, why: unknown.
- Tue 14:32 · Collector A+250,000#4821
- Tue 16:05 · Finance−500,000#4821
- Wed 09:10 · Collector C+120,000#3307
Balances are computed from this list. Nothing is overwritten, ever.
The history is the ground truth.
A cached balance looks wrong? Replay the events and rebuild it. Corrections are new events, never edits.
Two codebases drift apart; one can't. The client doubted Rust at first, so we proved it: 230 tests, most of them full scenarios with several people acting at once, plus stress tests.
The dashboard
Wallets, teams and clients in one place, every number traceable back to the actions that produced it.
The collector's app
Collectors post payments where they stand, signal or not. Work queues on the phone and syncs the moment it reconnects.
The part nobody thinks about until they need it.
- Wallet-wide — who adds members, renames, edits the rules.
- Team to team — "Sellers Admin" runs Sellers, not Finance.
- Contact groups — which teams can file clients where.
- Action-level — read, create, update, delete, close: per team, per group.
Every permission change is itself a recorded event.
Servers that check each other.
Several servers compare cryptographic fingerprints of their event history. To forge a record you'd have to rewrite every server and every device at once, and even then every node raises the alarm, stops taking new events and alerts the admins. The apps keep working offline until the servers agree.
Available in our custom builds.
How we switched without putting their business at risk.
- 1Move the dataA migration script copied everything out of the old database and reshaped it for the new system.
- 2Run both, side by sideFor almost a week the old system stayed on alongside the new one. If anything looked wrong (a bug, a mismatch, a case we hadn't seen), staff could go straight back to it while we fixed it.
- 3Switch the old one offNobody ever needed to fall back. The old system was retired, and Deptmaster runs the business.
- Day oneFirst contact
- Week oneAudit of the existing system
- Month oneClient reviews a working build
- Month threeFull delivery, in production
Six things they didn't have before.
- Full ownershipOne binary on their own server. No cloud, no subscription, no vendor.
- Permanent recordEvery action recorded for good. Disputes have an answer: replay the history.
- Multiple walletsEach with its own teams, contacts and rules, fully isolated.
- Offline mobile appQueues work and syncs when reconnected.
- Fine permissionsA team lead runs their own team and nothing else.
- Add-on servicesDue-date reminders, SMS and WhatsApp statements, office tools: beside the core, not inside it.
- Rust — server (Postgres + Axum) and client logic layer
- Flutter — mobile UI via Flutter Rust Bridge (FFI)
- SQLite — local client database
- Event sourcing — every action recorded; balances computed, not stored
- Shared Rust crates — business logic written once, compiled into both server and app