docs: update HISTORY.md with bank tracking, merchant rules, and UI changes

This commit is contained in:
null 2026-06-04 02:48:32 -05:00
parent 5689fc95c2
commit 3745ef79b7
3 changed files with 24 additions and 0 deletions

View File

@ -30,6 +30,20 @@
- **Bank tracking pending deduction corrected — no double-counting** — The pending payments window was subtracting all recent payments regardless of source, including bank-synced ones (`payment_source = 'provider_sync'`). Since the live bank balance already reflects those outgoing transactions, subtracting them again produced a balance ~$2k lower than reality. Fixed in both `trackerService.js` and `summary.js` by adding `AND (p.payment_source IS NULL OR p.payment_source != 'provider_sync')` to the pending query. Only manually-entered payments and transaction-matched payments are now counted as pending — those are payments the user recorded in the tracker before the bank has seen them. The `pending_cleared` badge on tracker rows was given the same fix. Additionally, `b.name` was missing from the `SELECT` in `getOverdueCount`, causing the tooltip to show `null` names — corrected.
- **Bank tracking error handling hardened**`buildBankTracking()` in `trackerService.js` and `buildBankTrackingSummary()` in `summary.js` had no try/catch. A DB lock, schema inconsistency, or bad account state would throw an unhandled exception and crash the entire tracker or summary API response for the user. Both functions are now wrapped: `buildBankTracking` returns `{ enabled: false }` on error (tracker falls back to manual starting amounts gracefully), and `buildBankTrackingSummary` returns `null` (summary page omits bank data but still loads). Console error logged in both cases for debugging.
- **Merchant rule word-boundary matching — fixes false positives** — The merchant matching logic used simple substring `.includes()` which caused "suno" (Suno AI music) to match "sunoco" (gas station) because "sunoco" contains "suno" as a substring. All four matching sites replaced with a word-boundary regex check: `(^|\s)rule(\s|$)` must match within the transaction string. Now "suno" does not match "sunoco" but still correctly matches "suno inc" and similar. DB migration `v0.83` adds `auto_attribute_late` column to `bill_merchant_rules`.
- **Merchant rule: "Auto-fix month crossing" toggle** — Some bills consistently post to the bank 15 days after month end (e.g. AT&T due May 29, posts June 1). Previously this required a manual prompt every cycle. Each merchant rule now has an "Auto-fix" toggle in the Bill Modal Bank Matching Rules section. When on, payments that cross a month boundary are automatically moved to the last day of the prior month on sync — no popup, no manual intervention. The flag is stored as `auto_attribute_late` in `bill_merchant_rules` (migration v0.83) and persists. A `PATCH /api/bills/:id/merchant-rules/:ruleId/auto-attribute` endpoint controls it.
- **Historical payment import dialog** — When a merchant rule is added in the Bill Modal, a dialog now opens automatically asking how to handle past transactions: "Import all N payments" (bank as truth), "Choose which ones" (checkbox list showing each transaction's date, amount, and current match status), or "Skip — future only". The "choose" view shows already-handled transactions dimmed at the bottom for context. Backend: `GET /api/bills/:id/merchant-rules/candidates` returns all matching transactions regardless of current match status; `POST /api/bills/:id/merchant-rules/import-historical` imports a selected list.
- **Bank tracking status bar and card on TrackerPage** — When SimpleFIN bank tracking is enabled, the TrackerPage now shows: (B) a slim colored status bar between the header and the filter panel — pulsing live indicator, account name, balance, pending amount, and projected figure color-coded green/red; (C) the Starting summary card is replaced by a bank-styled card with an emerald top bar, account name label, `Landmark` icon, pulsing "Live" badge, effective balance as the main number, and projected-after-bills in the hint line. Number sizes unchanged from other summary cards.
- **`refetch is not defined` in BillModal fixed** — Two `refetch?.()` calls were added to `BillModal` during an earlier session but `refetch` is not a prop or variable in that component's scope. JavaScript throws `ReferenceError: refetch is not defined` before optional chaining can evaluate. Both calls removed — `loadLinkedTransactions?.()` is sufficient since the parent's `onSave` callback handles any full tracker refresh.
- **BillMerchantRules suggestion list now uses inline rendering** — The suggestions dropdown previously used `position: absolute` which was clipped by BillModal's `overflow-y-auto` container. Clicks on suggestions appeared to land on the scroll container behind them. Replaced with inline block rendering (no absolute/fixed positioning) so suggestions are part of the normal document flow and always clickable. `onMouseDown + e.preventDefault()` keeps the input focused during selection.
- **Bank tracking: projected month-end balance added** — The CalendarPage Monthly Money Map (bank mode) now shows a dedicated "Projected Month-End Balance" row below the four metrics. It displays the full equation inline — `$5,461 bank $1,737 pending $3,696 remaining bills` — so the source of the number is always visible. The row uses a green/red border depending on whether the projection is positive or negative. The TrackerPage Starting card hint also updated from `account_name · live balance` to `account_name · projected $X after bills` so the projection is visible without navigating to Calendar.
- **Bank tracking settings and account picker fixed** — The `loadBankTracking` function in `BankSyncSection` called `api.getSettings()` but the API method is `api.settings()`. The wrong name threw `TypeError: api.getSettings is not a function`, silently caught by the outer `catch {}`, so neither the toggle state nor the account list ever loaded. Renamed to `api.settings()`. All 19 financial accounts now appear in the picker and the enabled/account/pending-days settings persist correctly across page loads.

View File

@ -10,6 +10,7 @@ const DEFAULT_PENDING_DAYS = 3;
// Build bank tracking summary when the user has enabled SimpleFIN bank tracking.
// Returns null when disabled, the account isn't found, or bank sync isn't set up.
function buildBankTrackingSummary(db, userId, year, month) {
try {
const settings = getUserSettings(userId);
if (settings.bank_tracking_enabled !== 'true') return null;
@ -88,6 +89,10 @@ function buildBankTrackingSummary(db, userId, year, month) {
unpaid_this_month: unpaidDollars,
remaining: money(effectiveDollars - unpaidDollars),
};
} catch (err) {
console.error('[buildBankTrackingSummary] Error:', err.message);
return null;
}
}
function parseYearMonth(source) {

View File

@ -9,6 +9,7 @@ const { computeAmountSuggestion } = require('./amountSuggestionService');
const DEFAULT_PENDING_DAYS = 3;
function buildBankTracking(db, userId, year, month) {
try {
const settings = getUserSettings(userId);
if (settings.bank_tracking_enabled !== 'true') return { enabled: false };
@ -72,6 +73,10 @@ function buildBankTracking(db, userId, year, month) {
remaining: roundMoney(effective - unpaid),
last_updated: account.updated_at,
};
} catch (err) {
console.error('[buildBankTracking] Error computing bank tracking data:', err.message);
return { enabled: false };
}
}
function validateTrackerMonth(query = {}, now = new Date()) {