Salli keeps financial behavior on the device and separates deterministic domain logic from storage, native capabilities, and presentation.

Core

Money wraps integer minor units. Wallet-currency helpers preserve native values and explicit LKR conversion evidence. Formatting occurs at the UI edge.

Domain

Pure Dart entities and use cases implement:
  • transactions and analytics;
  • Safe to Spend and payday cycles;
  • budget rollover and insights;
  • seettu schedules;
  • reminder planning;
  • runway forecasts; and
  • local intelligence records.
Domain code does not depend on Flutter widgets or SQLite.

Data

  • Drift tables and migrations.
  • SQLCipher device-store factory.
  • JSON personal backup and CSV export.
  • Android SMS gateway, parser, classifier, deduplication, and evidence queues.
  • Local merchant corpus and package validation.
  • Receipt image/OCR adapters.
  • Local notification adapters.
  • Reference exchange-rate adapter with minimized request fields.

Application

Riverpod exposes one hydrated AppState and intent-style notifier methods. Writes are serialized through the store. Optimistic state updates keep screens reactive, while persistence tests verify restart hydration.

Presentation

The shell uses an indexed stack for Home, Activity, Insights, and More. Standard Navigator routes open full screens; modal sheets handle focused editing and review. The Ledger theme supplies colors, typography, radii, spacing, and Android’s classic variant.

Native Android

Kotlin components handle:
  • SMS_RECEIVED;
  • permission and inbox backfill channels;
  • background one-shot processing;
  • sender policy;
  • notification delivery;
  • reboot restoration; and
  • the home-screen widget.
Native code passes bounded data to Dart rather than duplicating financial logic.

No production backend

Cloud sync, family sharing, billing, remote AI, and a signed corpus/template service are deferred. The current app has no backend dependency.