When building personal finance software, standard engineering advice says:
"Spin up Supabase, plug in Plaid for automatic bank scraping, and charge $12/month."
We rejected that premise entirely when architecting MyneWallet.
Handling money data requires extreme operational discipline. If your remote server stores a user's transaction ledger, you are one zero-day exploit, misconfigured S3 bucket, or sub-processor breach away from exposing their entire financial identity.
Here is the engineering breakdown of how we built an offline-first, zero-telemetry financial vault in Flutter—handling decimal currency math without floating-point errors, deterministic envelope allocation, and client-side web verification.
- The Core Constraint: Zero Network Permissions
The cleanest way to guarantee data privacy is architectural, not legal:
No Firebase SDKs.
No Mixpanel, Segment, or analytics beacons.
No network requests carrying payload figures.
Every ledger write, balance reconciliation, and category balance calculation runs strictly inside an on-device SQLite database encrypted with SQLCipher.
[User Device]
└── Flutter UI Layer
└── Integer Math Engine
└── Encrypted SQLite Database (On-Device Storage Only)
The app operates identically in airplane mode because it has zero remote dependencies.
- Handling Currency Math Without Floating-Point Traps
In financial software, standard IEEE 754 floating-point operations (0.1 + 0.2 = 0.30000000000000004) are unacceptable. Over multi-year ledgers with thousands of line items, floating-point rounding errors compound into balance drift.
To guarantee precision, all monetary values in our SQLite database are stored as 64-bit Integers representing minor units (cents):
Dart
class Money {
final int minorUnits; // $14.99 is stored as 1499 integer cents
const Money(this.minorUnits);
Money operator +(Money other) => Money(minorUnits + other.minorUnits);
Money operator -(Money other) => Money(minorUnits - other.minorUnits);
String toFormattedString(String currencySymbol) {
final double value = minorUnits / 100.0;
return '(currencySymbol){value.toStringAsFixed(2)}';
}
}
By enforcing integer arithmetic, our envelope auto-allocation algorithms never lose a single cent to binary rounding residue.
- The Envelope Allocation Engine
Under a True Zero-Based Budgeting (ZBB) model, every single unit of income must be assigned a job before the month begins:
💡 The Core Equation:
To Assign = Unallocated Cash − Total Assigned Envelopes
When income arrives, our deterministic Auto-Assign engine allocates funds through a three-stage priority pipeline:
Fixed Monthly Obligations: Rent, utilities, debt minimums.
Sinking Fund Targets: Amortized monthly allocations for annual commitments.
Flexible Spending: Groceries, personal allowances, dining.
If a category overspends, the ledger flags the exact variance and prompts the user to reallocate from another envelope, keeping the core ledger balanced to zero.
- Client-Side Web Companion & Open Methodology
Alongside the mobile app, we built 10 standalone client-side financial calculators that run in the browser without cookies, tracking scripts, or server requests:
Web Suite: https://thebrinklabs.com/tools/
Formulas & Verification Gates: https://thebrinklabs.com/methodology
Every formula, rounding rule, and mathematical test case is published openly, allowing users to verify our math directly in their browser's Network tab before downloading the mobile app.
Conclusion & Open Discussion
Privacy in software is often treated as a marketing bullet point. In practice, it is a set of hard architectural trade-offs: no password reset flows, no remote sync fallbacks, and total reliance on robust local database integrity.
Google Play: https://play.google.com/store/apps/details?id=com.thebrinklabs.mynewallet.expensetracker
Architecture Docs: https://thebrinklabs.com/
How are other indie developers handling local encrypted storage and offline state management in Flutter? Let's discuss in the comments below!
Top comments (0)