Commit Graph

167 Commits

Author SHA1 Message Date
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 820fedd58e feat: subscription catalog migration, 200-row seed, improved detection
db/database.js:
- Added monitored to COLUMN_WHITELIST
- runSubscriptionCatalogMigration() creates table + seeds 200 rows
- Migration v0.65 in both legacy reconciliation and main migrations

services/subscriptionService.js:
- SUBSCRIPTION_TYPES expanded 10→14 (food, education, shopping, security)
- TYPE_KEYWORDS updated with 30 new keywords across categories
- loadCatalog() loads 200 entries per recommendation call, graceful [] on old DBs
- lookupCatalog() longest-match wins, handles embedded domains
- inferType() catalog hit takes priority over keyword guessing
- Two-tier detection: catalog 1-hit → possible (62), 2+ → pattern/confirmed with boost (68-99)
- Canonical names from catalog, type auto-filled
- buildRecommendation() extracted as shared helper with tier + catalog_match fields
- createSubscriptionFromRecommendation sets subscription_source to catalog_match
2026-05-29 01:51:42 -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 6c1b02e613 fix: remove premature idx_payments_transaction_active from schema.sql
The index referenced transaction_id which is only added by migration v0.59.
On existing databases CREATE TABLE IF NOT EXISTS is a no-op, so the index
creation crashed before migrations could run. v0.61 creates it correctly
after the column exists. Fresh installs still get it via normal migration.
2026-05-28 23:33:45 -05:00
null 1b9518a5d7 fix: migration dedup and legacy reconcile gaps
- Removed double log line in runMigrations (migration name printed twice)
- Added v0.54 (user_settings) and v0.55 (user_login_history device metadata) to reconcileLegacyMigrations
- Both are idempotent, no data was ever lost, but legacy upgrades were re-running them unnecessarily
2026-05-28 23:28:53 -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 f84d1967f2 chore: bump version to v0.29.2 2026-05-28 22:09:24 -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 1c8d754068 chore: bump version to v0.29.1 2026-05-28 21:32:18 -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 c0cb02dbd9 fix: Node 18->22 in Dockerfile for terser compat
Dockerfile was pinned to node:18-alpine which can't load crypto
synchronously in @rollup/plugin-terser -> serialize-javascript.
Upgrading build stage to node:22-alpine to match host Node.
2026-05-28 20:57:33 -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 3b44fe3cbc chore: bump version to v0.28.4.3 2026-05-28 19:58:48 -05:00
null 33e5c187a3 dark theme 2026-05-28 19:58:01 -05:00
null f8b88350d9 chore: bump version to v0.28.4.2 2026-05-28 19:41:11 -05:00
null d99ea8057e dark theme 2026-05-28 19:40:55 -05:00
null 6d42dd9a29 chore: bump version to v0.28.4.1 2026-05-28 19:32:51 -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 726b80c765 chore: bump version to v0.28.4 2026-05-28 04:07:11 -05:00
null 8f7d0aeaff styling 2026-05-28 04:06:37 -05:00
null 8cab248959 security fixes 2026-05-28 03:59:35 -05:00
null d3f2a921bf no exploitable SQL injection vulnerabilities 2026-05-28 03:43:50 -05:00
null f1692193f6 chore: bump version to v0.28.3 2026-05-28 02:59:59 -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 33f1bfd3c2 chore: bump version to v0.28.2 2026-05-28 02:37:50 -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