Commit Graph

43 Commits

Author SHA1 Message Date
null 522eaaf101 chore(deps)!: tailwind 3 -> 4 via @tailwindcss/vite (4i)
Official codemod (run in a clean worktree; docker-owned data/ blocks it
in-tree): tailwind.config.js inlined into client/index.css as CSS-first
@theme/@utility (config file deleted — v4 auto-detects content, which
also retires the .tsx-content-glob failure class from the TS migration),
33 template files' class renames applied, tailwindcss-animate loads via
the v4 @plugin bridge. Build runs through @tailwindcss/vite; postcss
config is now plugin-free. tailwind-merge -> 3 (v4 class model).

Visual-regression gate: only diffs were a ~2px global preflight shift +
the version string (baseline predated 0.41.1); re-baselined both login
screenshots in this commit after review. webauthn.probe confined to the
probe project (it enables WebAuthn for the seeded user, racing the
parallel UI projects' password logins).

e2e 27 passed, probe 18/18, PROD SMOKE PASS, typecheck/lint/tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:03:15 -05:00
null 1238ac5b14 feat(demo): full "take it for a ride" seed + surgical, correct removal
The demo seeder created bills + categories only, so nearly every page
rendered empty; clear-demo had a data-loss bug and error-protection gaps.

Seed now populates every user-facing surface: bills with autopay states,
3-6 months of payment history (with drift + debt paydown), monthly
skips/overrides/snoozes/notes, a demo bank source + accounts + matched/
unmatched/subscription transactions, categorised spending + budgets +
rules, planning income/starting-amounts, category groups, an active
snowball plan (+ extra-payment), merchant rules, and a calendar feed —
so a new user can explore Tracker (incl. overdue/drift), Analytics,
Summary, Spending, Snowball, Payoff, Transactions, Matches, Subscriptions,
Banking and Calendar with realistic data.

Correct removal (the emphasis):
- Migration v1.07 adds an is_seeded marker to the 12 user-scoped,
  non-cascading demo tables (bill-children cascade with their seeded bill).
- clearSeededDemoData() (new, in userDataService alongside eraseUserData)
  removes ONLY seeded rows in one transaction, child->parent, and keeps a
  seeded category if a user's own bill still references it.
- Fixes the category collision: seed marks ONLY categories it creates, so
  clear no longer deletes the user's default categories / uncategorises
  their real bills.

Error protection: idempotency guard on seeded (not all) bills -> 409
instead of a fake "created 0"; whole seed wrapped in one transaction
(atomic); rate-limit + audit + standardizeError on all three routes;
seeded-status reports payments/transactions counts; dead --force removed.
Client copy/counts corrected.

Verified: typecheck/check clean; server suite 232/232 (+6 new); client
typecheck/lint/build clean; e2e probe 17/17; on a COPY of the real prod
DB the v1.07 migration applies (integrity ok) and a seed->clear round-trip
on the data-rich user restores their real data byte-for-byte with no
orphans.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 13:06:47 -05:00
null 1807456da7 refactor(brand): adopt new primitives in admin + data + dialogs
The remaining per-file 2-4 line adjustments land here: the admin
cards (EmailNotifCard, UsersTable), the bank-sync section, and the
two cross-cutting dialogs (ReleaseNotesDialog, SearchFilterPanel)
adopt the same BrandGlyph / TonedCard / SectionHeading imports as
the rest of the app. Each file is independently buildable on top of
the previous 6 commits.

This is commit 7 of 9 in the v0.42.0 brand refresh. Depends on
0eb024d (pages).
2026-07-05 17:19:03 -05:00
null 88874f3f3d feat(tracker): export/print the month + calendar link (plan C1/C2)
- Header "Export" menu: Export CSV (via the existing /api/export?from&to date
  range for the viewed month) and Print (window.print()). Extract the shared
  downloadFile blob helper to lib/download.ts (reused by DownloadMyDataSection).
- Add api.exportRangeUrl(from, to, fmt).
- Tracker-scoped @media print CSS: hide interactive chrome (.tracker-print-hide),
  keep the month title + summary + buckets, avoid splitting a row across pages.
- Header "Calendar" button deep-links to /calendar?year&month; CalendarPage now
  reads those params as its initial month (falls back to today).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 14:49:09 -05:00
null 03009e2a83 refactor(client): de-duplicate parseUtc + settingEnabled to lib/utils (plan A2/A3)
- Extract parseUtc (was copy-pasted in 4 files) and settingEnabled (3 copies,
  one named settingsBool) into client/lib/utils.ts as the single source.
- Replace all local copies with the shared import.
- Add tracker_show_safe_to_spend to the tracker's local settings defaults so it
  matches SettingsPage's list (behavior unchanged; aligns the two sources).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 14:38:12 -05:00
null 80fb0043b6 refactor(ts): convert ImportSpreadsheetSection to TypeScript — data/ dir complete
The XLSX importer (workbook parse → per-row decision tree → bulk actions →
bill-history grouped import). Typed PreviewRow/Decision/BillGroup/ImportDetail
and the merged BillImportResult accumulator; fixed Date subtraction in the
duplicate-date sort to use getTime(). Dropped two unused imports (CountPill/fmt)
the original .jsx never used. Trimmed unused eslint-disable directives.

This completes the entire client/components/data/ directory (14 files) → .tsx.
typecheck 0, lint 0 errors, build green.
2026-07-04 21:56:04 -05:00
null 0cc5cbd957 refactor(ts): convert BankSyncSection to TypeScript
SimpleFIN connect/sync/backfill/accounts + bank-budget-tracking + auto-categorize.
Branded Cents on account/tx amounts, Dollars on financial-account balances.
Dropped unused sourceId/bills props on AccountRow. typecheck 0, build green.
2026-07-04 21:46:55 -05:00
null 5a2e37fd61 refactor(ts): convert data/ import + matching sections to TypeScript
ImportMyData (SQLite), ImportTransactionCsv, TransactionMatching sections.
Branded BankTransaction/Bill/Category flow through the matching workbench;
relaxed BillModal initialBill to Partial<Bill> (it's a pre-filled draft).

TypeScript caught a real bug: ImportTransactionCsvSection used <CountPill> 6×
but never imported it — a ReferenceError that crashed the CSV preview/results
views. Added the missing import.

typecheck 0, build green.
2026-07-04 21:42:18 -05:00
null dfedb75e6d refactor(ts): convert data/ shared + small sections to TypeScript
dataShared (SectionCard/CountPill/importErrorState), DataNav, ConnectionHero,
DownloadMyData/Erase/SeedDemo/ImportHistory/AutoMatchReview/ImportOfx sections.
Branded Cents on OFX preview txns, Dollars on auto-match amounts; SectionCardProps
exported for section cardProps passthrough. typecheck 0, build green.
2026-07-04 21:33:25 -05:00
null b8d394061b fix(client): resolve all 13 exhaustive-deps warnings (R2b)
- BankSyncSection: handleBtSave read btLateGraceDays but it was missing from the
  useCallback deps -> saving could persist a STALE late-grace value (real bug).
- ProfilePage: EditProfile sync effect now depends on [profile].
- Stabilized identity of derived arrays/objects feeding useMemo deps (they were
  recreated every render, defeating memoization): TrackerPage filters + rows,
  HealthPage bills, BankTransactionsPage transactions -> wrapped in useMemo.
- BillModal + TransactionMatchingSection: intentional id/filter-scoped effects
  documented with a targeted eslint-disable + reason.
- Removed 2 stale eslint-disable directives (confirm-dialog, useAuth).

exhaustive-deps + rules-of-hooks now both 0. Build + client tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 19:47:14 -05:00
null 5e267e4fa7 fix(client): fix ESLint errors — real latent bugs (R2a)
ESLint surfaced 6 errors, incl. real bugs invisible before:
- ImportTransactionCsvSection called importErrorState() without importing it —
  its own error handler would throw ReferenceError on a failed CSV import.
- client/components/MobileTrackerRow.jsx was a dead duplicate (unused; the live
  one is tracker/MobileTrackerRow.jsx) with undefined-setter refs → deleted.
- StatusPage dbOk had a dead '?? true' (constant boolean LHS) — restored the
  intended default-true-when-unknown.
- MobileBillRow redundant !! in a ternary condition.
Lint is now 0 errors; wired 'npm run lint' into 'npm run ci'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 19:42:52 -05:00
null d53a64b604 feat(data): "Erase my data" danger zone (Batch 5)
New services/userDataService.js eraseUserData() permanently wipes a user's
financial + imported data in one transaction (child → parent order for FK
safety): bills (+ cascading payments/monthly_bill_state/bill_history_ranges),
transactions/accounts/data_sources, categories/groups, templates, snowball,
spending rules/budgets, merchant rules, imports, and per-user hint tables. It
PRESERVES the account, sessions, 2FA/WebAuthn, login history and preferences —
this resets your data, not your account — then re-seeds default categories and
writes an audit row to import_history.

- POST /api/user/erase-data — rate-limited (demoDataLimiter), requires a
  type-to-confirm token ("ERASE"), structured errors.
- UI: EraseDataSection danger-zone card (Export & backups pane) — red-accented,
  "download a backup first" nudge, type-to-confirm AlertDialog, toasts; on
  success DataPage reloads all state.

Tests: tests/eraseUserData.test.js — wipes user A only, preserves user B +
account + session, re-seeds categories, audited. Server 139 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:21:07 -05:00
null 314e4ff45e feat(export): JSON export + date-range/format payments export (Batch 4)
- GET /api/export now accepts a date range (?from=&to= on paid_date) in addition
  to ?year=, for CSV or JSON; filename derived from the range. Validates the
  range (both bounds, from<=to).
- New GET /api/export/user-json — full portable JSON of the user's data, reusing
  the same getUserExportData assembly as the SQLite/Excel exports (money via
  fromCents).
- UI (DownloadMyDataSection): a JSON export card plus a "Payments export" with
  From/To dates and a CSV/JSON toggle; shared blob-download helper; toasts and
  client-side range validation.

Tests: tests/exportRicher.test.js (JSON assembly in dollars, year vs range
filtering, CSV filename, bad-range rejection). Server 134 pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:15:36 -05:00
null bd1eee00b0 feat(import): OFX/QFX transaction import (Batch 3)
New services/ofxImportService.js parses OFX 1.x (SGML, unclosed leaf tags),
OFX 2.x (XML) and QFX (+ Intuit tags ignored) into the same normalized shape the
CSV path produces, then writes through the SAME shared primitives (session table,
(user_id, data_source_id, provider_transaction_id) dedupe, import_history) — now
exported from csvTransactionImportService (additive; CSV tests still pass).

- Routes POST /api/import/ofx/{preview,commit} mirror the CSV two-step (raw
  upload → structured commit; no column mapping since OFX is structured).
- UI: ImportOfxSection (upload → preview list → import) in the Import pane;
  amounts shown via formatCentsUSD; toasts on preview/commit/malformed.
- Gap handling: signed TRNAMT → signed cents; DTPOSTED → YYYY-MM-DD; FITID →
  stable provider id (hash fallback); non-OFX / empty files rejected clearly.

Tests: tests/ofxImportService.test.js (SGML + XML/QFX parse, entity decode,
signed cents, preview→commit, re-import dedupe, import_history). Server 129 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:11:59 -05:00
null c7b110cd68 feat(data): actionable badges, health dots, at-a-glance stats, palette links (Batch 2)
- Transactions nav shows a live "N to review" badge (unmatched count from the
  bank-ledger summary, limit:1 so it's cheap; refreshes on sync/import).
- Bank sync nav shows a green/amber/grey health dot (connected / needs-attention
  / off), mirroring the hero tone.
- Connection hero connected line now shows the transaction count at a glance
  ("SimpleFIN · 1,159 transactions · synced 2h ago · syncs automatically").
- Command palette gains Data section deep-links (Bank sync / Transactions /
  Import / Export) via ?section=.
- Count/stat fetch is non-blocking (.catch → 0), never blocks the page.

Build clean; client suite 46 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:05:25 -05:00
null 6a1b2f62b2 feat(data): two-pane shell + connection hero + deep-linking (Batch 1)
Rewrite the Data page shell into a settings-style two-pane layout (sticky goal
-nav on desktop, segmented on mobile) with:
- ConnectionHero — 5 states so a network blip is never mistaken for "not
  connected" and a server without SimpleFIN never shows a dead Connect button
  (loading / disabled / error+retry / not-connected / connected±needs-attention);
  Sync-now handles partial errors, 429, and failure with toasts.
- DataNav — <nav> landmark, aria-current, keyboard, responsive.
- ?section= deep-linking via useSearchParams (URL source of truth → localStorage
  → default; migrates the old 3-tab key), so refresh/back-button work.
- Goal-based regroup into 4 panes with plain-language titles/subtitles/icons
  passed via cardProps (every section component reused unchanged).
- Lazy panes: ImportSpreadsheet/ImportMyData code-split (own chunks) + only the
  active pane mounts; framer-motion cross-fade (reduced-motion aware);
  focus-to-heading on switch.
- Repoint BankTransactions "Open Data" → ?section=bank-sync; add /data to the
  authed axe sweep.

Build clean (heavy panes split into their own chunks); client suite 46 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:02:36 -05:00
null 212117a61a feat(data): modernize SectionCard chrome (Batch 0 — Data overhaul)
Replace the tiny grey uppercase section titles with a modern header: optional
leading icon in a soft chip, sentence-case high-contrast title, calm subtitle,
a right-aligned rotating chevron, and optional statusDot/badge slots. API is
unchanged (title/subtitle/collapsible/summary/storageKey/actions preserved) so
no section internals change — purely the shared card chrome for the Data page.

Build clean; client suite 46 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:57:03 -05:00
null a15f00c568 refactor(client): single source of truth for money formatting (IMP-CODE-01)
The client had ~15 hand-rolled currency formatters (local `fmt`/`money`/
`fmtFull`/`fmtDollars`/…) plus a canonical `fmt` in lib/utils used at ~190
sites — same rules copy-pasted, with inconsistent handling of negatives,
whole-dollar, cents vs dollars, and blank input.

Add client/lib/money.js as the one implementation:
  - formatUSD(dollars)      — "$1,234.56" (whole/dash options)
  - formatUSDWhole(dollars) — "$1,235"
  - formatCentsUSD(cents)   — from integer cents; signed "+/-" and dash options
Inputs are coerced so null/''/NaN never render as "$NaN", and -0 is
normalized so it never shows as "-$0.00".

lib/utils.fmt now delegates to formatUSD (byte-identical — the existing
utils.test.js fmt suite is the regression guard), and the 15 local
formatters delegate to money.js. No display currency formatting remains
outside money.js; the /100 conversions left behind are calculations
(form prefill), not display.

Tests: client/lib/money.test.js (13). Full client suite 46 pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 12:46:22 -05:00
null 81ddcb5fc1 feat(banking): bank transactions page with merchant/store matching, transaction matching refactor, bank sync improvements (batch 0.40.0) 2026-06-14 15:15:31 -05:00
null f3bcf6cdec fix(api): transaction matching logic improvements (batch 0.37.5) 2026-06-08 21:07:42 -05:00
null 79b51b1c9a fix(bank-sync): transaction matching, services, and worker updates 2026-06-07 20:07:27 -05:00
null 31be51e77f fix(bank-sync): admin config, matching, and worker updates 2026-06-07 19:41:17 -05:00
null 4f5a3d0cff feat: bank sync section, data sources route, subscription page updates, package updates 2026-06-07 02:03:00 -05:00
null b4779c9eda feat: auto-match review panel with undo — last 7d provider_sync payments 2026-06-06 17:34:09 -05:00
null a2ac241cd3 refactor(sync): centralize sync constants in bankSyncConfigService, wire through config/UI 2026-06-06 15:51:56 -05:00
null 809bd4498b fix: BankSyncSection enhancements, merchant rule service updates, user settings import 2026-06-04 02:57:09 -05:00
null 779ace60dd fix: overdue badge excludes due today, tooltip with names, larger column labels 2026-06-04 01:12:25 -05:00
null 690a86611a feat: SimpleFIN bank budget tracking with live balance, pending payments, bank tracking mode
- Opt-in Bank Budget Tracking mode replaces manual starting amounts with live bank balance
- Calendar money map shows Balance / Pending / Unpaid Bills / After Bills in bank mode
- Pending badge (amber) on tracker rows within configurable pending window (0-7 days)
- New GET /api/data-sources/accounts/all endpoint for account picker
- Tracker starting-amounts card shows account name and live balance hint
2026-06-03 21:09:26 -05:00
null 31bafb0e55 0.34.3 2026-05-31 15:06:10 -05:00
null c6cd81e33a chore: bump to v0.34.2, subscription badge fix on Tracker rows 2026-05-30 21:52:02 -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 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 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 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 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 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 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 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