whisper-money/database/factories
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
..
AccountBalanceFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
AccountFactory.php feat(accounts): add loan amortization projections for loan accounts (#246) 2026-03-26 15:06:09 +01:00
AiConsentFactory.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
AutomationRuleFactory.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
BankFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
BankingConnectionFactory.php feat: Coinbase banking integration (#388) 2026-05-13 19:53:30 +02:00
BudgetFactory.php feat(budgets): track multiple categories and labels per budget (#466) 2026-06-01 12:32:23 +02:00
BudgetPeriodFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
BudgetTransactionFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
CategoryCorrectionFactory.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
CategoryFactory.php feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
ExchangeRateFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
LabelFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
LoanDetailFactory.php feat(accounts): add loan amortization projections for loan accounts (#246) 2026-03-26 15:06:09 +01:00
RealEstateDetailFactory.php feat(accounts): add market value and annual revaluation to real estate accounts (#245) 2026-03-26 11:02:20 +01:00
RuleSuggestionFactory.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
SavedFilterFactory.php feat(transactions): save and reuse transaction filters (#496) 2026-06-05 18:00:14 +02:00
SuggestionRunFactory.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
TransactionFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
UserFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
UserLeadFactory.php feat(leads): cohort-based launch invitations with per-user Stripe coupons (#333) 2026-04-30 15:10:28 +01:00
UserMailLogFactory.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
UserSettingFactory.php feat(settings): let users disable bank transactions email (#472) 2026-06-02 12:24:39 +02:00