Commit Graph

221 Commits

Author SHA1 Message Date
null 90cfed035b feat: Payoff Custom mode, Summary reordering, unifed billing schedule, SimpleFIN + backup fixes (batch v0.34.1.3) 2026-05-30 21:20:51 -05:00
null c23cae1107 feat: reordering across management pages (Bills, Subscriptions, Categories, Snowball) — batch v0.34.1.2 2026-05-30 20:04:50 -05:00
null 35d0cbf8be chore: reset tracked db file 2026-05-30 17:27:15 -05:00
null 5449427b86 Add persistent bill reordering 2026-05-30 16:13:37 -05:00
null 799189059b chore: roadmap audit v0.34.2 — remove completed FUTURE.md items, update partial statuses 2026-05-30 15:18:45 -05:00
null 5182754e0f feat(tracker): price-change drift detection with amber insight panel
Detects when a bill's recent payments have diverged from its configured
expected amount for 2+ consecutive months and surfaces it in a new
collapsible amber panel on the Tracker page.

- Migration v0.71: adds `drift_snoozed_until` to bills and
  `notify_amount_change` to users
- New `driftService.getDriftReport()`: computes per-bill payment median
  over last 3 months, flags drift above a user-configurable threshold
  (default 5%, minimum $1 delta)
- New `GET /api/bills/drift-report` and `POST /api/bills/:id/snooze-drift`
  routes (registered before `/:id` to avoid routing conflict)
- `runDriftNotifications()` added to daily worker — sends amber digest
  email per user listing all changed bills with old → new amounts
- `notify_amount_change` wired through profile and notifications routes
- `DriftInsightPanel`: collapsible amber panel with per-bill
  strikethrough old → new amount, ±% badge, TrendingUp/TrendingDown
  icons, "Update to $X.XX" (with undo toast) and "Dismiss" (30 days)
  actions; teal palette for price decreases
- `drift_threshold_pct` setting added to SettingsPage Billing Behavior
- "Notify on price changes" toggle added to ProfilePage notifications

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:33:55 -05:00
null 3978507572 feat(tracker): overdue command center with snooze/skip/pay + sidebar badge
- migration v0.70 adds snoozed_until TEXT to monthly_bill_state
- trackerService: snoozed_until in monthly state fetch + getOverdueCount()
- GET /api/tracker/overdue-count endpoint
- PUT /bills/:id/monthly-state validates snoozed_until
- OverdueCommandCenter component: collapsible, per-bill actions, hides snoozed
- useOverdueCount hook (2-min stale, 5-min poll, tab-only)
- Sidebar/nav uses overdue count badge on Tracker menu item
- Bump v0.33.8.7 → v0.34.0
2026-05-30 13:19:09 -05:00
null db5f765d84 feat(roadmap): size grid from populated lanes + db cleanup fixes
- Roadmap grid now adapts columns based on how many priority lanes have items
- With only LOW items, lane uses full width instead of narrow 5-column slot
- cleanupService: use BACKUP_DIR import, handle .xlsx export file cleanup
- backupScheduler: export computeNextRun for external use
- Added backupAndCleanup.test.js for coverage
2026-05-30 13:04:27 -05:00
null 6b0c86b73c revert: compact tracker mode + wider layout, keep S badge + remaining/Done header (batch 0.33.8.7)
- Removed hasBoth, compact prop, 2xl:min-w-[700px], 2xl:hidden Last Month,
  narrowed columns — back to original single-column tracker layout
- Removed 2xl:max-w-[2000px] from Layout/Sidebar/AdminShell/footer/nav
- Kept S badge in all 4 locations and bucket remaining/Done header
- Added mkdocs/ to .gitignore
- Bump v0.33.8.6 -> v0.33.8.7
2026-05-29 21:16:13 -05:00
null af601057c4 style: wider max-width at 2xl+ (1500px -> 2000px) (batch 0.33.8.6)
- Layout, AdminShell, Sidebar, footer, mobile nav: 2xl:max-w-[2000px]
- Content area grows from ~1436px to ~1936px, enough room for
  dual-bucket tracker at 2xl+
- Bump v0.33.8.5 -> v0.33.8.6
2026-05-29 20:40:14 -05:00
null f99cd82438 feat: compact tracker, S badge, side-by-side buckets (batch 0.33.8.5)
- Sub badge changed to 'S' in all 4 locations with matching border style
- Two-bucket grid at 2xl+ when both buckets have bills
- Compact mode: narrow table, hide Last Month column, shrink Notes/Actions/Due
- Bucket header shows remaining/Done labels alongside paid/total/overpaid
- Removed standalone Remaining summary card (redundant with bucket header)
- Row and Bucket accept compact=false
- Bump v0.33.8.4 -> v0.33.8.5
2026-05-29 20:33:01 -05:00
null a15436b637 feat: 90-day backfill + auto-seed + status page redesign (batch 0.33.8.4)
- New backfillDataSource export and POST route for 89-day history pull
- Auto-seed 89 days on first connect, 30 days for routine syncs
- sinceEpoch() replaced with sinceEpochDays(days) with explicit param
- Status page errorRow now filters AND status = 'error'
- Full status page redesign: colored top borders, card icons, section labels,
  health banner with glowing dot, consistent spacing
- Bump v0.33.8.3 -> v0.33.8.4
2026-05-29 19:58:52 -05:00
null 0f9f48e255 feat: subscription badges + status improvements + dailyWorker fix (batch 0.33.8.3)
- Sub badge (indigo) in all 4 locations, toggleable in Bills prefs
- SimpleFIN Sync card on Status page
- dailyWorker.start() now called on startup
- tracker.overdue_count uses real SQL query
- Status page accuracy: dynamic headers, Degraded state, worker last_error check
- Removed SimpleFIN prefix from Recommendations title
- Bump v0.33.8.2 -> v0.33.8.3
2026-05-29 19:21:46 -05:00
null 6e9fd6873f fix: GeorgiaDigits font-bleed fix (batch 0.33.8.2)
- Removed 'Georgia' from --font-serif stack, replaced with ui-serif
- Added 'GeorgiaDigits' to --font-mono for snowball extra payment input
- Georgia now only enters via GeorgiaDigits @font-face with unicode-range
- Bump v0.33.8.1 -> v0.33.8.2
2026-05-29 18:42:11 -05:00
null c37716f685 feat: subscription catalog v2 + GeorgiaDigits font-face (batch 0.33.8.1)
- Migration v0.69: 90 new services across 16 categories
- Fixed Discord Nitro, Twitch Turbo, X Premium categories
- GeorgiaDigits @font-face with unicode-range for digit/currency codepoints
  only, applied via --font-sans and .tracker-number
- Bump v0.33.8.0 -> v0.33.8.1
2026-05-29 18:34:50 -05:00
null b34e21d1ba feat: advisory non-bill transaction filter system (batch 0.33.8.0)
- Migration v0.68: seeds advisory_non_bill_filters (5k+ patterns) and
  advisory_bill_like_overrides (83 override terms) on first startup.
  Idempotent — skips if already seeded.
- advisoryFilterService.js: lazy in-memory cache checks override terms
  first, then scans patterns. Returns null | {confidence, category, rationale}.
- Transaction list: each row gets advisory_filter from the server.
- High-confidence unmatched transactions: show 'Probably not a bill'
  italic text instead of 'No bill linked'.
- MatchBillDialog high confidence: 'Create Bill' replaced with
  'Probably not a bill · create anyway' text link for manual override.
- MatchBillDialog medium confidence: Create Bill button renders muted.
- Same logic in empty-state CTA when search returns no results.
- BillModal onSave now returns the saved bill so callers can auto-match.
- Bump v0.33.7.3 -> v0.33.8.0
2026-05-29 18:06:12 -05:00
null 392de3264f fix(ui): SimpleFIN transaction table fixed column sizing (batch 0.33.7.3)
- Table now uses table-fixed + colgroup for fixed column widths
- Long transaction text can no longer push action buttons off-screen
- Action buttons are compact icon-only with aria-label/title
- Long matched bill names are truncated with truncate class
- Bump v0.33.7.2 -> v0.33.7.3
2026-05-29 16:51:31 -05:00
null 32f1568515 feat: SimpleFIN payment backfill button on subscription bills (v0.33.7.2) 2026-05-29 04:19:20 -05:00
null da6a93804b fix: SimpleFIN recommendation card stays vertical in narrow sidebar
Title and amount in header, badges/reasons below, action buttons
in a clean row at the bottom.
2026-05-29 03:55:55 -05:00
null c3c0ab3542 style: SubscriptionsPage layout and responsiveness pass
- Page width consistent with rest of app
- Subscription/recommendation names no longer overflow
- Improved mobile/tablet wrapping for rows, amounts, action buttons
- Two-column layout delayed until very wide screens
- Added missing labels for food, education, shopping, security types
2026-05-29 03:49:36 -05:00
null 6b30ee4eb7 feat: merchant rules, auto-match on sync, duplicate API fix
- Removed duplicate unmatchTransaction API entry in api.js
- Unmonitored accounts: no chevron, click-to-expand disabled, tx panel hidden
- matched_bill_name included via LEFT JOIN bills in accounts query
- BillPickerDialog resets search/selection on open
- Link to bill: marks historical txs matched, stores merchant rule,
  applyMerchantRules catches other unmatched txs from same merchant
- Track (new subscription): creates bill with is_subscription=1, stores
  merchant rule for ongoing tracking
- SimpleFIN sync: applyMerchantRules runs after tx insert, auto-matches
  by merchant rule with payment_source='auto_match'
- Auto-match payments have transaction_id set, treated same as manual matches
- New services/billMerchantRuleService.js for rule storage and matching
- Migration for bill_merchant_rules table
2026-05-29 03:38:48 -05:00
null eeb26ccab1 feat: manual match/unmatch transactions to bills
Backend:
- POST /api/matches/confirm — atomic payment creation + transaction match
- POST /api/matches/:transactionId/unmatch — soft-delete payment, reset transaction
- Account transactions include matched_bill_id and matched_bill_name

Frontend:
- Unmatched transactions show + match pill button
- BillPickerDialog with transaction details + searchable bill list
- Confirm creates payment and updates row immediately
- Matched transactions show Unlink icon to remove match
- Toast on success with bill name and date
2026-05-29 03:02:36 -05:00
null c43c476ae9 fix: subscription recommendation dedup and amount-bucket grouping
- Amount-bucket grouping ensures consistent charges are grouped together
- Catalog lookup names and boosts the result
- Deduplication ensures one recommendation per known service
- Removed catalog-first rewrite
2026-05-29 02:51:30 -05:00
null 1d8ae4f511 fix: sync_days hard-clamped to 90 (SimpleFIN Bridge limit)
- bankSyncConfigService: SYNC_DAYS_MAX=90, getBankSyncConfig clamps on read,
  setSyncDays rejects >90 with explanation
- bankSyncService: every sync requests full sync_days window, dedup handles
  already-seen transactions
- dataSources status endpoint returns sync_days alongside enabled
- BankSyncAdminCard: input max 90, live clamp, description cites Bridge limit
- BankSyncSection: third stat tile showing History window X days
2026-05-29 02:23:19 -05:00
null 7682758aa8 fix: sync_days now reads from DB config, admin UI controls it
- bankSyncService: removed local syncDaysBack() reading env directly;
  sinceEpoch() now calls getBankSyncConfig().sync_days
- bankSyncConfigService: added setSyncDays() with 1-730 day validation
- routes/admin: PUT accepts sync_days alongside enabled/sync_interval_hours
- BankSyncAdminCard: Transaction history days input, loaded from config,
  defaults 90, dirty-checked on save
2026-05-29 01:33:54 -05:00
null 262d7789db feat: account monitoring, expanded sync UI, match filtering, error toasts
Backend:
- v0.64 migration: monitored column on financial_accounts
- GET/PUT data-sources accounts endpoints for monitored toggle + tx listing
- matchSuggestionService: excludes unmonitored accounts from match scoring

Frontend:
- BankSyncSection rebuild: accounts panel with monitored switch, expand for
  last 50 transactions, match status badges, optimistic toggle
- TransactionMatchingSection: toast on bills load failure
- DataPage: toast on import history load failure
- ProfilePage: toast on both login history fetch failures
2026-05-29 01:06:20 -05:00
null 542ab5e382 feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
  (DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both

#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
  score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch

#4 Encryption note in BankSyncAdminCard below worker status panel

Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
null b03264ceb1 feat: zero-config encryption + SimpleFIN Bridge links
- encryptionService.js: getKey() tries TOKEN_ENCRYPTION_KEY env first, then
  auto-generates a random 48-byte key on first startup, persists to settings
  as _auto_encryption_key. assertEncryptionReady() is now a no-op.
- bankSyncConfigService.js: removed encryption_key_set response and
  encryptionKeyReady() helper. No env config required.
- .env.example: TOKEN_ENCRYPTION_KEY removed. Comment says enable from Admin
  panel, no env config required.
- BankSyncSection.jsx: added SimpleFIN Bridge links — 'Open SimpleFIN Bridge'
  for first-time setup, 'Get a SimpleFIN token' for existing connections
2026-05-29 00:04:28 -05:00
null 3fea3931f5 style: AP badge next to bill name instead of blue dot
Tracker and mobile tracker rows now show a small AP badge
immediately to the right of the bill name, replacing the
blue dot on the left.
2026-05-28 23:50:03 -05:00
null 792980b8ba style: stronger late/missed payment visibility
- Tracker rows, mobile rows: alert icons, left-edge marker, stronger row tinting
- Calendar grid and detail dialog: brighter dots, count badges
- StatusBadge: stronger orange/rose badges for late/missed
- Shared badge component: clearer contrast
2026-05-28 23:42:46 -05:00
null a1f679f7b0 style: global readability/theme pass
- Sharpened font stack in index.css, removed softer Georgia digit font for UI text/money
- Tuned dark-mode tokens: clearer foreground, brighter muted text, stronger borders, defined cards
- Updated UI primitives: cards, buttons, inputs, selects, tables, badges
- Cleaned up bills rows, mobile bill rows, tracker dismiss, snowball icons, summary/category/health/analytics money values, import/export status icons
- Reduced fuzzy uppercase label spacing globally
2026-05-28 23:18:14 -05:00
null 7a58d69c70 feat: hybrid subscription tracker
Added subscription metadata to bills: is_subscription, type, reminder_days, source, detected_at
Backend subscription API (routes/subscriptions.js)
SimpleFIN recommendation logic (services/subscriptionService.js)
New /subscriptions page (client/pages/SubscriptionsPage.jsx)
Track-as-subscription controls in BillModal.jsx
Navigation under Tracker menu
Accepting a recommendation creates a subscription-backed bill + links detected transactions
2026-05-28 22:54:07 -05:00
null 22df64e5e7 feat: auto-sync worker for SimpleFIN bank sync
New:
  services/bankSyncWorker.js — interval-based worker running every 4h (configurable via SIMPLEFIN_SYNC_INTERVAL_HOURS)
    - Checks bank sync enabled, fetches oldest-synced sources, skips <1h old
    - Staggers syncs 3s apart, writes last_error on failure, timer.unref() for clean shutdown

Modified:
  server.js — starts worker inside app.listen callback
  routes/admin.js — GET bank-sync-config includes worker status (running, interval, last/next run)
  client/components/admin/BankSyncAdminCard.jsx — shows auto-sync worker status panel when enabled
  .env.example — SIMPLEFIN_SYNC_INTERVAL_HOURS
2026-05-28 22:32:33 -05:00
null 858f65b66b fix: BankSyncAdminCard toggle no longer gated on encryption key
- Removed disable logic and key warning banner from BankSyncAdminCard
- Toggle works freely regardless of TOKEN_ENCRYPTION_KEY status
- encryptionKeyReady and encryption_key_set left as informational only
2026-05-28 22:18:20 -05:00
null 88a4b64924 feat: DB-first bank sync config, admin toggle, extracted BankSyncSection
New:
  services/bankSyncConfigService.js — bank_sync_enabled from settings table, env fallback
  client/components/admin/BankSyncAdminCard.jsx — single toggle + encryption key status
  client/components/data/BankSyncSection.jsx — full connection management extracted from SettingsPage

Modified:
  routes/dataSources.js — per-request getBankSyncConfig() instead of module-level env check
  routes/admin.js — GET/PUT /api/admin/bank-sync-config
  AdminPage.jsx — renders BankSyncAdminCard after EmailNotifCard
  SettingsPage.jsx — BankSyncSection removed, 580->352 lines
  DataPage.jsx — BankSyncSection first, passes simplefinConn to TransactionMatchingSection
  TransactionMatchingSection.jsx — compact sync bar with green dot + Sync Now
  Layout.jsx — SimplefinBadge shows muted dot when enabled
  client/api.js — bankSyncConfig API calls
2026-05-28 22:06:15 -05:00
null 979886cb6a style: CalendarPage readability pass + DataPage fix
CalendarPage.jsx:
- Tightened day numbers, due-count badges, bill labels inside cells
- Crisper color contrast for paid/due/missed states
- Cleaner grid surfaces and borders for row/day tracking
- Switched font-mono values to tracker-number style

SeedDemoDataSection.jsx:
- Fixed render logic for data page
2026-05-28 21:40:27 -05:00
null 42abb12497 feat: SimpleFin bank sync with encrypted token storage
New services:
  services/encryptionService.js — AES-256-GCM with SHA-256 derived key
  services/simplefinService.js — protocol layer: claim token, fetch accounts/transactions, normalize to DB shapes
  services/bankSyncService.js — orchestration: connect, sync, disconnect with encrypted access URL storage

Modified:
  routes/dataSources.js — status, connect, sync, disconnect endpoints (gate on BANK_SYNC_ENABLED=true)
  client/api.js — simplefinStatus, connectSimplefin, syncDataSource, deleteDataSource, dataSources
  client/pages/SettingsPage.jsx — BankSyncSection with connected account info, sync/disconnect actions, setup token input
  .env.example — BANK_SYNC_ENABLED, TOKEN_ENCRYPTION_KEY, SIMPLEFIN_APP_NAME
2026-05-28 21:30:20 -05:00
null 994b5c1e17 feat: spending forecast with linear regression chart
Analytics page additions:
- linearForecast(rows, horizonMonths) — OLS regression producing projected,
  low, and high (±1σ residual) for each future month
- ForecastChart — SVG line chart: solid historical line + area fill, dashed
  projected line, translucent confidence band, divider line at forecast start,
  legend for Historical and Projected ± 1σ
- Forecast added to CHART_OPTIONS (on by default)
- Forecast dropdown: 3/6/12 month horizon (default 6)
- Controls grid expanded to 7 columns
- Forecast card spans full width below heatmap
- Projection table: Month / Projected / Low / High columns
- Reset filters resets forecast to 6 months
2026-05-28 21:11:29 -05:00
null 71dfbe36cc refactor: component splits, PWA support, CommandPalette
Component Splits:
  - AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
  - DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
  - TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)

PWA:
  - vite-plugin-pwa installed with NetworkFirst caching for API routes
  - Square PWA icons (192x192, 512x512, apple-touch-icon)
  - theme-color, apple meta tags, touch icon in index.html
  - Build generates dist/sw.js + Workbox runtime

CommandPalette:
  - Navigation commands, Add bill action, month jumps
  - Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
null 92cc667947 chore: bump version to v0.28.4.4 2026-05-28 20:14:00 -05:00
null 33e5c187a3 dark theme 2026-05-28 19:58:01 -05:00
null d99ea8057e dark theme 2026-05-28 19:40:55 -05:00
null 1f3a254c7c brighten dark mode 2026-05-28 19:30:46 -05:00
null 0fd82568cc georgia font 2026-05-28 04:20:15 -05:00
null 8f7d0aeaff styling 2026-05-28 04:06:37 -05:00
null 8efb7c934d fix suggested 2026-05-28 02:53:59 -05:00
null 8122d07069 inline editing 2026-05-28 02:53:35 -05:00
null 1426ee3bb5 error handling 2026-05-28 02:34:24 -05:00
null e8218a3dd8 bill tracker futurue 2026-05-28 02:09:49 -05:00
null fa60ea8fbd fix paid coloum 2026-05-28 01:38:18 -05:00
null a811589db4 theme correctness 2026-05-28 01:30:40 -05:00
null 82de135186 push 2026-05-18 09:44:16 -05:00
null 060c8dc2f4 chore: version bump to 0.28.01 and update HISTORY format 2026-05-16 21:36:04 -05:00
null 9d933f70cc v0.28.01 2026-05-16 20:26:09 -05:00
null b124e48ebc v0.28.0 2026-05-16 15:38:28 -05:00
null 8913436575 v0.28.0 2026-05-16 11:56:38 -05:00
null 53670b3745 v0.28.0 2026-05-16 11:42:32 -05:00
null 88c1374d97 v028.0 2026-05-16 10:56:56 -05:00
null 59d9d21d4c v0.28.0 2026-05-16 10:34:32 -05:00
null 9174ec3290 v0.28. 2026-05-16 10:17:24 -05:00
null 0ba315bd32 v0.28.0 2026-05-15 22:45:38 -05:00
null 74603ff2d5 v0.27.04 2026-05-15 04:22:33 -05:00
null 153ed7ab79 v0.27.04 2026-05-15 02:26:10 -05:00
null 48dcb480ba v0.27.04 2026-05-15 01:49:55 -05:00
null 263f1c5e6e v0.27.04 2026-05-15 01:36:56 -05:00
null 576163e85b apr/snowball 0.27.04 2026-05-15 00:03:32 -05:00
null d720931894 v0.27.02 push 2026-05-14 21:00:07 -05:00
null eea5641126 snowball visuals 2026-05-14 19:33:23 -05:00
null 7aff0d0283 snowball ui fiix 2026-05-14 03:23:52 -05:00
null ce22139bb3 chore: bump version to 0.27.01 2026-05-14 03:01:47 -05:00
null 440f872d97 snowball bug fixes 2026-05-14 03:00:01 -05:00
null 7d2d0bf45e 0.28.0 snowball release 2026-05-14 02:11:54 -05:00
null 48fe87ea25 corrections 2026-05-14 01:17:05 -05:00
null 34b0f75918 v0.26.1: fix dual-column XLSX parser bugs
- Rewrite detectAllHeaderSets() with repeat-field detection instead of gap-based splitting
- Require ≥2 header fields per group (filters out false matches like 'Left Over | Paid')
- Fix column leakage: right-side bills no longer pick up left-side amounts
- Add header_set_index to analyzeRow return object for frontend use
- Add isLikelySummaryRow() filter (Paycheck, Left Over, Enter how much, etc.)
- Expand isLikelyTotalRow() to catch 'Auto Total ------>' patterns
- Filter leftover calc rows (null name + negative amount, dash separators)
- Remove 'paid' from HEADER_PATTERNS.amount (was false-matching 'Paid' cells)
- Skip empty string cells in detectAllHeaderSets
2026-05-11 23:17:19 -05:00
null 831f617893 v0.26.0: dual-column XLSX import parser
- detectAllHeaderSets() finds multiple header groups per row (left 1st / right 15th)
- isBlankRowForHeaderSet() checks blanks per column range for dual layouts
- parseSheetRows() scans rows 0-4 for header row, processes each set independently
- analyzeRow() computes due_day from date/label/pattern with fallback to defaultDueDay
- Cell type validation allows 's' (shared formula) type
- Non-numeric amounts (auto, double pay, past due) become detected labels
- Day patterns (1st, 15th, 24th) parsed as due_day values
- Security: bounds validation in isBlankRowForHeaderSet, anchored regex, label sanitization
2026-05-11 22:13:37 -05:00
null 2ce5328fd2 v0.25.0: roadmap redesign, import CSRF fix, AdminDashboard removed
- RoadmapPage: kanban-style priority lanes, shadcn Collapsible/Tabs,
  lazy-loaded activity log, admin-only /api/about/roadmap + /dev-log endpoints
- Import CSRF fix: added x-csrf-token header to importAdminBackup,
  previewSpreadsheetImport, previewUserDbImport raw fetch() calls
- Removed AdminDashboard.jsx, replaced by RoadmapPage
- Added @radix-ui/react-collapsible + collapsible shadcn component
- Security audit by Private_Hudson: PASS (CSRF fix verified,
  admin endpoints gated, path traversal mitigated, XSS safe)
2026-05-11 21:42:36 -05:00
null 98ede20cd3 fix: prevent duplicate payment prompts 2026-05-11 16:04:21 -05:00
null 22f9a570aa v0.24.5: starting amounts fix, pay badge alignment, demo data persistence 2026-05-11 15:25:04 -05:00
null b29d3a0b02 fix: starting amounts paid_from_other calculation + pay badge alignment on tracker 2026-05-11 15:00:35 -05:00
null 890427c75a v0.24.3: Session fixes, activity log corrections, UI polish 2026-05-11 13:39:48 -05:00
null c1ac14efe3 v0.24.4: analytics mobile layout + previous month payment toggle 2026-05-11 11:56:49 -05:00
null 86148a101f feat: remove confirmation popup from status badge toggle (v0.24.3)
Clicking status badges (Late, Due Soon, Upcoming, Missed) now instantly
toggles paid/unpaid. Removed AlertDialog from TrackerPage.jsx — no more
confirmation dialog blocking the action.
2026-05-10 17:56:23 -05:00
null 6d42453e07 fix: status badge toggle-paid using wrong property name (v0.24.2)
handleTogglePaid() was using row.bill_id instead of row.id, causing
the API call to fail with an undefined bill ID. Clicking status badges
(Late, Due Soon, Upcoming, Missed) now correctly toggles paid/unpaid.
2026-05-10 17:28:26 -05:00
null ba888c1c6f feat: export privacy warning + updated included fields list (v0.24.1)
- Added amber warning banner on Download My Data section about sensitive metadata
- Updated 'What's included' list to show monthly starting amounts and history ranges
- Marked LOW export sensitive fields item as FIXED in FUTURE.md
2026-05-10 15:29:35 -05:00
null 80b3bcc17b fix: HIGH+MEDIUM batch — 10 fixes (v0.24.0)
HIGH:
- Admin toggle-paid: removed cross-user admin branch, now requires ownership
- Analytics crash: imported missing standardizeError
- Export data loss: added cycle_type, cycle_day, bill_history_ranges to exports
- Single-user lockout: removed unnecessary sessions join from getSingleModeUser

MEDIUM:
- Password rate limiter: scoped to change-password only, not all profile routes
- Profile session invalidation: fixed req.sessionId → req.cookies[COOKIE_NAME]
- CSRF default: httpOnly now defaults to false (matches SPA double-submit pattern)
- CSRF password routes: removed csrfSkip for password change endpoints
- Notification due-day: calendar day comparison instead of timestamp floor
- Upcoming bills: clamped days to 1-365, default 30 for invalid input

FUTURE.md: marked all 10 items as FIXED, bumped version refs
HISTORY.md: added v0.24.0 entry
2026-05-10 15:25:47 -05:00
null 5537ab2bd5 fix: clear demo data button, seed user ID bug, duplicate endpoint (v0.23.4)
- DataPage: removed 'coming soon' placeholder, made Clear Demo Data button accessible from seeded state
- seedDemoData.js: fixed userId -> targetUserId bug
- settings.js: removed duplicate /api/settings/seed-demo-data endpoint
- Version bumped to 0.23.4
2026-05-10 15:11:02 -05:00
null 5eed5932b4 feat: replace native confirm() with shadcn/ui AlertDialog (v0.23.3)
- TrackerPage: confirm('Mark as paid?') → AlertDialog with dynamic bill name
- DataPage: window.confirm('Import SQLite?') → AlertDialog for import confirmation
- Both dialogs use proper shadcn/ui components (AlertDialogAction/Cancel)
- Theme-aware, accessible, consistent with app design system
- STRUCTURE.md: corrected tech stack (Vite+React, not Next.js)
- Version bumped to 0.23.3
2026-05-10 14:36:59 -05:00
null 6b1ef7dcfa fix: notification privacy leak — per-user bills no longer sent to all recipients (v0.23.2)
CRITICAL security fix: In per-user notification mode, the notification runner
was fetching ALL active bills globally and sending each bill's details to
every opted-in recipient regardless of ownership. This meant User A's bill
names, amounts, and due dates could be emailed to User B.

Fix: Added ownership filter in the recipient loop:
  if (allowUserConfig && bill.user_id !== recipient.id) continue;

Also added a defensive guard for bills with no user_id (orphaned bills),
which are now skipped with a console.warn instead of being broadcast.

Global notification mode (single admin recipient) is unaffected.

Security audit: Private_Hudson confirmed the fix is airtight. All other
routes (bills, payments, tracker, analytics, export, calendar, summary,
categories) properly scope data by user_id.

Version bump: 0.23.1 → 0.23.2 (security patch)
2026-05-10 12:34:53 -05:00
null 52db06001f v0.23.1: migration rollback capability
- Add rollbackMigration() function in db/database.js with transaction safety
- Add POST /api/admin/migrations/rollback endpoint (admin-only)
- Rollback SQL for v0.44 (indexes), v0.45 (audit_log table), v0.46 (cycle columns)
- Error codes: NOT_APPLIED (404), ROLLBACK_NOT_SUPPORTED (422)
- Audit logging for rollback events
- Fix duplicate migrationStartTime declaration from v0.23.0 commit
- Fix broken migration completion audit log from v0.23.0 commit
- Fix DB path exposure (uses path.basename() now)
2026-05-10 10:44:39 -05:00
null 53783aaec5 v0.23.0: Detailed migration logging with timing, error context, and audit logging
- Added [migration] logging for each migration step (applying, completed, timing)
- Added [migration-error] logging with elapsed time on failures
- Added [migration] All migrations completed in Xms total timing
- Added lazy getLogAudit() for audit logging of migration failures (avoids circular dep)
- Changed DB path log to basename only (Hudson rec: reduce info disclosure)
- Version bumped to 0.23.0
2026-05-10 09:45:39 -05:00
null eb86da1e69 v0.22.3: fix ENV-seeded users skip first-login flow, add audit logging
- setup/firstRun.js: reset first_login=0, must_change_password=0 on update
- server.js: reset flags for existing regular users + add logAudit
- db/database.js: fix must_change_password=0 in init code (was 1)
- Add logAudit calls for seed.flag_reset events
- database.js uses console.log for init-time resets (avoids circular dep)
- Hudson audit: 6/6 PASS after audit logging fix
2026-05-10 04:24:51 -05:00
null c4a3593241 v0.22.2: Session Token Rotation on Auth Events
- invalidateOtherSessions() in authService.js: deletes all sessions except current
- Password change (auth.js + profile.js) now invalidates all other sessions
- Password change rotates current session ID (sets new cookie)
- New POST /api/auth/logout-all endpoint (deletes all sessions + clears cookie)
- Audit logging for logout.all and password.change
- Added last_password_change_at to auth.js change-password for consistency
- Hudson security audit: 6/6 PASS
2026-05-10 03:55:14 -05:00
null 65849fc554 v0.22.1: N+1 Query Optimization
- Batch queries replace per-bill loops in tracker and analytics
- monthly_bill_state, payments, prev month payments batched with WHERE IN
- Empty billIds guards prevent SQL errors
- Hudson security audit: 5/5 PASS (SQL injection, empty IN, user scoping, data leakage, type safety)
2026-05-10 03:29:09 -05:00
null d67fe6e61d v0.22.0: React Query Migration
- Added @tanstack/react-query and @tanstack/react-query-devtools
- Created useTracker, useBills, useCategories custom hooks (useQueries.js)
- Migrated TrackerPage from manual useState/useEffect to useQuery
- Added QueryClientProvider with 2min staleTime, 1 retry, refetchOnWindowFocus: false
- Added ReactQueryDevtools for development
- Fixed error handling: useRef pattern prevents duplicate toast notifications
- Replaced load() callback with refetch() from useQuery
- Hudson security audit: 4/5 PASS (1 FAIL fixed: error handling toast duplication)
2026-05-10 03:10:43 -05:00
null 314159d241 v0.21.1: Loading Skeletons & Async State
- Reusable Skeleton component (line, circle, card, button, input variants)
- TrackerPage: skeleton cards, rows, buckets with aria-busy attributes
- BillsPage: skeleton rows during loading
- Bug fix: double closing brace />}} on Bucket component
- Hudson security audit: 5/5 PASS
2026-05-10 01:35:41 -05:00
null cfb074c7cd v0.21.0: 3-Month Trend Indicator on Tracker
- Backend: 3-month payment aggregation with year-wrapping, trend object in API (direction, percent_change, 3_month_avg)
- Frontend: TrendIndicator component (arrow + percentage + label), TrendCard with purple gradient
- Bug fix: Bishop fixed 3-month query to JOIN through bills for user scoping (payments table has no user_id)
- Bug fix: Ripley removed duplicate TrendIndicator function definition
- Hudson security audit: 5/5 PASS (SQL injection, user scoping, date wrapping, division by zero, XSS)
2026-05-10 01:22:51 -05:00
null 4990bf47f6 v0.20.9: Previous Month Paid column on Tracker
- Backend: previous month calculation with year wrapping (Jan→Dec)
- Backend: previous_month_paid per bill row, previous_month_total in summary
- Frontend: 'Last Month' column in desktop table with muted text
- Frontend: 'Last Month' in mobile view, summary card for prev month total
- Hudson security audit: 5/5 PASS (SQL injection, date wrapping, user scoping, auth, XSS)
2026-05-10 00:52:23 -05:00
null bd796d61c0 v0.20.8: Billing cycle sub-categories + server-side cycle_day validation
- Migration v0.46: cycle_type (monthly/weekly/biweekly/quarterly/annual) and cycle_day columns
- Server-side validation: cycle_type whitelist, cycle_day validated per type
  - monthly: 1-31 integer
  - weekly/biweekly: day name enum
  - quarterly/annual: free text (max 50 chars)
- BillModal UI: conditional cycle_day selector (ordinal/weekday/text)
- Hudson audit: 4/5 PASS, fixed medium-risk cycle_day validation gap
2026-05-10 00:39:11 -05:00
null e184fed88a v0.20.7: Keyboard navigation and ARIA accessibility
- Skip-to-content link for keyboard users (sr-only/focus:not-sr-only pattern)
- aria-expanded and aria-haspopup on Tracker menu dropdown
- aria-label on footer, role='main' and aria-labelledby on layout wrapper
- Main content wrapped in <main> with unique id from React useId()
- Fixed build error: useId imported from react, not react-router-dom
- Hudson security audit: 5/5 PASS (no XSS, no DOM clobbering, no injection)
2026-05-10 00:18:36 -05:00
null 7503a54f81 v0.20.6: Audit logging for critical operations
- New audit_log table (migration v0.45) with indexes
- logAudit() service with try/catch safety (never crashes app)
- Audit events: login.success, login.failure, logout, password.change, role.change, csrf.failure, profile.update, profile.settings.update
- All events include ip_address and user_agent
- No passwords, tokens, or session IDs logged
- Hudson security audit: 7/7 PASS
2026-05-10 00:03:12 -05:00
null 8e7f977fef v0.20.5: Bulk payment input validation
- Request body must contain `payments` array (breaking change from raw array)
- Max 50 items per bulk request
- Per-item validation: bill_id (integer regex + parseInt), paid_date (YYYY-MM-DD), amount (finite number >= 0)
- Duplicate detection using bill_id + paid_date + amount composite key — skipped, not rejected
- Response format: { created, skipped, errors }
- Security fix: bill_id type coercion attack (parseInt('1abc') bypass) blocked via regex check
- Security fix: Infinity amount bypass blocked via isFinite() check
- Hudson audit: 5/7 PASS, 2 FAIL fixed (type coercion + Infinity)
2026-05-09 23:41:28 -05:00
null 35e09430c9 v0.20.4: Explicit migration dependency management
- Added dependsOn field to all 17 versioned migrations
- Added validateMigrationDependencies() function for dependency validation
- Migrations with unmet dependencies are skipped with error log (no crash)
- Dependency satisfaction logged: [migration] vX depends on [vY] — satisfied
- appliedVersions Set tracks newly applied migrations for subsequent checks
- Hudson security audit: 7/7 PASS
2026-05-09 23:24:51 -05:00
null 1fd4f49758 v0.20.3: Performance indexes on frequently queried columns
- Added v0.44 migration with 4 indexes:
  - idx_bills_user_name ON bills(user_id, name)
  - idx_payments_method ON payments(method)
  - idx_monthly_starting_amounts_user ON monthly_starting_amounts(user_id)
  - idx_import_history_imported_at ON import_history(imported_at)
- Fixed nested transaction bug in migration run() function
- Hudson security audit: 7/7 PASS
2026-05-09 22:44:38 -05:00
null d34316844e v0.20.2: Transaction wrapping for database migrations
- All migrations (versioned, legacy, unversioned) now run within
  BEGIN/COMMIT with ROLLBACK on failure
- v0.40 migration uses try/finally to guarantee PRAGMA foreign_keys
  is always re-enabled, even on error paths
- Clear transaction boundary logging (BEGIN/COMMIT/ROLLBACK)
- Hudson security audit: 6/7 PASS, FK fix applied for v0.40 edge case
2026-05-09 22:34:50 -05:00
null 0cd8423a19 v0.20.1: code splitting, version badge on roadmap, roadmap nav link
- React.lazy + Suspense for all page components (except LoginPage)
- PageLoader component for loading states
- Version badge on admin roadmap page
- Version in /api/about-admin response
- Roadmap nav link for admins (dropdown + sidebar)
- /admin/roadmap route
2026-05-09 22:01:19 -05:00
null d8888af845 feat: add Roadmap nav link for admins
- Added Roadmap link in dropdown menu (below About), admin-only
- Added Roadmap in admin sidebar nav
- Added /admin/roadmap route pointing to AboutPage with admin prop
- Uses Map icon from lucide-react
2026-05-09 21:26:39 -05:00
null 852da29b4d v0.20.0: admin dashboard with roadmap and activity log
- New AdminDashboard component with Roadmap and Activity Log
- Color-coded priority cards (🔴🟠🟡🔵💭) with collapsible sections
- CRITICAL/HIGH expanded by default, others collapsed
- Activity log shows DEVELOPMENT_LOG entries in reverse chronological order
- Admin-only rendering, non-admins see standard About page
- Custom scrollbar styles for admin panels
- Version bumped to 0.20.0 (Bishop)
2026-05-09 21:14:21 -05:00
null c04d3ba27e v0.19.4: bump version to 0.19.4 in package.json and login screen 2026-05-09 20:25:05 -05:00
null 9d257d9d5e v0.19.2: update version to 0.19.2 in version.js and package.json 2026-05-09 18:52:00 -05:00
null 4e91bed343 v0.19.2: add React Error Boundaries for crash recovery
Added ErrorBoundary component wrapping all routes in App.jsx.
Shows friendly fallback UI with Try Again and Reload buttons
instead of white screen crash. Logs component stack to console.
2026-05-09 18:33:02 -05:00
null a9cdf846fe v0.19.2: fix legacy DB migration login failure + security hardening
CRITICAL fix: Users upgrading from pre-migration-tracking databases
(now get 'invalid username/password' because schema_migrations table
doesn't exist. Added handleLegacyDatabase() and
reconcileLegacyMigrations() to detect and reconcile legacy DBs.

Security fixes:
- Path traversal: replaced sanitizePath() with ALLOWED_FILES allowlist
- Public /about bypass: added admin route guard in App.jsx
- Sensitive info exposure: expanded redactSensitiveContent() patterns
- Error message path leaks: generic error messages only
- Race condition: wrapped in db.transaction() in server.js
- Password validation: INIT_REGULAR_PASS min 8 chars with process.exit(1)

All verified by Bishop (build + runtime) and Private_Hudson (security).
2026-05-09 18:25:25 -05:00
null 6c7d481494 feat: add admin about page with security hardening
- Add /api/about-admin endpoint (admin-only, path traversal protection, content redaction, error sanitization)
- Add /admin/about route with RequireAuth admin guard
- Add adminActionLimiter rate limiting on about-admin endpoint
- Add rehype-sanitize XSS prevention in AboutPage.jsx
- Add aboutAdmin API client endpoint
- Create HISTORY.md with version bump convention (patch/minor/major)
- Update Engineering Reference Manual with about-admin docs and security measures
- Add INIT_REGULAR_USER/INIT_REGULAR_PASS env vars to docs
- Update FUTURE.md with critical regular user env var item
2026-05-09 16:25:12 -05:00
kaspa 4d1709aea3 push 2026-05-09 13:03:36 -05:00
_null 3228332e8c push 2026-05-04 23:34:24 -05:00
_null d1efeece04 push 2026-05-04 20:12:57 -05:00
_null b019487423 init 2026-05-04 16:38:03 -05:00
_null 9fc442fb8e readme 2026-05-04 13:38:19 -05:00
_null 969139251d calendar 2026-05-04 13:14:32 -05:00
_null d46b85da8a logo 2026-05-03 22:33:21 -05:00
_null 734e190884 corrected admin view 2026-05-03 20:40:48 -05:00
_null b9d1366d46 initial commit 2026-05-03 19:51:57 -05:00