Mudassir
All Projects

Koin

A smart expense tracker that auto-detects and categorizes Indian transactions in real time.

RoleSolo Developer
TimelineJan 2025 — Mar 2025
Stack
React NativeExpoTypeScriptReact NavigationMMKVFirebase FirestoreFirebase Authexpo-local-authenticationEAS BuildAndroid Native Modulesexpo-clipboardexpo-crypto

The Challenge

The core challenge was building a zero-friction expense detection system that works across Android and iOS without any server infrastructure. The naive approach would have been a simple form-based logger — but users abandon those within days. The real problem was intercepting transactions the moment they happen, whether from an SMS, a push notification, or an image shared from a banking app. On Android, this required writing custom native modules in Java to tap into SMS broadcasts and notification listeners — two separate permission-gated channels that each needed their own bridge to React Native's JS layer. Synchronizing these async native events with the app's local-first MMKV state without creating race conditions or duplicate entries was a non-trivial concurrency problem. The second hard problem was categorization accuracy. A naive keyword lookup would misfire constantly — Amazon could be shopping, groceries, or streaming. The solution was a 7-tier priority pipeline: user corrections → app source detection → UPI VPA analysis → context-weighted regex → keyword matching → transfer detection via Indian name patterns → fallback. Each tier gates the next, ensuring the system learns from corrections and respects intent signals over surface-level text.

Architectural Decisions

storage

MMKV over AsyncStorage for local-first persistence

React Native default AsyncStorage is async and JS-thread-bound, creating lag on every read during app startup and list rendering. MMKV provides synchronous reads via a C++ JSI bridge, making it 10-30x faster. This enabled a local-first architecture where the app renders instantly from local data, then optionally syncs to Firebase in the background — no loading spinners on the critical path.

category

7-tier smart categorization pipeline

A flat keyword lookup fails on ambiguous merchants like Amazon or Reliance. The pipeline was designed with explicit priority ordering: learned user overrides always win, followed by app-source detection, UPI VPA string analysis, context-weighted regex on full transaction text, merchant keyword map, Indian name pattern detection for personal transfers, and finally a safe fallback.

sensors

Android native modules for dual-channel transaction detection

Two separate native Java modules were written — one for SMS broadcast receivers and one for notification listeners — because no single cross-platform library handled both reliably. Using Expo bare workflow allowed mixing managed Expo APIs with custom native code. This dual-channel approach means the app catches transactions from banking apps that send SMS AND from UPI apps that only show notifications.

cloud_sync

Firebase anonymous authentication for cloud sync

Requiring user sign-up creates abandonment friction in a personal finance app. Firebase anonymous auth was chosen to give every device a persistent, unique identity without email/password — enabling full cloud sync across reinstalls. The anonymous ID is stored in MMKV and reused, so users retain their transaction history even after reinstalling.

share

Share intent bridge for cross-app transaction capture

iOS does not allow background SMS access, so an alternate capture path was needed. The share intent bridge lets users share bank notification screenshots or transaction texts directly to Koin from any app. A unified parseKoinURL() function normalizes both paths, keeping the downstream categorization logic identical.

Impact

7-tier
categorization pipeline
9+
Indian payment apps auto-detected
500+
merchant keywords mapped
3
transaction detection channels
Next Project

Cloud Kitchen — Order Management