Skip to content

Add category and tag management on a new Labels tab - #17

Merged
LouisBenjamin merged 2 commits into
mainfrom
feature/categories-and-tags
Sep 2, 2026
Merged

Add category and tag management on a new Labels tab#17
LouisBenjamin merged 2 commits into
mainfrom
feature/categories-and-tags

Conversation

@LouisBenjamin

Copy link
Copy Markdown
Owner

Summary

Categories already existed as a table (icon column + all) but were read-only in the app, and expense rows showed a hardcoded receipt icon regardless of category. Tags — a keyword that auto-assigns a category, e.g. "COSTCO" → Groceries — are exactly the merchant_rules the statement importer already had, just without a home outside the import flow.

  • Labels tab: new fourth tab on the group screen (Expenses / Balances / Members / Labels) with full CRUD for categories and tags. Global categories render read-only with a "Default" chip; group categories are editable/deletable.
  • Tags = merchant_rules: no new table — the Labels tab is a second UI over the same data statement import has always used. MerchantRulesScreen is retired; /import/rules now redirects to Labels.
  • Migration 0012_categories.sql: category FKs go ON DELETE SET NULL (a category can now be deleted without an FK violation or orphaning data), unique category names per group, and the 10 global categories are re-seeded with Phosphor icon slugs.
  • lib/core/icons.dart: the app's new icon vocabulary, built on phosphor_flutter (MIT). kCategoryIcons backs the category picker, _legacyIconAliases keeps pre-migration Material icon names resolving, categoryTint/onCategoryTint give each category a deterministic colour with no colour picker needed, and AppIcons holds semantic constants for app chrome. Every Icons.* call site in lib/ moved to it — confirmed via flutter build web --tree-shake-icons.
  • Expense rows now show the category's icon (on its tint) and name, instead of a fixed receipt icon for every row.
  • Add-expense autofill: new matchTagCategory runs the same tag-matching precedence import review uses, live as you type a description, and never overrides a category you picked by hand.
  • Docs: updated docs/statement-import.md, added docs/categories-and-tags.md, updated the README project-structure listing.

Note: this branches off main (commit 89f8693), independent of the in-flight docs/readme-statement-import PR — the two touch overlapping README sections and whichever merges second will need a small rebase.

Testing

  • flutter analyze — clean
  • flutter test — 175/175 passing (updated screens_smoke_test.dart for the 4th tab, retargeted MerchantRulesScreen tests to LabelsScreen, added matchTagCategory unit tests and a new labels_tab_test.dart)
  • flutter build web --tree-shake-icons — succeeds, Phosphor + Material fonts tree-shake correctly

Follow-ups (out of scope here)

  • add_recurring_screen.dart doesn't get the tag-autofill treatment yet, to keep this diff reviewable.
  • No colour picker — category avatars use a deterministic tint derived from the category id.

🤖 Generated with Claude Code

Categories were already a table with an icon column but were read-only
in the app — no create/rename/delete path, and expense rows rendered a
hardcoded receipt icon regardless of category. Tags (a keyword that
auto-assigns a category, e.g. "COSTCO" -> Groceries) are exactly the
merchant_rules the statement importer already had, just missing a home
outside the import flow.

- Add a Labels tab to the group screen (Expenses/Balances/Members/Labels)
  with full category CRUD and tag CRUD, reusing merchant_rules as tag
  storage instead of introducing a parallel table.
- Retire MerchantRulesScreen; /import/rules now redirects to Labels.
- Migration 0012: category FKs go ON DELETE SET NULL so a category can
  be deleted without orphaning expenses; unique category names per
  group; re-seed the 10 global categories with Phosphor icon slugs.
- Add lib/core/icons.dart: the app's Phosphor icon vocabulary
  (phosphor_flutter, MIT) — kCategoryIcons for the picker, legacy
  Material-name aliases, deterministic per-category tint colors, and
  AppIcons semantic constants. Every Icons.* call site in lib/ moved
  to it.
- Expense rows now show the category's icon and name instead of a
  fixed receipt icon.
- Add matchTagCategory: the Add-expense form autofills a category from
  tags as you type a description, the same precedence import review
  uses, and never overrides a category picked by hand.
- Update statement-import.md, add categories-and-tags.md, update the
  README project-structure listing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzXWJsUFffSSJAKGaRqUT4
@LouisBenjamin
LouisBenjamin force-pushed the feature/categories-and-tags branch from a363f81 to 729d60a Compare September 2, 2026 01:21
The `stable` channel moved to a Flutter release that marks `IconData` as a
final class. phosphor_flutter 2.1.0 (last published two years ago) extends
`IconData`, so dart2js and `flutter test` both fail to compile on the newer
toolchain while everything still builds on the 3.41.9 used locally.

Pin all three workflows to 3.41.9 to make CI reproducible and match local
dev. Revisit the pin when phosphor_flutter is replaced with a maintained
icon dependency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzXWJsUFffSSJAKGaRqUT4
@LouisBenjamin
LouisBenjamin merged commit 9642693 into main Sep 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant