Files
WealthySmart/codebase-review/PROGRESS.md
Carlos Escalante 65dffdac06 Adopt TanStack Query: provider, timeouts, useBudget, Budget page
QueryClientProvider (30s staleTime, 1 retry) + Sonner Toaster at the
root. api.ts gains AbortSignal support and a default 30s timeout
(FE-24); query cancellation kills the stale-response races (FE-01,
FE-03). useBudget is now queries + mutations with targeted ['budget']
invalidation and success/error toasts on every mutation (ARCH-13,
UX-01); month navigation keeps the previous month visible while
fetching. Budget's transaction list is a cancellable query with
placeholder data; deferred-toggle gets feedback (UX-05); both panels
render a shared ErrorState with retry instead of failing silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:24:48 -06:00

8.2 KiB
Raw Blame History

Implementation Progress

Tracking execution of 07-improvement-plan.md. Newest entries first within each phase.


Phase 0 — Security Hardening Sprint DONE

Completed and deployed to production 2026-06-09 (deploy task 81, verified live).

Plan item Status Commit
0.1 Fail-fast configuration (SEC-01, BE-15) 15ea1ef
0.2 Login hardening: compare_digest + 5/min/IP rate limit (SEC-02, SEC-03) b412370
0.3 CORS pinned to prod domain + localhost dev (SEC-04) b412370
0.4 7-day tokens (was 30) + COOKIE_SECURE setting (SEC-05, SEC-08) 15ea1ef, b412370
0.5 Security headers via Hono middleware (SEC-07, FE-08) bebd7b5
0.6 Paste-import 1 MB cap / proxy 502 / 401 loop guard (ARCH-05, FE-23, FE-22) 3a357e4, bebd7b5, ad29cce
0.7 Housekeeping: dead AgentHomeClient removed, dev compose creds → .env, .env.example 4a758b2, 15ea1ef

Production verification (2026-06-09):

  • Health 200 after deploy; frontend+backend containers recreated, healthy
  • X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy live on prod responses
  • Login rate limit live: 6th rapid attempt → 429 with Retry-After: 58
  • CORS live: evil.example origin gets no allow header; app origin allowed
  • Fail-fast config: behaviorally tested (rejects missing/default/weak secrets in 4/4 cases); prod booted with real Gitea-injected secrets

Incidents & discoveries during rollout:

  • Deploy task 80 failed on a latent CI bug unrelated to Phase 0: unpinned corepack resolved pnpm 11, which hard-errors on unreviewed dependency build scripts (ERR_PNPM_IGNORED_BUILDS). Fixed in d874cf5 by pinning packageManager: pnpm@10.33.1 and completing the build-script review in pnpm-workspace.yaml (approve @swc/core, esbuild; ignore @scarf/scarf). A failed build never touches running containers — prod was unaffected.
  • The Gitea repo is a pull-mirror (no direct pushes). Deploys are triggered by pushing to GitHub and then running a mirror-sync via the Gitea API from the VPS (token via gitea admin user generate-access-token, POST /repos/admin/wealthysmart/mirror-sync from inside the container — port 3000 is not published on the host).
  • Dev credential change: dev no longer accepts admin/admin. The generated dev password lives in the gitignored .env (old file backed up as .env.bak-phase0). Prod credentials unchanged.
  • Two temporary phase0-sync-* Gitea tokens should be revoked in Gitea UI → Settings → Applications.

Corrections to the review docs found during implementation: none beyond those already noted in README.md.


Phase 1 — Foundations: Tests, Migrations, Time DONE

Completed 2026-06-09.

Plan item Status Commit
1.1 pytest harness, 55-test suite (no network, SQLite fixtures) c725c14
1.1 CI gate: test job (pytest + typecheck) blocks deploy (workflow)
1.2 Cycle-math characterization + month validation (BE-07) 0a4c3e9, c725c14
1.3 Alembic adoption: autogen baseline + stamp-or-upgrade startup 9a25c4b
1.4 Datetime sweep: 29 utcnow sites → app.timeutil.utcnow() 996bd43
1.5 Decimal-equivalence baseline (float behavior pinned by tests) c725c14
Pre-req: all 20 frontend type errors fixed, typecheck green 49b96ed

Key findings & decisions:

  • BE-06 is a FALSE POSITIVE. get_cycle_range(Y,M) returns the cycle starting M/18; budget month M composes get_previous_cycle[(M-1)/18, M/18), exactly as the code comment and the frontend convention state. Empirically validated against prod: May 2026 budget's credit-card figure reproduced by independent SQL over the cycle window (95 transactions exactly, refunds to the colón, 0.13% residual from a single EUR transaction the simplified SQL can't convert). Convention now pinned by tests/test_cycle_math.py and the docstring.
  • Datetime strategy: all DB columns are naive TIMESTAMP, so the sweep deliberately keeps naive-UTC semantics via a shared app/timeutil.py::utcnow() (non-deprecated API, zero behavior change). Going tz-aware would have poisoned naive/aware comparisons. TIMESTAMPTZ migration deferred to Phase 2 — now a one-line change.
  • Alembic baseline (c3da001a0eb3) autogenerated against empty Postgres, then schema-diffed against the live schema until column-identical. Two model fixes fell out: deferred_to_next_cycle now declares its server_default (live DBs have it from the legacy ALTER), usersettings.data is JSONB on Postgres (matching live) via a dialect variant. Startup stamps pre-Alembic DBs, upgrades fresh ones, under a pg advisory lock (prod uvicorn runs 2 workers → lifespan runs twice).
  • Verified locally: adoption + idempotent re-run on dev DB, fresh 13-table build on empty DB, full dev-container boot through the Alembic path, 55/55 tests, typecheck 0 errors, production vite build.

Dev environment note: backend dev tooling lives in backend/.venv (gitignored); pytest and alembic run from there. See CLAUDE.md for the migration workflow.


Phase 2 — Backend Correctness & Robustness DONE

Completed 2026-06-10.

Plan item Status Commit
2.1 Money → Decimal/NUMERIC (29 columns, BE-02) 74886fb
2.2 Upload hardening: 10 MB cap, %PDF magic, to_thread (SEC-06, BE-14) (uploads)
2.3 FK delete rules, grouped queries (10→3), N+1 fixes, tiebreakers 3cdd7d9
2.4 Error visibility: per-source rate logging, freshness, clear agent errors 82f10a5
2.5 Agent cleanup: real multipliers, year bounds, offsets, read-only policy 82f10a5
2.6 Consistency: enums, keyword status codes, SimpleCookie, import hygiene 440da3e

Key decisions:

  • Decimal strategy: Money = Annotated[Decimal, PlainSerializer(float, when_used="json")] — storage is exact NUMERIC(15,2) (rates 15,6) while JSON keeps emitting plain numbers, so the frontend contract is unchanged (pinned by test_models_serialization.py). Services coerce to float at their computation boundaries. Migration 7f567c8bafdb verified on dev: per-row values and table sums byte-identical across the type change.
  • FK rules (7884505b16b3): transactions/recurring items SET NULL on category delete — this also fixes the 500 that DELETE /categories raised for in-use categories; water readings CASCADE. Verified with a rolled-back probe on dev.
  • Agent net worth no longer guesses (hardcoded 600 CRC / 1.08 EUR removed): it converts via get_crc_multipliers and reports unconvertible accounts explicitly.
  • Read-only tool policy documented in agent/tools.py (SEC-09): ingested email text is a prompt-injection surface; any future write tool needs UI confirmation.

Review findings closed as overstated/false during implementation:

  • BE-09 (temp-file leak): parsers already use context-managed temp files.
  • BE-10 (per-file commits): the pension batch already commits atomically.
  • ARCH-08 (swallowed cancellation): CancelledError is a BaseException since Python 3.8 — except Exception never caught it.
  • ARCH-03 (filter precedence): if cycle / elif dates is already explicit.
  • BE-22 (upsert race): accepted as-is — single writer (daily n8n cron), batch- scoped commit; ON CONFLICT complexity not warranted.

Tests: 55 → 69 (new: model serialization, agent tools, upload validation).

Production verification (2026-06-10, deploy after CI test gate): boot logs show both migrations applied in order; alembic_version = 7884505b16b3; transaction.amount is numeric(15,2); FK rules live (SET NULL×2, CASCADE); data intact through the type change (238 transactions, sum unchanged); live API emits amounts as JSON numbers.


Phase 3 — Frontend Data Layer & Feedback 🔄 IN PROGRESS

Started 2026-06-10. Scope per plan: TanStack Query adoption (3.1), toast + error-state standard (3.2), auth-flow fixes (3.3), type alignment (3.4 — scope assessed at the end), small-fix batch (3.5).

Phase 3 — Frontend Data Layer & Feedback NOT STARTED

Phase 4 — UX, Trust & Features NOT STARTED