diff --git a/docs/QA_PLAN.md b/docs/QA_PLAN.md index 17ac4b4..39d6662 100644 --- a/docs/QA_PLAN.md +++ b/docs/QA_PLAN.md @@ -76,6 +76,26 @@ no matter how tempting or trivial. - **The exit is empirical:** you're done only when an entire find pass (B0→B15) turns up zero new findings — not when you *think* it's clean. Log the cycle result in the [Cycle Log](#11-qa-cycle-log) each time. - Improve THIS plan whenever a pass reveals a missed surface, a better repro, or a batch that should be reordered/split. +**Improvement lens (not just bug-hunting).** QA here is also about making the product +*better*, not only *correct*. On every batch, in addition to logging bugs, actively +look through three improvement lenses and log what you find as **IMP** items in the +[Improvement Backlog (§2.1)](#21-improvement-backlog): +- **Code health & consolidation** — duplication to DRY up, dead code to delete, + overlapping modules to merge, oversized files to split, one canonical path per + concern. *Consolidate only where it genuinely reduces surface area and is + behavior-preserving.* (Dedicated pass: **B17**.) +- **User experience** — friction in core flows, unclear states (empty/loading/error), + weak feedback/affordances, inconsistent patterns, mobile parity. (Dedicated pass: **B18**.) +- **Information architecture / menus** — features that are buried or only reachable by + URL, actions that belong in a menu (nav, overflow, context, settings groupings), and + groupings that would make the app more discoverable. *Put things where a user would + look for them.* (Dedicated pass: **B18**.) + +IMP items are **proposals**, not silent changes: log the candidate with a concrete +recommendation, agree the direction, then implement behind a test. They **don't block +sign-off** — but a strong QA cycle leaves the code cleaner and the UX clearer, not just +green. + --- ## 1. Batch plan & progress tracker @@ -105,9 +125,14 @@ before cross-cutting; regression last). Update **Status** and **Findings** every | B14 | Non-functional | a11y, performance, PWA/offline, XSS/secrets, timezone/DST | large + adversarial | ✅ | 0 / 4 | | B15 | Regression & sign-off | full smoke on **production build**, exit criteria | seeded | ✅ | 0 / 0 | | B16 | Migrations, secrets & deploy | migration idempotency/rollback/fresh==migrated, encryption-key lifecycle, `docker-entrypoint` (perms/first-run/migrate), update-check phone-home | scratch + docker | ✅ | 0 / 1 | +| B17 | **Code health & consolidation** (IMP) | duplication/DRY, dead code, overlapping modules to merge, oversized files to split, one canonical path per concern | whole repo | ⬜ | 0 / 0 | +| B18 | **UX & information architecture** (IMP) | core-flow friction, empty/loading/error states, feedback/affordances, nav/menu discoverability, surfacing actions into sensible menus | any | ⬜ | 0 / 0 | > After B15, if any batch is 🔁 or has open S1/S2, loop back. Then start a new > cycle from B0 against the next build/version. +> +> **B17/B18 are improvement (IMP) batches** — they run alongside the correctness +> batches but their findings are enhancements, not defects, and don't gate sign-off. **✅ means "run complete for this cycle's automatable scope, green, findings archived."** Cycle 1 built a durable, automated guard for every batch (`npm run ci` · `test:e2e` · @@ -173,6 +198,29 @@ Log console errors, failed network requests, and unhandled rejections as finding _All Cycle 1 write-ups have been archived to `HISTORY.md` v0.41.0 (see §3)._ +### 2.1 Improvement backlog + +**IMP-stream, separate from the bug log above.** Enhancement candidates found through +the three improvement lenses (code/consolidation, UX, IA/menus — see §0 and batches +B17/B18). These are **proposals**: log the candidate + a concrete recommendation, then +discuss before implementing. They don't gate sign-off. When one is implemented, archive +it to `HISTORY.md` (`### 🧹 QA` / `### ✨` as fits) and remove the row; deferred ideas +graduate to `roadmap.md`/`FUTURE.md`. + +**ID:** `IMP-{stream}-{nn}` where stream = `CODE` (health/consolidation), `UX`, or `IA` (menus/nav). +**Effort:** S (local, <1h) · M (a file or two) · L (cross-cutting / needs design). + +**Status:** 🔵 Noted (proposal) → 🟡 Doing → then archive to `HISTORY.md` on implement. + +| ID | Lens | Area (`file`/page) | Proposal (what & why) | Effort | Status | +|----|------|--------------------|-----------------------|--------|--------| +| IMP-CODE-01 | Code | `client/` (~10 files, ~30 sites) | **No shared client money formatter.** Server has `utils/money.js`; the client formats currency inline with `toLocaleString`/`Intl.NumberFormat` scattered across ~10 components. Add `client/utils/money.js` `formatUSD(cents)` and migrate call sites → one consistent format (esp. negatives), single source of truth for the cents model. | M | 🔵 Noted | +| 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-IA-01 | IA | Sidebar · `/data` | **Central features under an overflow menu.** Data (import/export/backups) and account pages are reachable only via the account overflow dropdown + `Ctrl+K`, not the primary nav. For how central import/export/backup is, consider a primary-nav or labeled "Manage" entry so it's easier to find. | S | 🔵 Noted | +| IMP-UX-01 | UX | Bills / Categories delete | **Retention isn't surfaced.** Soft-delete keeps records 30 days, but the only restore affordance is a transient "Undo" toast — dismiss it and a bill deleted an hour ago is unrecoverable via UI. Add a lightweight "Recently deleted / restore" view to actually leverage the retention window. | M | 🔵 Noted | +| 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 | + --- ## 3. Archiving fixed findings to HISTORY.md @@ -501,6 +549,74 @@ secrets silently. **Rate-limiter completeness** (`middleware/rateLimiter.js`) — beyond B13's list - [ ] `backupOperationLimiter` throttles admin backup/restore/cleanup; `skipRateLimitIfNoUsers` only relaxes limits on a genuinely empty instance (first-run), never afterward. +### B17 — Code health & consolidation (IMP) + +An **improvement** batch: hunt for ways to make the codebase smaller, clearer, and more +consistent — *without changing behavior*. Every candidate is logged as an `IMP-CODE-*` +row in §2.1 with a concrete proposal; nothing is refactored silently. Consolidation +lands only when it's behavior-preserving **and** covered by existing or added tests. + +- [ ] **Duplication / DRY:** find logic copy-pasted across services/routes/components and + propose a shared helper. Known hot spots: money formatting/rounding (`utils/money.js` + vs inline), the `resolveDueDate` occurrence gate (must stay one implementation), + error-response shaping (`utils/apiError.js` vs ad-hoc), React data-fetch patterns + (repeated `useQuery` + toast + error handling → shared hooks). +- [ ] **Dead / unused code:** unused exports, unreachable branches, orphaned files, + commented-out blocks, unused deps (`depcheck`), unused UI components/CSS, leftover + scaffolding. Propose deletion (verify no dynamic/`require`-by-string use first). +- [ ] **Overlapping modules:** services that do similar work and could merge or share a + core — e.g. the matching family (`matchSuggestionService`, `transactionMatchService`, + `merchantStoreMatchService`), the bank-sync family (`bankSyncService`, + `bankSyncWorker`, `bankSyncConfigService`, `simplefinService`). Map responsibilities; + propose a consolidation only where it removes real duplication, not just moves it. +- [ ] **Oversized / low-cohesion files:** split by concern where it aids navigation + (e.g. `db/database.js` is very large — migrations vs query helpers vs settings could + be separate modules). Propose the seams; don't split for its own sake. +- [ ] **One canonical path per concern:** cents handling, date/tz, CSRF, error shape, + pagination — confirm there's a single blessed way and flag divergences. +- [ ] **Consistency:** naming, file layout, async patterns, import ordering; a lint rule + that would prevent a class of the bugs found in earlier batches is itself an IMP. +- [ ] **Test/infra dedupe:** repeated test setup → shared fixtures/helpers; flag coverage + gaps a consolidation would risk. + +### B18 — UX & information architecture / menus (IMP) + +An **improvement** batch focused on the person using the app: is every feature +*discoverable*, is every core flow *smooth*, and does every action live *where a user +would look for it*? Candidates are logged as `IMP-UX-*` or `IMP-IA-*` in §2.1 with a +concrete before/after proposal. Walk the app as a real user (both `user` and `admin`, +desktop and mobile, light and dark), not just as a tester. + +**Information architecture & menus** +- [ ] **Discoverability:** is any feature buried, orphaned, or reachable only by typing a + URL? Everything should be reachable from the nav, a menu, or a clear in-page entry. +- [ ] **Navigation structure:** sidebar/nav grouping is logical; related pages sit + together; admin vs user separation is clear; active state + page titles are correct. +- [ ] **Menus where they belong:** actions that today are loose buttons or hidden should + be grouped into sensible menus — overflow (`⋯`) menus on rows/cards, context menus, + a consolidated **Settings** grouping, an account menu. Put related actions in one menu + rather than scattering them. Flag anything that would be easier to find as a menu item. +- [ ] **Command palette (`Ctrl+K`) coverage:** every page/primary action is reachable; + no dead entries. +- [ ] **Redundancy:** the same action offered in three places with different labels, or + two pages that do nearly the same thing — propose consolidating. + +**Experience quality** +- [ ] **Core-flow friction:** count the clicks for the top tasks (pay a bill, add a bill, + connect SimpleFIN, run a sync, import data). Propose shortcuts where a step is wasted. +- [ ] **States:** every list/page has a clear **empty state with a next-step CTA**, a + **loading** state (skeleton/spinner, no layout jump), and a **recoverable error** + state — no dead ends, no silent failures. +- [ ] **Feedback & safety:** state changes confirm (toast); destructive actions confirm + and, where feasible, offer undo (bills already soft-delete — surface a restore path); + long actions show progress. +- [ ] **Consistency:** primary-action placement, button hierarchy, iconography, + terminology, and confirmation patterns are consistent across pages. +- [ ] **Mobile parity:** every action available on desktop is reachable on mobile; touch + targets adequate; menus/overflow work on touch. +- [ ] **Onboarding:** first-run and empty-account guidance explains the next step; advanced + features (SimpleFIN, debt planning, backups) have a short in-context explanation. + --- ## 8. Appendices