BillTracker/FUTURE.md

26 KiB

Bill Tracker — Future Improvements

This document tracks potential future enhancements for Bill Tracker.

Last Updated: 2026-05-09
Current Version: v0.19.0 noice

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. Mark completed items with and version number
  4. Reference this file when dispatching improvement tasks

Pending Recommendations

Click-to-toggle Paid/Unpaid Status

Priority: HIGH
Status: COMPLETED v0.19.0
Added: 2026-05-08 by _null

Description: Allow users to click directly on the "Paid", "Missed", "Late", "Due Soon", "Upcoming" status in the tracker to toggle between Paid and Unpaid states without opening the bill modal.

Implementation:

  • Added POST /api/bills/:id/toggle-paid endpoint
  • StatusBadge component now supports clickable prop with hover effects
  • Clicking Paid removes payment (soft delete), Clicking Unpaid creates payment
  • Confirmation dialog before toggling Unpaid → Paid
  • Loading spinner during API call
  • Toast notifications on success/failure

Files Modified:

  • routes/bills.js — new toggle-paid endpoint
  • client/api.js — togglePaid API function
  • client/pages/TrackerPage.jsx — StatusBadge click handler, enhanced StatusBadge component

Billing Cycle Sub-categories for Weekly/Monthly

Priority: MEDIUM
Added: 2026-05-08 by _null

Description: Add sub-categories to billing cycles. Current cycles (1st, 15th, Other) work for monthly bills, but need weekly and monthly options with sub-categories for due dates.

Rationale: Supports users with weekly bills (rent, subscriptions, etc.) and more complex monthly schedules. Requires backend schema changes and frontend updates.

Implementation Notes: Backend:

  • Add cycle_type enum: monthly, weekly, biweekly, quarterly, annual
  • Add cycle_subcategory for specific day (e.g., "Monday", "1st", "15th")
  • Migration for existing bills (default to monthly)
  • Update bill creation/edit endpoints

Frontend:

  • Dropdown for cycle type
  • Conditional sub-category selector based on type
  • Update Tracker to group by cycle type
  • Files likely to be modified: db/schema.sql, db/database.js, routes/bills.js, client/pages/BillsPage.jsx, client/components/BillModal.jsx
  • Estimated effort: 6-8 hours

Previous Month Paid Amount on Tracker Page

Priority: MEDIUM
Added: 2026-05-08 by _null

Description: Display the previous month's total paid amount on the Tracker page, positioned between "Expected" and "Paid" columns.

Rationale: Context for users to compare current month spending vs. previous month at a glance. Helps with budgeting and spotting anomalies.

Implementation Notes:

  • Fetch previous month's payment data alongside current month
  • New column: "Last Month" between Expected and Paid
  • Option to show/hide via settings
  • Consider sparkline mini-chart for trend
  • Files likely to be modified: routes/tracker.js, client/pages/TrackerPage.jsx
  • Estimated effort: 3 hours

3-Month Trend Indicator with Up/Down Arrows

Priority: MEDIUM
Added: 2026-05-08 by _null

Description: Add trend indicators showing whether the last 3 months of payments went up or down compared to current month. Display as up/down arrow with percentage change.

Rationale: Visual trend indicator helps users identify spending patterns without navigating to Analytics page.

Implementation Notes:

  • Calculate 3-month rolling average
  • Compare current month vs. previous 3-month average
  • Show green up arrow if trending up (more paid), red down arrow if trending down
  • Display percentage change
  • Position in Tracker header or Summary card
  • Files likely to be modified: routes/analytics.js (new endpoint), client/pages/TrackerPage.jsx or client/pages/SummaryPage.jsx
  • Estimated effort: 4 hours

Add React.memo() to prevent unnecessary re-renders

Priority: HIGH
Status: COMPLETED v0.19.0
Added: 2026-05-08 by Scarlett

Description: Many components render on every state change in the parent (especially App.jsx, TrackerPage.jsx, BillsPage.jsx), causing unnecessary re-renders of child components that don't depend on those specific state changes.

Implementation:

  • Applied React.memo() to StatusBadge, SummaryCard, MobileBillRow, MobileTrackerRow, NavPill, and BrandBlock
  • Extracted NavPill and BrandBlock to separate files in client/components/layout/
  • Fixed missing React imports and useState bugs during implementation
  • Build verified successful

Files Modified:

  • client/components/StatusBadge.jsx
  • client/components/SummaryCard.jsx
  • client/components/MobileBillRow.jsx
  • client/components/MobileTrackerRow.jsx
  • client/components/layout/NavPill.jsx (new file)
  • client/components/layout/BrandBlock.jsx (new file)
  • client/components/layout/Sidebar.jsx (refactored to use new components)

Implement proper error boundaries

Priority: CRITICAL
Added: 2026-05-08 by Scarlett

Description: The app has no React error boundaries. When a component throws an error (network failure, unexpected data shape, etc.), the entire app crashes with a white screen and no clear path to recovery.

Rationale: User experience and reliability. Currently, any JavaScript error in a component causes a complete app crash. Error boundaries would allow the app to display a fallback UI and potentially recover. This is especially important for production use where you can't predict all error conditions.

Implementation Notes:

  • Create a generic ErrorBoundary component with fallback UI
  • Wrap top-level pages (TrackerPage, BillsPage, AnalyticsPage) in error boundaries
  • Wrap App.jsx router with error boundary
  • Log errors to console and optionally to error tracking service
  • Consider adding componentDidCatch class component wrapper for critical paths
  • Files likely to be modified: Add new client/components/ErrorBoundary.jsx, wrap pages in App.jsx
  • Estimated effort: 45-60 minutes

Add loading skeletons and better async state management

Priority: MEDIUM
Added: 2026-05-08 by Scarlett

Description: Many pages show only "Loading..." or no state between async API calls and data rendering. Pages like TrackerPage, AnalyticsPage, and BillsPage have inconsistent loading states.

Rationale: Perceived performance. Users should see immediate visual feedback when data is loading, even if the actual data loads slowly. Skeleton loaders prevent layout shifts and set proper expectations about wait times.

Implementation Notes:

  • Add loading skeleton components for:
    • Summary cards (4 skeleton cards for TrackerPage)
    • Table rows (skeleton rows for bills tracker tables)
    • Chart placeholders (shimmer effect for analytics)
    • Form fields (skeleton inputs for modals)
  • Create reusable Skeleton components in client/components/ui/Skeleton.jsx
  • Implement loading state with proper transitions (fade in/out)
  • Consider adding aria-busy attributes during load
  • Files likely to be modified: client/components/ui/, client/pages/TrackerPage.jsx, client/pages/AnalyticsPage.jsx, client/pages/BillsPage.jsx
  • Estimated effort: 60-90 minutes

Add keyboard navigation and accessible ARIA labels

Priority: HIGH
Added: 2026-05-08 by Scarlett

Description: While many components use semantic HTML, several interactive elements lack proper ARIA attributes, keyboard navigation, or focus management, making the app inaccessible to screen reader users and keyboard-only users.

Rationale: Accessibility compliance and broader user reach. Bill Tracker should be usable by everyone. WCAG 2.1 Level A compliance requires:

  • Proper labeling of interactive elements
  • Keyboard navigation support
  • Focus management in modals
  • Screen reader announcements for dynamic content

Implementation Notes:

  • Audit all interactive components for missing ARIA labels:
    • Buttons without aria-label or visible text
    • Icons used as buttons
    • Custom selects and dropdowns
    • Modal dialogs (missing role="dialog" and aria-modal)
  • Add focus management to modals (trap focus, return focus on close)
  • Ensure keyboard navigation works through all pages
  • Add proper aria-live regions for toast notifications
  • Ensure color contrast meets WCAG AA standards (verify with axe DevTools)
  • Files likely to be modified: client/components/*.jsx, client/pages/*.jsx
  • Estimated effort: 2-3 hours for comprehensive audit and fixes

Add React Query (TanStack Query) for server state management

Priority: MEDIUM
Added: 2026-05-08 by Scarlett

Description: Currently using manual useState/useEffect patterns with custom api wrapper for data fetching. This leads to duplicated loading/error handling, stale data issues, and no request caching.

Rationale: Developer experience and performance. React Query provides:

  • Automatic request caching and stale-while-revalidate
  • Background refetching
  • Optimistic updates
  • Request deduplication
  • Built-in loading/error states

Implementation Notes:

  • Replace manual API calls in pages with useQuery, useMutation
  • Add query keys for cache invalidation
  • Implement global query client with React Query DevTools
  • Gradual migration: start with TrackerPage, then BillsPage, then AnalyticsPage
  • Files likely to be modified: client/pages/*.jsx, add client/hooks/useQueryClient.js
  • Estimated effort: 4-6 hours for full migration

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

Optimize bundle size and code splitting

Priority: LOW
Added: 2026-05-08 by Scarlett

**Description: No code splitting is implemented. All JavaScript loads on initial page load, including rarely used pages like AdminPage (1873 lines) and DataPage (1583 lines).

Rationale: Initial load performance. Users shouldn't download admin-only code if they're regular users. Code splitting reduces initial bundle size and improves time-to-interactive.

Implementation Notes:

  • Use React.lazy() for route-level code splitting
  • Lazy load admin routes for non-admin users
  • Lazy load rarely used pages (DataPage, AnalyticsPage)
  • Consider dynamic imports for large dependencies (xlsx, openid-client)
  • Analyze bundle with vite-bundle-visualizer
  • Add preload hints for critical resources
  • Files likely to be modified: client/App.jsx, vite.config.js
  • Estimated effort: 1-2 hours

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

Template for New Recommendations

### [Feature Name]
**Priority:** CRITICAL / HIGH / MEDIUM / LOW / MEH  
**Added:** YYYY-MM-DD by [Agent]

**Description:**
Brief description of the improvement.

**Rationale:**
Why this matters.

**Implementation Notes:**
- Technical approach
- Files likely to be modified
- Estimated effort

**Depends On:**
Any prerequisites or blocking issues.

Completed Items

None yet


Backend Analysis Recommendations (by Neo)

Database Query Optimization: Add Missing Indexes

Priority: HIGH
Added: 2026-05-08 by Neo

Description: Several frequently queried columns lack indexes, causing full table scans on growth.

Rationale:

  • bills.name and bills.user_id are used in WHERE clauses but only indexed as part of composite indexes
  • payments.method is used for filtering but has no index
  • monthly_starting_amounts.user_id exists but lacks explicit index
  • import_history.imported_at is used for cleanup but not indexed

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/db/database.js (migrations section)
  • Estimated effort: 30 minutes
  • Add these indexes:
    CREATE INDEX IF NOT EXISTS idx_bills_user_name ON bills(user_id, name);
    CREATE INDEX IF NOT EXISTS idx_payments_method ON payments(method);
    CREATE INDEX IF NOT EXISTS idx_monthly_starting_amounts_user ON monthly_starting_amounts(user_id);
    CREATE INDEX IF NOT EXISTS idx_import_history_imported_at ON import_history(imported_at);
    

Security: Missing Input Validation on Bulk Operations

Priority: HIGH
Added: 2026-05-08 by Neo

Description: The /api/payments/bulk endpoint validates individual items but lacks validation for the request body as a whole.

Rationale:

  • No maximum item count check — an attacker could send 10,000+ items
  • No size limit on JSON body beyond Express defaults
  • Missing rate limiting per user (not just per IP) for bulk operations
  • No duplicate detection — sending same payment twice creates duplicates

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/routes/payments.js
  • Estimated effort: 2 hours
  • Add:
    • Max 50 items per request
    • Max 5MB body size
    • Per-user rate limit (e.g., 10 bulk operations per hour)
    • Duplicate detection using bill_id + paid_date + amount hash

Security: Session Token Expiry Not Enforced at Database Level

Priority: CRITICAL
Added: 2026-05-08 by Neo

Description: Session tokens expire in application logic but database records persist indefinitely.

Rationale:

  • /services/authService.js checks expires_at > datetime('now') in code
  • Expired sessions accumulate in sessions table
  • No cleanup worker for orphaned/expired sessions
  • Risk of table bloat and potential token reuse if bugs exist

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/db/database.js, /services/cleanupService.js
  • Estimated effort: 4 hours
  • Add:
    • Database-level cleanup job (runs daily via admin cleanup service)
    • SQL:
      DELETE FROM sessions WHERE expires_at < datetime('now');
      
    • Consider adding created_at + last_used_at for better cleanup targeting

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

Features: Missing Audit Logging for Critical Operations

Priority: HIGH
Added: 2026-05-08 by Neo

Description: Security-sensitive operations lack comprehensive audit trails.

Rationale:

  • Password changes (via /api/profile/change-password) not logged
  • User role changes (admin routes) not logged
  • Session invalidation events not tracked
  • Import/export operations only tracked via import_history table, missing details
  • CSRF token validation failures not logged

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/services/auditService.js (new file), route files
  • Estimated effort: 4 hours
  • Add audit table:
    CREATE TABLE IF NOT EXISTS audit_log (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER,
      action TEXT NOT NULL,
      entity_type TEXT,
      entity_id INTEGER,
      details_json TEXT,
      ip_address TEXT,
      user_agent TEXT,
      created_at TEXT DEFAULT (datetime('now'))
    );
    CREATE INDEX IF NOT EXISTS idx_audit_log_user ON audit_log(user_id, created_at);
    
  • Log: password changes, role changes, login attempts (success/fail), session invalidation

Features: Missing Export for User-Specific Reports

Priority: LOW
Added: 2026-05-08 by Neo

Description: No built-in way to export filtered data (e.g., "all bills in category X for last 6 months").

Rationale:

  • /api/analytics/summary exists but returns JSON only
  • Users cannot generate Excel/PDF reports
  • No programmatic way to get export links for specific filters
  • /api/export/user-excel exports everything, not filtered views

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/routes/export.js
  • Estimated effort: 6 hours
  • Add endpoints:
    • GET /api/export/user-excel?category_id=1&start=2026-01&end=2026-06
    • GET /api/export/user-json?filter=bills&status=missed
    • Add report title/description to export metadata

Performance: N+1 Query Patterns in Tracker and Analytics

Priority: MEDIUM
Added: 2026-05-08 by Neo

Description: Looping over bills and querying payments/state individually causes N+1 queries.

Rationale:

  • tracker.js line 27-37: iterates over bills, runs mbsStmt.get() per bill
  • analytics.js uses bills.map() and builds maps with per-bill lookups
  • With 50 bills, this creates 100+ extra queries per request

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/routes/tracker.js, /analytics.js
  • Estimated effort: 3 hours
  • Use batch queries instead:
    // Fetch all monthly states for bills in one query
    const states = db.prepare(`
      SELECT * FROM monthly_bill_state
      WHERE bill_id IN (${billIds.join(',')}) AND year=? AND month=?
    `).all(billIds, year, month);
    

Security: Session Token Not Rotated on Auth Events

Priority: MEDIUM
Added: 2026-05-08 by Neo

Description: Session tokens are not rotated on password change or logout events.

Rationale:

  • admin.js deletes sessions on password change, but this is inconsistent
  • /api/profile/change-password does not invalidate other sessions
  • Logout only removes current session, doesn't invalidate others
  • Session tokens are static — no rotation mechanism

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/services/authService.js
  • Estimated effort: 4 hours
  • Add:
    • session_version or token_seed column in users table
    • Increment seed on password change, logout all
    • Validate seed in getSessionUser()
    • Logout invalidates only current session (more usable)

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)

Security: Error Messages Expose Implementation Details

Priority: LOW
Added: 2026-05-08 by Neo

Description: Some error messages leak database or implementation details.

Rationale:

  • SQLite errors (e.g., "UNIQUE constraint failed") bubble up in some paths
  • Stack traces logged to console (not in HTTP response, but visible in logs)
  • DB path exposed in error messages if DB_PATH env is set incorrectly
  • Migration errors include full SQL in some cases

Implementation Notes:

  • Files to modify: /home/kaspa/.openclaw/Projects/bill-tracker/middleware/errorFormatter.js, /server.js error handler
  • Estimated effort: 2 hours
  • Add generic error messages for 500s:
    { "error": "INTERNAL_ERROR", "message": "An unexpected error occurred. Please contact support.", "code": "ERR-500" }
    
  • Log detailed errors server-side only, never in response
  • Sanitize all error messages before sending

Database Migration System Issues

🔴 CRITICAL: No Explicit Version Tracking for Migrations

Priority: CRITICAL
Status: PENDING
Added: 2026-05-09 by Neo

Description: Database migrations lack explicit version tracking. System doesn't know which migrations have been applied, risking duplicate application or incomplete upgrades.

Rationale:

  • db/database.js runMigrations() has no tracking table
  • No way to know which migrations have been applied vs. pending
  • Migrations run every startup, relying only on IF NOT EXISTS checks
  • Risk: if a migration partially fails, system doesn't know to retry or skip

Implementation Notes:

  • Create schema_migrations tracking table
  • Log each applied migration with timestamp
  • Query table before running each migration
  • Mark as CRITICAL for production deployment

🔴 CRITICAL: No Transaction Wrapping for Migrations

Priority: CRITICAL
Status: PENDING
Added: 2026-05-09 by Neo

Description: Migrations are not atomic. If a migration fails partway through, database is left in inconsistent state with no rollback.

Rationale:

  • Multi-statement migrations (ALTER TABLE + UPDATE + CREATE INDEX) not wrapped in transactions
  • If step 2 fails, step 1 already committed
  • No recovery mechanism for partially-applied migrations
  • Risk: corrupt schema state that's hard to debug

Implementation Notes:

  • Wrap each migration in BEGIN/COMMIT/ROLLBACK
  • Error handling must ROLLBACK on any failure
  • Log transaction state for debugging
  • Test with intentional failures to verify rollback

🟠 HIGH: No Explicit Migration Dependency Management

Priority: HIGH
Status: PENDING
Added: 2026-05-09 by Neo

Description: Migrations have implicit dependencies (e.g., adding columns to tables that must exist first) but no explicit dependency graph or ordering guarantee.

Rationale:

  • Some migrations assume prior migrations have run
  • Manual ordering in runMigrations() function is fragile
  • Adding new migrations in wrong order could break schema
  • No way to validate dependency chain

Implementation Notes:

  • Create migration function objects with explicit dependsOn list
  • Validate dependency graph before running migrations
  • Enforce topological sort order
  • Test dependency failures to ensure proper error messages

🟡 MEDIUM: No Rollback Capability for Failed Migrations

Priority: MEDIUM
Status: PENDING
Added: 2026-05-09 by Neo

Description: No way to rollback or recover from failed migrations without manual database repairs.

Rationale:

  • If a migration fails, no automatic recovery
  • Admin must manually fix database state
  • No rollback scripts to revert breaking changes
  • Risk: extended downtime on production

Implementation Notes:

  • Design migrations with rollback functions
  • Store rollback SQL alongside migration
  • Implement ROLLBACK_LAST_MIGRATION functionality
  • Document manual recovery procedures

🟡 MEDIUM: Limited Error Handling and Logging for Migrations

Priority: MEDIUM
Status: PENDING
Added: 2026-05-09 by Neo

Description: Migration failures don't produce clear error messages or logs, making debugging difficult.

Rationale:

  • Migration errors are silent or unclear
  • No logging of which migration failed or why
  • No way to diagnose schema inconsistencies
  • Risk: slow debugging on production issues

Implementation Notes:

  • Add detailed logging: [migration] Applying v0.20.0: Add user_groups table
  • Include timing: [migration] v0.20.0 completed in 234ms
  • Log precondition checks: [migration] Checking: table_exists('users')
  • Error log with context: [migration-error] v0.20.0 failed: UNIQUE constraint failed on users.username

Migration Cleanup: bill_history_ranges Outside Versioned Array

Priority: LOW
Status: PENDING
Added: 2026-05-09 by Ripley

Description: The bill_history_ranges table creation and a few other inline items are still outside the versioned migrations array in db/database.js. They run on every startup via CREATE TABLE IF NOT EXISTS but aren't tracked in schema_migrations, so they bypass the version tracking system.

Implementation Notes:

  • Move bill_history_ranges and any other orphaned inline migrations into the versioned migrations array
  • Assign appropriate version numbers
  • Ensure idempotent run() functions for each
  • Verify they get tracked in schema_migrations after the move