Offline Android finance app
Peyvor
A standalone, offline Android app for tracking bills, loans, salary and weekly cash flow. Data stays on the phone, encrypted, and the app is built without internet permission.
- Status
- Built and tested. Personal project.
- Source
- Source: private
The problem
Personal money tracking apps usually want an account, a network connection and a copy of your data on someone else’s server.
The goal was a tool for manual bill, loan and salary tracking where nothing leaves the device, and where a storage glitch can never be mistaken for an empty phone and overwrite real data.
The approach
The React user interface runs inside a Capacitor Android shell. The financial engine (payment schedules, salary weeks, payments, backups) runs inside the app, against an in-app SQLite database compiled to WebAssembly.
An in-process router answers the interface’s API calls directly, so there is no network listener at all. The same server-side guards still run for every request.
Every stored file is encrypted with AES-256-GCM under a data key that only the Android Keystore can unwrap, through a small native plugin written in Java.
Amounts are stored as integers in hundredths of a currency unit. The display currency is a setting, not a conversion: the app has no exchange rates.
Architecture
Text alternative: the flow in words
- The React interface sends a request to the in-process router.
- The router enforces the same guards a server would, then calls the financial engine.
- The engine reads and writes an SQLite database in the app.
- Database snapshots are encrypted with AES-256-GCM before they reach app-private storage.
- The encryption key can only be unwrapped by the Android Keystore. The app has no network path.
Interactive demo
Demo with fictional data
A tiny stand-in for the app: mark fictional bills as paid, switch the display currency and preview English and Filipino labels. These strings are illustrative, not the app’s own.
Language
- Weekly salary
- ₱20,000.00
- Bills still to pay
- ₱13,800.00
- Left after unpaid bills
- ₱6,200.00
Only the symbol and number format change. No exchange rates, like the app.
Key technical decisions
No internet permission
The Android manifest removes the INTERNET permission explicitly, in case a library adds it. The strongest privacy control is the absence of a network path.
Fail-safe storage rule
Only a confirmed “file does not exist” counts as missing. Any other read error stops start-up without writing, deleting or setting anything up, so a temporary failure cannot lead to real data being replaced. Files that fail to decrypt are quarantined, never silently replaced.
One engine, two test targets
The engine’s tests run on the phone adapters as well as in Node, so the code that ships is the code that is tested.
Separate test build
The debug build uses its own application id and its own Keystore key, so testing can never touch the release app’s data. The release signing key lives outside the repository.
Bilingual interface, currency preferences
English and Filipino, with an automated translation completeness check in CI. Eighteen display currencies, formatted with the phone’s own locale.
Safety and security notes
- No personal financial data appears anywhere on this site, and none is used in the tests: on-device checks run with made-up data on a separate test package.
- Passphrase rules (10 or more characters, scrypt) are enforced by the in-app engine.
- CI builds an unsigned release APK with a read-only token and no secrets, then checks the release configuration (package id, permissions, backups, exported components, no test code).
Limits and honest caveats
- Single-device by design: there is no sync, so backups are the user’s responsibility.
- Manual entry only. The app deliberately does not import bank data or documents.