# Bill Tracker — Future Improvements **This document tracks potential future enhancements for Bill Tracker.** **Last Updated:** 2026-05-11 **Current Version:** v0.24.3 ## How to Use This Document This file is a living document. Agents should: 1. Read this file before proposing changes 2. Add new recommendations with priority levels 3. Never add completed items — move those to HISTORY.md instead 4. Reference this file when dispatching improvement tasks 5. Only Ripley can remove items from this list. Notify Ripley if something neds to be removed. ### Priority Format All items must include the priority emoji in their heading, matching the section they belong to: | Priority | Emoji | Heading Format | |----------|-------|---------------| | CRITICAL | 🔴 | `### 🔴 Title — CRITICAL` | | HIGH | 🟠 | `### 🟠 Title — HIGH` | | MEDIUM | 🟡 | `### 🟡 Title — MEDIUM` | | LOW | 🔵 | `### 🔵 Title — LOW` | | NICE TO HAVE | 💭 | `### 💭 Title — NICE TO HAVE` | Items are grouped under their priority section heading (`## 🔴 CRITICAL`, `## 🟠 HIGH`, etc.) and sorted most-impactful-first within each tier. ## Pending Recommendations ### 🔴 CRITICAL ### 🔴 Import XLSX / SQLite / Backup CSRF Failure — CRITICAL **Priority:** CRITICAL **Added:** 2026-05-11 by Ripley **Description:** All three file-upload import endpoints (`/api/import/spreadsheet/preview`, `/api/import/user-db/preview`, `/api/admin/backups/import`) return "Your session has expired or this request may be fraudulent" because the frontend raw `fetch()` calls don't include the `x-csrf-token` header. **Rationale:** - The `_fetch()` helper in `client/api.js` automatically adds `x-csrf-token` from the cookie for all state-changing requests - Three import functions bypass `_fetch()` and use raw `fetch()` directly for file uploads: `previewSpreadsheetImport`, `previewUserDbImport`, `importAdminBackup` - None of them include the CSRF token header - The CSRF middleware rejects these requests with 403 `CSRF_INVALID` - Import is completely broken — users cannot import XLSX, SQLite, or backup files - This affects a core feature (data import) and produces a confusing error message **Implementation Notes:** - Add `x-csrf-token` header to all three raw `fetch()` calls in `client/api.js` - Use the existing `getCsrfToken()` function (already defined at the top of `client/api.js`) - Lines to fix: ~L204 (previewSpreadsheetImport), ~L234 (previewUserDbImport), ~L93 (importAdminBackup) - Example: `headers: { 'Content-Type': 'application/octet-stream', 'x-csrf-token': getCsrfToken(), ... }` - No backend changes needed — CSRF middleware already works correctly - Files to modify: `client/api.js` - Estimated effort: 15 minutes ### 🔴 Import XLSX Dual-Column Layout Not Parsed — CRITICAL **Priority:** CRITICAL **Added:** 2026-05-11 by Ripley **Description:** The real-world spreadsheet (`backups/monthly bills.xlsx`) uses a **dual-column layout** — each monthly sheet is split into two halves representing two payment periods: - **Left half (columns A-E):** Bills due around the **1st** of the month - **Right half (columns G-K):** Bills due around the **15th** of the month Each half has its own `Due Date | Bill | Amount | Paid Date | Date Cleared` headers. The current parser only detects headers in the first row and processes columns linearly, so it captures the 1st-of-month bills but completely misses all 15th-of-month bills (roughly half the data). Example from Apr 2026 sheet: ``` Left (1st): auto | Roadrunner ATV | $225.64 | paid 2026-03-01 (due ~1st) Right (15th): | Amazon chase card | $366 | paid 2026-04-20 (due ~15th) ``` **Rationale:** - This is the actual production spreadsheet the app needs to import - ~100 monthly sheets spanning 2017–2026, each with two payment periods - The 15th-of-month bills (credit cards, loans, subscriptions) are completely lost during import - Without dual-column support, the import feature is broken for real data - The "1st vs 15th" split is semantically meaningful — it maps to `due_day` in the bill model **Additional Issues in This Spreadsheet:** - Rows 1–2 contain paycheck/leftover summary data, not bills — parser must skip these - Non-numeric amount values: "double pay", blank amounts, "past due" — need graceful handling - Due date column contains non-date values: "auto" (autopay indicator), "24th" (day-of-month shorthand), account numbers like "9522104" - Some sheets have slight column layout variations (extra column, merged cells) - Sheet names have typos: "Januaru 2021", "Novevmber 2019", "Febuary 2023" — parser already handles these - 3 non-month sheets ("2018 taxes", "debt totoals", "home ownership expenses") should be skipped — already handled by `NON_MONTH_SHEET_RE` - "auto" in the Due Date column is an autopay flag, not a date — should be detected as a label, not parsed as a date **Implementation Notes:** - Modify `spreadsheetImportService.js` to detect dual-column headers in a single sheet row - When two sets of bill headers are found (A-E and G-K), process each half independently - Left half rows should default `due_day` to ~1, right half rows should default `due_day` to ~15 - Each half produces its own set of rows with the same sheet name/month context - Handle non-numeric amount cells gracefully (null amount, "double pay" as a note/label) - "auto" in Due Date column → set `autopay` label/detected label, don't try to parse as date - "24th" in Due Date column → parse as day-of-month (24) - Skip rows where the bill name cell is blank AND the amount cell is blank or non-numeric - Filter out paycheck/summary rows (Row 1: Paycheck amounts, Row 2: Left Over calculations) - The `backups/monthly bills.xlsx` file is in `backups/` (gitignored) for testing - Files to modify: `services/spreadsheetImportService.js`, possibly `routes/import.js` - Estimated effort: 4-6 hours ### 🔴 No Confirmation Before Destructive Actions — CRITICAL **Priority:** CRITICAL **Added:** 2026-05-11 by Ripley **Description:** Deleting a bill or payment is one click with no confirmation dialog and no undo. For a financial app, accidental data loss destroys user trust. **Rationale:** - Bills and payments represent real financial commitments and history - No "are you sure?" prompt before delete - No undo mechanism, no soft delete, no recovery - One misclick = gone forever — unacceptable for financial data - This is a trust and data integrity issue, not a UX nicety **Implementation Notes:** - Add confirmation dialog to all delete actions (bills, payments, categories) - Consider soft delete (`deleted_at` column) with a grace period before permanent removal - Add undo toast after delete that allows restoration within a short window - Files to modify: `BillModal.jsx`, `BillsTableInner.jsx`, `TrackerPage.jsx`, `CategoriesPage.jsx` - Estimated effort: 3-4 hours ### 🟠 HIGH ### 🟠 No Search or Filter Across Bills — HIGH **Priority:** HIGH **Added:** 2026-05-11 by Ripley **Description:** No way to find a bill by name, category, or amount. Users must scroll through the entire list to find anything. Every bill tracker on the market has instant search. **Rationale:** - With dozens of bills, scrolling is slow and error-prone - No search bar on BillsPage, TrackerPage, or CalendarPage - Can't filter by category, amount range, autopay status, or billing cycle - Can't quickly find "where's that electric bill?" without visually scanning - Table stakes for any list-based app **Implementation Notes:** - Add search input to BillsPage (filter by name, category, notes) - Add filter chips/dropdowns for category, billing cycle, autopay, active/inactive - Add search to TrackerPage (filter visible rows by bill name) - Consider a global `Cmd+K` / `Ctrl+K` command palette for instant bill lookup - Files to modify: `BillsPage.jsx`, `TrackerPage.jsx`, `client/api.js` - Estimated effort: 6-8 hours ### 🟠 No Visible Overdue Indicators — HIGH **Priority:** HIGH **Added:** 2026-05-11 by Ripley **Description:** Overdue bills aren't visually flagged on the tracker. An unpaid past-due bill looks the same as one not due yet. The `notify_overdue` setting exists but there's no visual distinction in the UI. **Rationale:** - The whole point of a bill tracker is to not miss payments - Overdue bills should be impossible to overlook — red highlight, badge count, sticky alert - Data model supports overdue notifications but tracker grid shows no overdue state - Users scanning the tracker won't notice a missed bill buried in the list **Implementation Notes:** - Add overdue detection: if today > due date for current month and no payment logged, mark overdue - Red/amber background on overdue tracker rows - Overdue count badge in Sidebar next to Tracker nav link - Optional: overdue summary banner at top of TrackerPage - Files to modify: `TrackerPage.jsx`, `Sidebar.jsx`, `routes/tracker.js` (add overdue count to API response) - Estimated effort: 4-6 hours ### 🟠 Filtered Export for Reports — HIGH **Priority:** HIGH **Added:** 2026-05-11 by Ripley (upgraded from LOW) **Description:** No way to export filtered data (e.g., "all bills in category X for last 6 months", "everything overdue in 2026"). Export dumps everything or nothing. **Rationale:** - Exporting filtered reports is core functionality for a bill tracker, not a nice-to-have - Users need "all Q1 utility bills" or "overdue payments this year" for reconciliation and tax prep - `/api/export/user-excel` exports everything — no query params for date range, category, or status - This is how people actually use financial data outside the app **Implementation Notes:** - Add query params to export endpoints: `category_id`, `start`, `end`, `status` (paid/unpaid/overdue) - Files to modify: `routes/export.js`, `client/pages/DataPage.jsx` - Estimated effort: 6 hours ### 🟡 MEDIUM ### 🟡 No Bill Template / Duplicate Bill — MEDIUM **Priority:** MEDIUM **Added:** 2026-05-11 by Ripley **Description:** Creating a new bill means filling 10+ fields every time. No way to duplicate an existing bill or use a template. If you have 3 utilities from the same provider, you're retyping everything. **Rationale:** - Bill creation has many fields (name, category, due day, amount, autopay, website, account, 2FA, notes) - Common pattern: similar bills from same provider or same category with slight variations - "Duplicate bill" is table stakes in every bill tracker - Reduces friction and errors during bill setup **Implementation Notes:** - Add "Duplicate" button/action on each bill row and in BillModal - Pre-fill all fields from source bill, clear `name` and set "(Copy)" suffix - Files to modify: `BillModal.jsx`, `BillsPage.jsx`, `routes/bills.js` (POST endpoint can accept `source_bill_id` param) - Estimated effort: 3-4 hours ### 🟡 No Partial Payment Support — MEDIUM **Priority:** MEDIUM **Added:** 2026-05-11 by Ripley **Description:** The UI only supports logging a single payment per bill per month. The `payments` table schema supports multiple entries per bill, but the frontend doesn't surface this. Split payments (half now, half later) can't be tracked. **Rationale:** - Many bills get paid in installments (medical, tuition, large utilities) - Payment plan arrangements require tracking multiple payments against one bill - The data model already supports it — it's purely a frontend gap - Without this, users either over-record or under-record partial payments **Implementation Notes:** - Show payment history per bill in tracker (expandable row or modal tab) - Allow "Add partial payment" with amount + date, summing to bill total - Display remaining balance on partially-paid bills - Files to modify: `TrackerPage.jsx`, `routes/payments.js`, possibly `BillModal.jsx` - Estimated effort: 6-8 hours ### 🟡 No Year-Over-Year Comparison in Analytics — MEDIUM **Priority:** MEDIUM **Added:** 2026-05-11 by Ripley **Description:** Analytics shows monthly trends within a single year but there's no "this month vs same month last year" view. Users can't evaluate whether spending is improving. **Rationale:** - The whole point of analytics is answering "am I doing better or worse?" - Within-year trends are useful but don't show long-term improvement - Comparing April 2026 to April 2025 is the natural question people ask - Available in every competing app (YNAB, Monarch, etc.) **Implementation Notes:** - Add YoY comparison toggle or tab to AnalyticsPage - Query: same month range across current and previous year, diff the totals - Show percentage change and absolute change per category - Files to modify: `AnalyticsPage.jsx`, `routes/analytics.js` (add YoY endpoint or params) - Estimated effort: 6-8 hours ### 🟡 No Bulk Actions — MEDIUM **Priority:** MEDIUM **Added:** 2026-05-11 by Ripley **Description:** Every action is one-at-a-time. Can't select multiple bills and mark them paid, skip them for a month, or change their category. **Rationale:** - End-of-month reconciliation means marking many bills as paid in a row - Category reorganization affects multiple bills at once - Skipping seasonal bills for summer/winter requires individual clicks - Bulk actions are standard in any list-based management UI **Implementation Notes:** - Add checkbox selection to BillsPage rows (with select-all toggle) - Bulk action toolbar: Mark Paid, Skip This Month, Change Category, Delete - Backend: batch endpoints or loop with progress indicator - Files to modify: `BillsPage.jsx`, `BillsTableInner.jsx`, `routes/bills.js`, `routes/payments.js` - Estimated effort: 8-10 hours ### Architecture: Business Logic Mixed with Route Handlers **Priority:** MEDIUM **Added:** 2026-05-08 by Neo **Description:** Many routes contain business logic that should be extracted to service layers. **Rationale:** - `bills.js` contains `parseDueDay()`, `parseInterestRate()` — validation logic - `tracker.js` contains date/range calculations that are reused across routes - `admin.js` has complex OIDC config building mixed with routing - `analytics.js` has complex date-building logic (`buildMonths`, `monthKey`, etc.) **Implementation Notes:** - Files to modify: Multiple route files + new service files in `/services/` - Estimated effort: 8 hours - Proposed structure: ``` /services/billsService.js /services/trackerService.js /services/analyticsService.js /services/authService.js (existing) /services/oidcService.js (existing) /services/cleanupService.js (existing) ``` - Route handlers should call services, not contain business logic ### 🔵 LOW ### 🔵 Payment Method Tracking and Summary — LOW **Priority:** LOW **Added:** 2026-05-11 by Ripley **Description:** The `payments` table has a `method` column (free-text) but no way to see "how much did I pay via autopay vs manual vs credit card this month." No standardized method options, no summary. **Rationale:** - Useful for reconciling credit card statements vs bank statements - Autopay vs manual tracking helps identify bills that should be switched to autopay - Payment method breakdown is a common analytics view in financial apps - Current `method` field is unvalidated free text — no consistency **Implementation Notes:** - Standardize payment methods: enum or controlled list (autopay, bank_transfer, credit_card, check, cash, other) - Add payment method breakdown to analytics or summary page - Files to modify: `routes/payments.js`, `AnalyticsPage.jsx` or `SummaryPage.jsx`, schema migration for method validation - Estimated effort: 4-6 hours ### 🔵 No Keyboard Navigation or Shortcuts — LOW **Priority:** LOW **Added:** 2026-05-11 by Ripley **Description:** Only a skip link exists for keyboard accessibility. No `Cmd+K` to find a bill, no `Esc` to close modals, no arrow keys to navigate the tracker grid. Power users and accessibility need keyboard support. **Rationale:** - Keyboard accessibility is required for WCAG compliance - Power users navigate faster with keyboard shortcuts - Modal dismiss on `Esc` is expected behavior in any modern app - Command palette (`Cmd+K`) pairs with the search feature (also missing) **Implementation Notes:** - `Esc` closes any open modal/dialog - `Cmd+K` / `Ctrl+K` opens search/command palette - Arrow keys navigate tracker rows when grid is focused - Tab order follows logical flow, not DOM order - Files to modify: `App.jsx`, `BillModal.jsx`, `TrackerPage.jsx`, all dialog components - Estimated effort: 6-8 hours ### Add comprehensive unit and integration tests **Priority:** LOW **Added:** 2026-05-08 by Scarlett **Description:** Currently no unit tests exist for components or hooks. The only testing appears to be functional tests in `test-functional.js`. Component-level testing is missing. **Rationale:** Code quality and maintainability. Unit tests catch regressions and document component behavior. Bill Tracker has complex business logic (bill calculations, monthly state, analytics) that should be tested. **Implementation Notes:** - Set up Jest + React Testing Library - Test key components: BillModal, TrackerPage row, BillsTableInner - Test hooks: useAuth, custom form hooks - Test utility functions in `client/lib/utils.js` - Consider vitest for faster test execution - Add CI integration for test execution - Files likely to be modified: Add `client/test/` directory, add `jest.config.cjs` - Estimated effort: 8-12 hours for baseline coverage ### Features: Missing Bill Grouping and Reorganization API **Priority:** LOW **Added:** 2026-05-08 by Neo **Description:** No way to reorder bills, drag-and-drop, or group by custom criteria. **Rationale:** - `bills` table has `due_day` ordering but no manual sort order - Frontend likely orders by `due_day` only - Users cannot create bill groups or categories for bills - No way to mark bills as "hidden" or "archived" without deactivating **Implementation Notes:** - Files to modify: `/home/kaspa/.openclaw/Projects/bill-tracker/db/schema.sql`, `/routes/bills.js` - Estimated effort: 6 hours - Add: - `sort_order` column to bills table (default NULL, ordered first by sort_order then due_day) - `PUT /api/bills/reorder` endpoint accepting `{bill_id: new_index}` - `PUT /api/bills/:id/archived` to soft-dearchive (sets `archived` flag) ### 💭 NICE TO HAVE ### Add consistent form state management pattern **Priority:** MEH **Added:** 2026-05-08 by Scarlett **Description:** Form state management is inconsistent across components. Some use `useState` for each field, others use form libraries. Validation patterns vary. **Rationale:** Consistency and maintainability. A consistent pattern makes it easier to add new forms and reduce bugs. **Implementation Notes:** - Consider react-hook-form for complex forms - Create reusable form field components (InputField, SelectField, etc.) - Standardize validation approach - Files likely to be modified: `client/components/*.jsx` - Estimated effort: 4-6 hours for migration