whisper-money/app/Models
Víctor Falcón 1cc10566a3
feat: parent/child category tree (#474)
## Summary

Adds nested categories (parent → child, up to **3 levels**) across the
app. Children inherit their parent's type and cashflow direction, and
every category selector now renders the hierarchy as an indented tree.
Gated behind the `CategoryTree` Pennant flag (off by default).

## Backend

- **Migration**: nullable self-referencing `parent_id`; uniqueness
scoped per-parent via a `parent_unique_marker` virtual column (root
names stay unique). New composite unique created before dropping the old
one so the `user_id` FK keeps a supporting index.
- **`CategoryTree` service**: descendant/ancestor resolution, depth &
cycle checks, type cascade, subtree deletion.
- **Validation**: depth limit, cycle prevention, inherited + locked
child type.
- **Delete strategies**: reparent (default), promote to root, or cascade
(uncategorizes affected transactions).
- **Transaction filter** expands a selected parent to its descendants.
- **Cashflow Sankey & breakdown** roll up to top-level parents with
click-to-drill (children + a parent "direct" node).
- **Budgets** tracking a parent also count their children's
transactions.
- **Unified** the frontend category query behind
`Category::forDisplay()` / `FRONTEND_COLUMNS` (8 call sites) so every
selector receives the full Category shape, including `parent_id`.

## Frontend

- New `category-tree.ts` helpers (build/flatten/descendants/path,
tree-aware selection toggle + tri-state).
- **Settings page**: indented tree, sortable by name/color/type
(siblings sorted, hierarchy preserved), parent picker, delete-strategy
dialog.
- **Combobox** (transaction table cell + edit/create modal + parent
picker): indented tree, search keeps matches with their ancestors.
- **Transaction filter**: indented tree, tri-state cascading selection
(parent ↔ children), themed checkboxes, selected branches float to top
on open, ancestor-aware search.
- **Categorizer palette** and **budget multi-select**: same indented
tree + ancestor-aware search.
- **Sankey**: click a parent node to drill into its children, with
breadcrumb.
- Pennant `CategoryTree` flag gates the parent UI.

## Tests

- Pest: model/validation, delete strategies, filter expansion, cashflow
rollup/drill, budget child inclusion.
- Vitest: tree-aware selection logic.
- All green; Pint / ESLint / Prettier clean.

## Rollout

Flag is off by default — enable per user with:
\`\`\`
php artisan feature:enable "App\\Features\\CategoryTree" you@example.com
\`\`\`
2026-06-03 19:30:12 +02:00
..
Account.php feat(accounts): add loan amortization projections for loan accounts (#246) 2026-03-26 15:06:09 +01:00
AccountBalance.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
AutomationRule.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
AutomationRuleLabel.php feat: add transaction labels feature (#24) 2025-12-13 13:02:19 +01:00
Bank.php refactor(banks): add Bank::availableForUser scope (#480) 2026-06-03 17:59:24 +02:00
BankingConnection.php feat: Coinbase banking integration (#388) 2026-05-13 19:53:30 +02:00
BankingSyncLog.php fix(banking): retry failed sync connections and log every sync attempt (#251) 2026-03-31 11:34:35 +01:00
Budget.php feat(budgets): track multiple categories and labels per budget (#466) 2026-06-01 12:32:23 +02:00
BudgetPeriod.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
BudgetTransaction.php fix(static-analysis): clear phpstan-baseline by fixing all suppressed errors (#183) 2026-03-02 12:22:30 +00:00
Category.php feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
EncryptedMessage.php fix(static-analysis): clear phpstan-baseline by fixing all suppressed errors (#183) 2026-03-02 12:22:30 +00:00
ExchangeRate.php Preload exchange rates (#362) 2026-05-06 16:35:49 +01:00
Label.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
LabelTransaction.php feat: add transaction labels feature (#24) 2025-12-13 13:02:19 +01:00
LoanDetail.php feat(accounts): add loan amortization projections for loan accounts (#246) 2026-03-26 15:06:09 +01:00
RealEstateDetail.php feat(accounts): add loan amortization projections for loan accounts (#246) 2026-03-26 15:06:09 +01:00
Transaction.php feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
User.php feat(settings): let users disable bank transactions email (#472) 2026-06-02 12:24:39 +02:00
UserLead.php feat(leads): add user lead re-invite campaign (#432) 2026-05-26 08:35:31 +02:00
UserMailLog.php feat: Send custom emails to users (#52) 2026-01-09 09:33:19 +01:00
UserSetting.php feat(settings): let users disable bank transactions email (#472) 2026-06-02 12:24:39 +02:00