From 9aa312082d38bad84b1643ac67861501f163422c Mon Sep 17 00:00:00 2001 From: null Date: Fri, 3 Jul 2026 13:02:47 -0500 Subject: [PATCH] docs(qa): archive IMP-CODE-03 (canonical match-state writer) Co-Authored-By: Claude Opus 4.8 --- HISTORY.md | 1 + docs/QA_PLAN.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index c88cfce..e512998 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -23,6 +23,7 @@ ### ๐Ÿงน QA Cleanup +- **[Banking] One canonical writer for transaction match state** โ€” a transaction's `match_status`, `matched_bill_id` and `ignored` columns must move together, but they were updated by copy-pasted inline `UPDATE`s across six routes/services โ€” the same drift that produced QA-B5-04 (a `matched` row with a `NULL` bill). Added `services/transactionMatchState.js` (`markMatched`/`markUnmatched`/`markIgnored`, ownership-scoped) and routed every single-transaction transition (match, unmatch, ignore, unignore, and unmatch-on-payment-delete) through it. Guarded bulk auto-match sweeps and the retention purge keep their own queries by design (their `WHERE` carries idempotency guards). Test: `tests/transactionMatchState.test.js`. (was IMP-CODE-03) - **[Client] One source of truth for money formatting** โ€” the client had ~15 hand-rolled currency formatters (local `fmt`/`money`/`fmtFull`/`fmtDollars`/โ€ฆ across pages and components) alongside a canonical `fmt` in `lib/utils` used at ~190 sites โ€” the same rules copy-pasted with inconsistent handling of negatives, whole-dollar, cents-vs-dollars, and blank input. Added `client/lib/money.js` (`formatUSD` / `formatUSDWhole` / `formatCentsUSD`, with `signed`/`dash`/`whole` options) as the single implementation; inputs are coerced so `null`/`''`/`NaN` never render as `$NaN` and `-0` never shows as `-$0.00`. `lib/utils.fmt` now delegates to it (byte-identical โ€” guarded by the existing `utils.test.js` suite) and the 15 local formatters were removed in favor of it. Tests: `client/lib/money.test.js`. (was IMP-CODE-01) - **[Build] Split the vendor bundle** โ€” the main `index` chunk was ~659 kB (over Vite's 500 kB warning). Added `build.rollupOptions.output.manualChunks` (`vite.config.mjs`) to split React, Radix, framer-motion, and TanStack into separately-cacheable vendor chunks; the index chunk dropped to ~334 kB and the warning is gone. (was QA-B0-01) - **[Deps] Removed unused markdown libraries** โ€” `react-markdown`, `rehype-sanitize`, and `remark-gfm` were declared but never imported (client markdown is rendered by a custom `MarkdownText` component). Removed all three and corrected the security notes: the actual XSS defense is React auto-escaping + the restrictive custom renderer (https-only link hrefs, no `dangerouslySetInnerHTML` anywhere), not rehype-sanitize. (was QA-B14-03) diff --git a/docs/QA_PLAN.md b/docs/QA_PLAN.md index 50193c3..33b24a5 100644 --- a/docs/QA_PLAN.md +++ b/docs/QA_PLAN.md @@ -216,7 +216,7 @@ graduate to `roadmap.md`/`FUTURE.md`. |----|------|--------------------|-----------------------|--------|--------| | IMP-CODE-01 | Code | `client/lib/money.js` (+16 files) | ~~No shared client money formatter.~~ **Shipped `a15f00c`:** added `client/lib/money.js` (`formatUSD`/`formatUSDWhole`/`formatCentsUSD`); `lib/utils.fmt` delegates to it and 15 local formatters were removed. `null`/`NaN`/`-0` all handled. Test `client/lib/money.test.js`; full client suite + build green. | M | โœ… Shipped | | IMP-CODE-02 | Code | `db/database.js` (4,174 ln) | **Oversized module.** One file mixes the migration engine, query helpers, settings, and connection lifecycle. Split into cohesive modules (behavior-preserving, test-guarded) for navigability and lower merge-conflict risk. | L | ๐Ÿ”ต Noted | -| IMP-CODE-03 | Code | `services/*match*`, `bankSync*` | **Overlapping match logic.** `transactionMatchService` / `matchSuggestionService` / `merchantStoreMatchService` each write `match_status` + bill/payment links; QA-B5-04 showed how easily these drift out of sync. Extract one canonical "set/clear match" helper so state transitions live in one place. | M | ๐Ÿ”ต Noted | +| IMP-CODE-03 | Code | `services/transactionMatchState.js` | ~~Overlapping match logic.~~ **Shipped `fa24322`:** added canonical `markMatched`/`markUnmatched`/`markIgnored`; routed the 6 single-transaction transitions through it (guarded bulk sweeps keep their own queries by design). Test `tests/transactionMatchState.test.js`. | M | โœ… Shipped | | IMP-IA-01 | IA | Sidebar ยท `/data` | ~~Central features under an overflow menu.~~ **Shipped `0b1c6a8`:** Data moved into the main app nav (desktop dropdown + mobile) alongside Bills/Categories/Spending; same default-admin gate preserved; removed the redundant account-dropdown entry. | S | โœ… Shipped | | IMP-UX-01 | UX | Bills delete | ~~Retention isn't surfaced.~~ **Shipped `aace5a4`:** Bills shows a "Recently deleted (N)" button opening a restore dialog (amount, category, days-left); `GET /api/bills/deleted` (30-day window). Test `tests/billsDeletedRoute.test.js`. _Categories/payments could get the same treatment later._ | M | โœ… Shipped | | IMP-UX-02 | UX | all list pages | **State audit.** Systematically verify every list/page has an empty-state with a CTA, a skeleton/loading state, and a recoverable error state (pair with B14 fault-injection) โ€” no dead ends, no silent failures. | M | ๐Ÿ”ต Noted |