Skip to content

ADR-0016: Transaction-captured notification + parse-source tracking

  • Status: Accepted
  • Date: 2026-08-12
  • Deciders: maintainers
  • Related: ADR-0001, ADR-0004

Context

Two related needs surfaced together:

  1. When the pipeline automatically turns a bank alert into a transaction, the user has no signal inside the app that a new transaction landed. The app is a notification consumer (a NotificationListenerService) and posts no notifications of its own.
  2. Transactions carry no record of how they were parsed. The parser has two paths — an embedded structured JSON payload (Maybank/MAE) and regex rules over the prose — but that provenance is not persisted, and the raw JSON payload is not kept, so it cannot be audited, re-parsed, or exported.

Decision

  • The app posts a silent notification (IMPORTANCE_LOW, no sound, no heads-up) whenever a notification is parsed into a transaction. The channel is transaction_alerts. Tapping it deep-links to the transaction detail screen via the custom autobudget://transaction/{id} scheme handled in MainActivity/AutoBudgetNavHost. Posting is gated by the notify_on_parse setting (absent ⇒ enabled, only "false" disables) and only fires on a successful insert (insert returns row id > 0, so duplicates never re-notify).
  • Every transaction records its parse source: ParseSource.JSON or ParseSource.REGEX (stable dbValue, stored via Converters). JSON parses additionally persist the exact {...} payload span in rawJson. Legacy and imported rows default to REGEX. Both fields round-trip through CSV/JSON export.

Consequences

  • Users get immediate, silent feedback that a transaction was captured, without disturbing sound/interruption settings. Disable in Settings → Automation → "Notify on capture".
  • Notification tap works on cold start, warm start (onNewIntent), and behind the app lock (the detail screen is revealed once unlocked).
  • parseSource/rawJson add one indexed-free TEXT column pair to transactions; migration MIGRATION_3_4 backfills existing rows to REGEX. Exports include them; imports default missing values to REGEX.
  • Raw JSON contains sensitive card/account data but is stored in the same encrypted DB as everything else and is never transmitted.

Alternatives considered

  • Always-on notification with sound — rejected: transactions are high frequency; a silent tray entry is the least intrusive useful signal.
  • Grouping notifications by day — rejected: one notification per transaction keeps tap targets unambiguous; grouping can be added later.