Skip to content
All projects
Source on GitHubStill in active developmentSolo developer, personal projectJun 2026 – present

HitungUang

An offline-first Android expense tracker that keeps everything on the device: no account, no server, no sync. Receipt scanning and charts run locally.

HitungUang
KotlinJetpack ComposeDagger HiltRoom DBDataStoreWorkManagerGoogle ML Kit

The problem

Most expense trackers ask you to create an account and upload your spending history to someone else's server, and then still need a connection to open. I wanted to know whether a useful version could exist with no server in the picture, and what that costs you in return.

What I set out to build

Build a finance app that works with airplane mode on permanently, keeps every record on the device, and still makes entering a transaction fast enough that I would actually keep using it.

Approach

A native Compose app on Room, with the whole feature set built around local-only storage. ML Kit reads receipt text on-device and pre-fills a transaction the user confirms or corrects before saving. Charts are drawn directly with Canvas rather than pulling in a charting library. WorkManager handles background maintenance, and backup and restore go through a ZIP archive so the user owns their data.

Overview

A native Android personal finance app with no backend at all. Transactions live in Room on the device, the app locks behind a PIN or biometrics, receipts are scanned with on-device OCR, spending charts are drawn with Compose Canvas, and backups export to a ZIP file the user controls. Not published to the Play Store, but the source is on GitHub and I am still building on it.

Architecture

Feature-first Clean Architecture with a domain layer between the Compose UI and Room. Dagger Hilt for dependency injection, Room with KSP for the local database, DataStore for preferences, WorkManager for scheduled work, ML Kit for on-device text recognition, and AndroidX Biometric for the app lock.

What shipped

  • Fully functional with no network permission needed: Room for storage, PIN and biometric lock, and no account to create.
  • On-device receipt scanning through ML Kit, with the parsed result always shown for confirmation before it is saved.
  • Backup and restore as a user-held ZIP archive, with schema migrations covered by tests so an import cannot silently drop records.

Hard parts & trade-offs

  • OCR output is unstructured text, not fields. Mapping a receipt to an amount and a merchant needed heuristics, and the honest fix was to always show the parsed result for the user to correct rather than trusting it.
  • Custom Canvas charts avoid a dependency but you own hit-testing, labels, and accessibility yourself. A library would have been the right call if the charts needed to do any more than they do.
  • With no server, a bad database migration means permanently lost data. Migration tests mattered more here than anywhere else I've worked.

What I learned

  • Room's FTS4 indexes made local search fast enough that I stopped thinking about it, which is the point.
  • Compose Canvas is genuinely pleasant for simple charts, and clearly the wrong tool the moment interaction gets complicated.
  • Offline-first shifts the risk from the network to your migrations. That trade is worth making, but you have to actually pay for it in tests.

What's next

  • 1CSV import and export, so records can be moved in and out without going through the ZIP backup.
  • 2Recurring transactions and per-category budgets.
  • 3Publish a signed build so it can be installed without cloning the repo.