whisper-money/app/Http/Controllers
Víctor Falcón 8013a0b6f2
feat(ai): auto-categorize transactions with AI (behind flag) (#535)
## What

Auto-categorizes transactions with AI (Gemini) for **pro +
AI-consented** users when no automation rule already matched. Ships the
full backend **behind a Pennant flag, off by default**, so it's
mergeable and testable in isolation; the UI is a deliberate follow-up.

## Why / cost

Prod check first: ~20k txns/month, **~52% of pro-user transactions are
uncategorized** after rules. At Gemini Flash-Lite rates the cost is a
**rounding error** — ~$0.13–$0.75/month for all pro users, single-digit
dollars even on full Flash. So the model is chosen for accuracy, not
price; the real constraints are trust, accuracy and privacy.

## How it works

**Two tiers** (every transaction is covered, rules are an optimization
on top):
- **Tier 1 – label** — a queued listener runs *after* the synchronous
rules; if still uncategorized and the user is eligible, the model picks
a **leaf** category (referenced by numeric index, never a UUID, so it
can't hallucinate one). Auto-applied only above the **label bar**
(`0.7`); below → left blank, no nag. Tagged `category_source = ai` +
`ai_confidence`, fully reversible.
- **Tier 2 – learn** — above the higher **rule bar** (`0.85`) *and* a
clean merchant key *and* the model flags the merchant unambiguous → the
merchant is appended to a single **ai-owned** automation rule for that
category (OR'd conditions, not rule-sprawl), so future transactions
match for free and consistently. AI rules sit at the lowest priority;
**user-owned rules are never touched**.

**Self-heal + signal** — when a user overrides an AI category, a
`category_correction` is logged (calibration signal, bucketable by
confidence) and the offending merchant condition is dropped from the ai
rule (deleted if empty). User rules and manual categories are untouched.

**Safety** — config kill switch + pro + active consent + gradual Pennant
rollout. Dedicated `ai` queue so Gemini never blocks bank syncs.
Encrypted (client-side) transactions are never sent.

**Backfill** — `ai:categorize-backfill {user}`, explicit opt-in,
batched, learns rules as it goes.

## Data model

- `transactions`: `category_source`, `ai_confidence`,
`categorized_by_rule_id`
- `automation_rules`: `origin` (`user`/`ai`)
- new `category_corrections` table

## Screenshots

<img width="921" height="384" alt="image"
src="https://github.com/user-attachments/assets/f04c2a03-b39e-4a3d-81eb-ecf26eaefb83"
/>
2026-06-15 16:35:20 +02:00
..
Ai feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
Api fix(cashflow): bound trend window to prevent request timeout (#534) 2026-06-15 12:47:27 +02:00
Auth fix: verify email via signed link without requiring login (#490) 2026-06-05 10:01:32 +02:00
OpenBanking feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
Settings fix(account): block deletion while subscription or trial is active (#531) 2026-06-14 20:46:44 +02:00
Sync refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
AccountBalanceController.php feat: investment benefits — show gains/losses on investment accounts (#140) 2026-02-23 13:59:10 +01:00
AccountController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
BudgetController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
CashflowController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
Controller.php Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
DashboardController.php feat: expand parent categories inline in breakdowns (#486) 2026-06-04 11:19:21 +02:00
EncryptionController.php Remove unused controllers and routes (#11) 2025-12-04 08:48:17 +01:00
LoanDetailController.php feat(loans): backfill historical balances on loan creation (#322) 2026-04-24 13:09:34 +01:00
OnboardingController.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
ReEvaluateTransactionRulesController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
RealEstateDetailController.php feat(accounts): add real estate asset tracking (#241) 2026-03-24 10:21:32 +00:00
RobotsController.php User Onboarding Flow (#23) 2025-12-12 13:06:08 +01:00
SitemapController.php SEO landing page 2025-11-25 11:33:11 +01:00
SubscriptionController.php fix: allow managing canceled connections (#417) 2026-05-22 10:52:50 +01:00
TransactionController.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
UserLeadController.php feat: verify waitlist leads (#285) 2026-04-14 11:26:01 +01:00