# Feature Batch 2 Design - 16 Features

Date: 2026-03-03

## Overview

16 features sourced from Reddit community research on personal finance app wishlists, filtered against Outlay's existing feature set.

## Features

### 5. Custom Budget Cycle

Users can choose how budget periods are defined:

- **Calendar month** (default, current behavior): 1st to last day of month
- **Payday offset**: budget runs from day X to day X-1 of next month (e.g. 15th to 14th)
- **Rolling N-day**: budget period is a fixed window of N days from a configurable start date

New settings: `budget_cycle_mode` (calendar/payday/rolling), `budget_cycle_start_day` (1-31), `budget_cycle_days` (e.g. 30).

Affects: Budgets view period labels ("Mar 15 - Apr 14"), navigation step size, all budget queries, safe-to-spend calculation, and budget threshold notifications. Charts and History remain calendar-month based to avoid confusion.

Cycle configuration accessible via a gear icon popover next to the month nav in Budgets view.

### 6. Bulk Transaction Operations

Selection mode in History view:

- "Select" button in header bar activates selection mode
- Checkboxes appear on each transaction row
- Long-press also enters selection mode
- Action bar: "Delete (N)", "Recategorize", "Tag", "Select All", "Cancel"
- Delete shows confirmation dialog with count
- Recategorize opens a category picker, applies to all selected
- Tag opens a multi-select tag picker, applies to all selected

### 7. Monthly/Yearly Recap

Part of the new Insights view (see below). Toggle between "This Month" and "This Year".

Monthly recap: total income, expenses, net, transaction count. Per-category rows showing amount, percentage of total, and change vs previous month with directional arrows.

Yearly recap: month-by-month summary with sparklines, year-over-year comparison.

"Share as PDF" button reuses existing PDF export.

### 8. Natural Language Entry

Dedicated smart entry bar at the top of Log view and in Quick Add popup.

`adw::EntryRow` titled "Quick entry" with placeholder "e.g. Coffee 4.50 at Starbucks".

Parser (`outlay-core/src/nlp.rs`):
- `parse_transaction(input, categories) -> Option<ParsedTransaction>`
- Extracts amount (required), category (fuzzy match), note, payee (after "at"/"from"/"to")
- Patterns: "Coffee 4.50", "Lunch 12.50 at Subway", "4.50 groceries milk", "$25 gas"

Preview row shows parsed result below the entry. Press Enter to save. Existing detailed form remains below for manual entry.

### 9. Sankey Diagram

New section in Charts view after existing charts. Title: "Money Flow".

Cairo-drawn Sankey layout:
- Left nodes: income categories
- Right nodes: expense categories
- Center node: "Available" (net)
- Flow widths proportional to amounts
- Income flows colored green, expense flows use category colors
- Hover shows amount labels

Layout computation in `outlay-core/src/sankey.rs`:
- `compute_sankey_layout(income_sources, expense_categories) -> SankeyLayout`
- Returns node positions and bezier curve control points

Month navigation synced with other charts.

### 10. What-If / Sandbox Mode

Toggle button in Budgets view header bar.

When active:
- Header tinted amber, label shows "Sandbox Mode"
- All budget amounts become inline-editable
- Changes stored in temporary `HashMap<i64, f64>`, NOT written to DB
- Progress bars and safe-to-spend recalculate live
- Modified rows get a visual indicator
- "Apply Changes" button writes sandbox values to DB
- "Discard" button exits sandbox, reverts to real data

### 11. Tags UI

Database tables already exist (`tags`, `transaction_tags`). Need GTK surfaces:

- History view: tag chips in FlowBox alongside category chips (different visual style - outlined vs filled). Clicking a tag chip filters to transactions with that tag.
- Log view: tags already have an entry field. Ensure it works with `get_or_create_tag()` and `set_transaction_tags()`.
- Edit dialog: show and edit tags on existing transactions.
- Bulk operations: "Tag" action in selection mode.

### 12. Transaction Splits UI

Database tables already exist (`transaction_splits`). Need GTK surfaces:

- Log view / Edit dialog: "Split" toggle button next to category row
- When enabled: category row replaced by split list
- Each split row: category dropdown + amount entry + optional note
- "Add Split" button for more rows
- Validation: split total must equal transaction amount ("Remaining: X.XX" label)
- On save: `insert_splits()` called after transaction insert
- Edit dialog: if `has_splits()`, pre-fills split rows

### 13. Transaction Templates UI

Database tables already exist (`transaction_templates`). Need GTK surfaces:

- Log view: "Templates" icon button in header opens a popover
- Lists saved templates as `adw::ActionRow` items (name, amount, category icon, type badge)
- Tapping a template fills the log form
- "Save as Template" button at bottom of form when amount + category are filled
- Opens dialog for template name, saves via `insert_template()`

### 14. Auto-Categorization Rules UI

Database tables already exist (`categorization_rules`). Need GTK surface in Settings:

- New "Categorization Rules" `adw::PreferencesGroup` between Categories and Import/Export
- Each rule: `adw::ActionRow` showing field (Note/Payee), pattern, target category
- "Add Rule" button opens dialog: field dropdown, pattern entry, category dropdown, priority spinner
- Delete button per row
- Rules applied during import and optionally during manual entry

### 15. Searchable Category Picker

Replace all `adw::ComboRow` category dropdowns with a searchable version:

- Custom `gtk::FilterListModel` backed by `gtk::StringFilter`
- Search entry at top of dropdown popup
- Typing filters category list in real-time
- Shared utility: `fn make_searchable_category_combo(...) -> adw::ComboRow`
- Used in: log view, edit dialog, budget dialog, quick add, split rows, rules dialog

### 16. PDF Bank Statement Import

New "PDF" import button in Settings alongside existing importers.

Two-phase extraction (`outlay-core/src/import_pdf.rs`):
1. Text extraction via `pdf-extract` crate - look for tabular date/description/amount patterns
2. If no extractable text found, fall back to existing Tesseract OCR pipeline

Preview dialog shows extracted transactions in an editable list. Each row: date, description, amount, category (auto-matched via categorization rules, fallback "Uncategorized"). Import All / Import Selected buttons. Merge/replace mode toggle.

New dependency: `pdf-extract` crate.

### 17. Spending Streaks / Gamification

Dedicated Insights view (new sidebar item) with three sections:

**Streaks:**
- No-spend streak: consecutive days with zero expenses, flame icon, "Best: X days"
- Under-budget streak: consecutive months staying under total budget cap
- Savings streak: consecutive months with goal contributions

**Achievements:**
- Grid of achievement badges, earned ones colored, unearned dimmed
- Starter set: "First Transaction", "7-Day No-Spend", "30-Day No-Spend", "Month Under Budget", "3 Months Under Budget", "First Goal Completed", "100 Transactions", "Budget Streak 6mo"
- Checked and awarded on app launch

New tables: `streaks`, `achievements`.

### 18. Financial Goal Projections

Enhance existing Goals view:

- Each active goal row gets subtitle: "At current rate, reachable by [date]"
- Based on average monthly contributions over last 3 months
- States: "On track - X months ahead", "Behind schedule - need X.XX/month", "Start contributing to see projection"
- Expandable section per goal: mini line chart showing saved amount over time with projected line to target

### 19. Credit Card Billing Cycle Tracking

Dedicated Credit Cards view (new sidebar item).

**Summary card:** total balance, total limit, utilization bar, next due date.

**Card list:** each card is `adw::ExpanderRow`:
- Collapsed: name, balance, due countdown, utilization mini-bar
- Expanded: statement close date, minimum payment, payment history (last 3 months)
- Actions: "Record Payment" (creates expense transaction, reduces balance), Edit, Delete

New table: `credit_cards` (name, credit_limit, statement_close_day, due_day, min_payment_pct, current_balance, currency, color, active).

### 24. Spending Anomaly Alerts in UI

Surface existing `detect_anomalies()` in two places:

- **History view:** `adw::Banner` at top when anomalies exist for the displayed month: "N spending insights for this month". Tapping navigates to Insights view.
- **Insights view:** Anomaly Alerts section renders each anomaly as `adw::ActionRow` with warning/info icons. Clickable to navigate to category in History.
- **Startup:** toast on first launch of the day if current month has insights.

## Schema Migration (v8 -> v9)

New table: `credit_cards` - see feature #19 above.
New table: `streaks` - see feature #17 above.
New table: `achievements` - see feature #17 above.
New settings: `budget_cycle_mode`, `budget_cycle_start_day`, `budget_cycle_days`.

## New Files

- `outlay-core/src/nlp.rs` - natural language transaction parser
- `outlay-core/src/import_pdf.rs` - PDF statement import
- `outlay-core/src/sankey.rs` - Sankey layout computation
- `outlay-gtk/src/insights_view.rs` - Insights view (streaks, achievements, recap, anomalies)
- `outlay-gtk/src/credit_cards_view.rs` - Credit Cards view

## New Dependencies

- `pdf-extract` crate for PDF text extraction

## Modified Files

- `outlay-core/src/db.rs` - migration v9, new CRUD methods for credit cards / streaks / achievements / recap queries / budget period computation
- `outlay-core/src/models.rs` - new structs (CreditCard, Achievement, Streak, ParsedTransaction, SankeyLayout, etc.)
- `outlay-core/src/lib.rs` - register new modules
- `outlay-gtk/src/main.rs` - register new views, startup achievement checks
- `outlay-gtk/src/window.rs` - add Insights and Credit Cards to sidebar navigation
- `outlay-gtk/src/history_view.rs` - bulk operations, tag chips, anomaly banner
- `outlay-gtk/src/log_view.rs` - NL entry bar, templates button, split toggle
- `outlay-gtk/src/edit_dialog.rs` - splits editing, tags editing
- `outlay-gtk/src/budgets_view.rs` - custom cycle, what-if sandbox
- `outlay-gtk/src/charts_view.rs` - Sankey diagram section
- `outlay-gtk/src/goals_view.rs` - projection subtitles and mini charts
- `outlay-gtk/src/settings_view.rs` - categorization rules section, PDF import button
- `outlay-gtk/src/quick_add.rs` - NL entry bar, searchable category
- `outlay-gtk/Cargo.toml` - add pdf-extract dependency
