no-restricted-imports never fires on require() calls, so the ratchet was
toothless — switched to no-restricted-syntax on the require literal. It
immediately flagged four residual files whose multi-line res.status chains
the conversion greps had missed: user.cts (four err.message-at-500 leaks —
same class as QA-B13-02), calendar.cts, export.cts, and payments.cts's
DUPLICATE_SUSPECTED body (now a hand-built literal of the standard shape,
import dropped). Lint enforces the ratchet for real now; 252/252.
Co-Authored-By: Claude Fable 5 <[email protected]>
Every routes/*.js → .cts, with handler signatures typed against the shared
http Req/Res/Next types. Routes carry @ts-nocheck for now — they're thin glue
over the (fully typed) services, so full route-level type-checking is deferred;
the handler-param typing is a head-start. server.js + test requires updated to
the explicit .cts paths.
Behavior-preserving. Verified: check:server 0, typecheck:server 0, suite 226/226,
real boot → /api/health + /api/about 200 (all routes mount).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
- 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 <[email protected]>