1.10.0¶
Released: 2026-06-10
Highlights¶
- Expense categories can now carry an icon and be grouped one level deep into subcategories.
- Credit cards are now first-class: track expenses paid on a credit card by selecting it as the expense's payment account.
Added¶
- Expense category icons & subcategories —
ExpenseCategorygains a free-formiconstring and a single-levelparentId, plus anexpenseCategoryTreequery that returns top-level categories with their children. See Expense Category Icons, Subcategories & Credit Cards. CREDIT_CARDaccount type — newAccountType.CREDIT_CARD(a liability, auto-coded in the 2400 range) that can be selected as an expense payment account.
Changed¶
validateExpenseAccountsnow accepts cash, bank, or credit-card accounts for an expense'spaymentAccountId. Customer payments and receipts remain cash/bank only.
Fixed¶
- None.
Migrations¶
In down_revision order (tip was add_recurring_id_to_invoices):
add_icon_to_expense_categories—alembic/versions/20260610_add_icon_to_expense_categories.py(addsexpense_categories.icon).add_parent_id_to_exp_categories—alembic/versions/20260610_add_parent_id_to_expense_categories.py(addsexpense_categories.parent_idFK + index).exp_category_no_self_parent—alembic/versions/20260610_expense_category_no_self_parent.py(NULLs any existing self-parented rows and adds a CHECK constraint forbiddingparent_id = id).
No migration for AccountType.CREDIT_CARD: it is persisted as an integer (IntEnum) and the member is appended, so existing rows are unaffected. No one-off scripts.
Frontend impact¶
- Category icons: send
icon(any string) oncreateExpenseCategory/updateExpenseCategory; read it back onExpenseCategoryandExpenseCategoryLandingPage. Meaning is frontend-defined. - Subcategories: pass
parentIdto nest a category one level under another. The backend rejects nesting under a category that already has a parent, re-parenting a category that already has children, and self-parenting. UseexpenseCategoryTreefor grouped lists;childrenholds a category's subcategories. - Credit cards: create one via
createAccountwithaccountType: CREDIT_CARD, then select it as an expense'spaymentAccountId.
Versioning notes¶
- Bumped with
uv run python scripts/bump_version.py 1.10.0 --changelog-stub. - MINOR (additive schema only) — no deploy-order constraint beyond applying the two expense-category migrations.