Free, ad-free, open-source expense tracker for Android and iOS with: multi-item entries, a broad category catalogue, on-device bank SMS parsing (Android), Splitwise-style groups, budgets, encrypted backup and (next) encrypted cloud sync.
| Layer | Choice | Why |
|---|---|---|
| UI | Flutter 3.47, Material 3, light + dark via ThemeMode |
One codebase, native performance on both platforms, built-in dark mode |
| State | Riverpod 3 | Compile-safe providers, stream-friendly, testable without widgets |
| Navigation | go_router with StatefulShellRoute |
Bottom tabs keep state; deep links (hisab://) for free |
| Storage | Drift (SQLite) | Reactive queries, typed schema, migrations |
| Charts | fl_chart | Pure Dart, no platform views |
| Crypto | cryptography (AES-256-GCM, PBKDF2) |
Pure Dart, same bytes on both platforms |
lib/core money, dates, ids, theme, icons, settings, providers
lib/domain pure logic, no Flutter: split calculator, debt simplifier, SMS parser,
categorizer, category catalogue, budget math, backup codec (unit-tested)
lib/data Drift schema, repositories, SMS ingest, backup service
lib/features one folder per screen: dashboard, transactions, expense_editor,
categories, groups, split, sms, budgets, accounts, settings, shell
android/.../MainActivity.kt SMS inbox + live receiver platform channel
Rule: anything that can be a pure function lives in lib/domain with a test.
- accounts bank / card / wallet / cash,
smsKey(bank:ac:1234) links SMS to an account - categories seeded from
category_catalog.dart(18 expense groups, 100+ subcategories, 13 income, 5 transfer); user-editable;unitsper category for item entry - entries expense / income / transfer;
sourcemanual | sms | import; optionalgroupId - entry_items name, quantity, unit, unit price → remembered-item suggestions per category
- groups, members, splits, settlements Splitwise model; balances computed, never stored
- entry_payers who paid what when several members paid one group expense; empty for a
single payer, and
entries.paidByMemberIdkeeps the biggest payer as the main one - reminders generic reminder log (kind, group, member, channel, sent time); settle-up reminders use it today
- group_activities append-only log of who added, edited, deleted or restored which group expense or payment, and when, with JSON snapshots of the state before and after; it backs the activity feeds and restoring a deleted expense with its exact split and payer rows
- budgets overall or per category, monthly
- sms_log every parsed SMS with status pending | added | ignored | skipped (dedupe by hash)
| Feature | Hisab | FinArt | Walnut/Axio | Splitwise | Money Manager |
|---|---|---|---|---|---|
| Free, no trial, no ads | ✅ | ❌ (trial) | ❌ | partial | ads |
| Multi-item entries with qty/unit/price + memory | ✅ | ❌ | ❌ | ❌ | ❌ |
| 100+ categories, editable, archivable | ✅ | ✅ | ✅ | ❌ | ✅ |
| SMS auto-tracking, on-device | ✅ Android | ✅ | ✅ | ❌ | partial |
| Review inbox before adding | ✅ | ✅ | ✅ | – | – |
| Balance from bank SMS | ✅ | ✅ | ✅ | – | – |
| Groups: equal / exact / % / shares / adjustment / by item | ✅ | ❌ | partial | ✅ | ❌ |
| Simplify debts | ✅ | – | – | ✅ | – |
| Budgets with pace indicator | ✅ | ✅ | ✅ | – | ✅ |
| Salary-month cycle | ✅ | ❌ | ❌ | – | ✅ |
| Encrypted backup | ✅ | ❌ | ❌ | – | plain |
| iOS SMS workaround (Shortcut → URL) | ✅ | ❌ | ❌ | – | – |
| Works offline, no account | ✅ | ❌ | ❌ | ❌ | ✅ |
SmsChannel.readInbox(since)(Android) or pasted/Shortcut text (any platform)looksLikeBankSender+ financial-keyword gate drops personal/promo SMS before storageparseBankSms→ amount, direction, instrument, account, balance, counterparty, referencesuggestCategoryKeykeyword rules → category- Account auto-created from
accountKey; reported balance applied if newer SmsLogrow: pending (review inbox) or added (auto-add on)- Manual entries adjust account balance; SMS entries do not (bank already reported it)
Principle: the server never sees plaintext. Reuse backup_codec (AES-256-GCM, key from
passphrase via PBKDF2, 200k iterations). Key is held in the platform keystore.
- Android: Google Drive
appDataFolder(drive.appdatascope, hidden from the user's Drive, deleted with the app). Sign in withgoogle_sign_in. - iOS: CloudKit private database (
cloud_kit/icloud_storage), no sign-in UI needed. - Format: one encrypted blob per table per device plus a change log of rows since the last
push (
updatedAt > lastSync). Merge rule: last-writer-wins byupdatedAt, tombstones viadeletedAt. This is exactly whatBackupService.importSnapshotalready does. - Cross-platform: a user moving Android → iOS restores from an encrypted backup file; Drive ↔ iCloud bridging is out of scope.
No backend at all (owner, 2026-10-24). This supersedes the earlier Firebase/Supabase relay
idea. A shared group lives in one shared Google Drive file in the group owner's own
Drive (drive.file scope), holding an append-only encrypted event log; members merge by
union of event ids with last-writer-wins on edits, and balances are replayed from the log. The
group key travels in the invite link fragment (hisab:///join?g=<fileId>#k=<key>), never to any
server. Full design, invite flow, trade-offs, and the mandatory Drive-permission consent copy
are in SYNC_SHARING.md — the authoritative spec for sync and sharing.
- Settings → "Back up to Google Drive" → consent screen → upload one encrypted blob.
- Incremental row sync for personal data.
- Shared groups: per-group shared Drive file with an append-only log and invite links.
Full study in REFERENCE_APPS.md. Already in the app:
- Dashboard leads with "spent this month" and account balances (FinArt, Walnut).
- Review inbox with Add / Edit / Ignore per SMS (FinArt) behind a PennyWise-style disclosure.
- Day-grouped entries list with day totals (Money Manager).
- Six split methods and settle-up suggestions with "record payment" (Splitwise), by-item assignment (Cashew).
- Salary-month start day (Money Manager, Axio).
- No login, no paywall, works offline (the opposite of axio and Splitwise).
- Recurring entries and reminders
- CSV / PDF statement import
- Home-screen widget and quick-add notification
- Receipt photos (needs camera permission; deliberately deferred)
- Cloud sync as above
- Hindi and Spanish dictionaries (framework ready, see LOCALIZATION.md)
- Calculator keypad, save-and-add-another, merchant autocomplete, smart rules (see REFERENCE_APPS.md backlog)