ADR-0016: Transaction-captured notification + parse-source tracking
Context
Two related needs surfaced together:
- 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. - 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 istransaction_alerts. Tapping it deep-links to the transaction detail screen via the customautobudget://transaction/{id}scheme handled inMainActivity/AutoBudgetNavHost. Posting is gated by thenotify_on_parsesetting (absent ⇒ enabled, only"false"disables) and only fires on a successful insert (insertreturns row id > 0, so duplicates never re-notify). - Every transaction records its parse source:
ParseSource.JSONorParseSource.REGEX(stabledbValue, stored viaConverters). JSON parses additionally persist the exact{...}payload span inrawJson. Legacy and imported rows default toREGEX. 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/rawJsonadd one indexed-freeTEXTcolumn pair totransactions; migrationMIGRATION_3_4backfills existing rows toREGEX. Exports include them; imports default missing values toREGEX.- 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.