Official codemod (run in a clean worktree; docker-owned data/ blocks it
in-tree): tailwind.config.js inlined into client/index.css as CSS-first
@theme/@utility (config file deleted — v4 auto-detects content, which
also retires the .tsx-content-glob failure class from the TS migration),
33 template files' class renames applied, tailwindcss-animate loads via
the v4 @plugin bridge. Build runs through @tailwindcss/vite; postcss
config is now plugin-free. tailwind-merge -> 3 (v4 class model).
Visual-regression gate: only diffs were a ~2px global preflight shift +
the version string (baseline predated 0.41.1); re-baselined both login
screenshots in this commit after review. webauthn.probe confined to the
probe project (it enables WebAuthn for the seeded user, racing the
parallel UI projects' password logins).
e2e 27 passed, probe 18/18, PROD SMOKE PASS, typecheck/lint/tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Build drops 6.5s -> 0.65s. Three breakages found by the prod-smoke gate,
all fixed:
- rolldown removed object-form manualChunks -> function form in
vite.config.mjs (same vendor split, all @radix/@tanstack grouped)
- the 4a 'send' bump rejects bare absolute paths: SPA fallback sendFile
and both download routes (admin backup, user-db export) now use the
root-option form
- rolldown minifies inline HTML scripts, breaking any CSP hash approach:
the pre-paint theme script moved to client/public/theme-init.js so
script-src 'self' holds with no inline hash to maintain
@testing-library/dom added (peer no longer auto-installed). Server 252,
client 52, probe 18/18, PROD SMOKE: PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BrandGlyph drew hardcoded monochrome shapes from an inline switch and
ignored the actual /brand/glyphs/*.svg files. Render the real files via a
robust <img> (fail-soft onError, intrinsic width/height so no layout
shift, alt for a11y parity) so every existing placement — PageHeader
(Tracker/About/Release), Command Palette, Release Notes, Onboarding,
Login — shows the full-color brand tiles. Deletes the ~85-line dead
BrandGlyphShape switch and the now-unused useId import.
Senior-review while-here:
- Guard test (client/lib/brand.test.ts): asserts every BrandGlyphName
asset — and every /brand asset in brand.ts — resolves to a real,
non-empty file on disk. Catches the "image added but path wrong /
renamed" regression TS can't see.
- Widen vitest include to {js,jsx,ts,tsx}: TypeScript client tests were
silently never run (client/hooks/useAutoSave.test.ts). Now 6 files / 50
tests run (was 4 / 42).
- Remove dead brand.ts entries: legacyLogo (pointed at the OLD pre-brand
/img/logo.png) and the unused ADMIN_GLYPH const.
- PageHeader glyph class inline-grid -> inline-block for the <img>.
Verified: typecheck + lint clean; test:client 50/50; build (glyphs land
in dist/brand/glyphs, served 200 as image/svg+xml); e2e probe 17/17;
login visual baseline unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
index.html: favicon and apple-touch-icon now point at the SVG mark
(plus the legacy PNG fallback for browsers that don't honour SVG
favicons). vite.config.mjs: VitePWA manifest icons reference the
SVG mark + social-preview, theme_color and background_color
inherit from the new brand tokens.
No behaviour change for end users — the PNG derivatives stay in
the same directory and are still used by the PWA splash / app-icon
paths that need raster.
This is commit 3 of the v0.42.0 follow-up batch. Depends on
1c04dfd (Brand components).
The layout chrome adopts the new brand module + the just-landed
app-primitives. CSS variables, the favicon, the page title, and the
vite PWA manifest all switch to the new brand assets:
- BrandBlock / NavPill / Sidebar / Layout use BrandMark / BrandWordmark
/ BRAND.name from @/lib/brand.
- ThemeContext exposes the system / dark / light options for the new
'theme = System' setting (commit 1 of 9 in the brand refresh set;
the actual settings UI lands in the per-page commit).
- client/index.css: 153 lines of churn — the design-token refresh
(accent palette, neutrals, surface tokens) consumed by every
downstream commit.
- index.html: title, favicon, apple-touch-icon, theme-color, manifest
href all point at client/public/brand/*.
- vite.config.mjs: VitePWA manifest icons + theme/background colors
follow the new brand.
This is commit 3 of 9 in the v0.42.0 brand refresh. Depends on
4898987 (app-primitives).
Added babel-plugin-react-compiler to the Vite React plugin. The compiler
auto-memoizes components/hooks at build time, so manual useMemo/useCallback
become largely unnecessary going forward (existing ones are left in place —
harmless, and the compiler adds the rest). Safe here because the codebase is
rules-of-hooks clean (enforced by eslint-plugin-react-hooks).
Validated: production build succeeds and the e2e probe passes 17/17 with the
compiler on — every authed page renders axe-clean and Tracker/Summary/Analytics
reconciliation holds. (Build time ~2.2s -> ~6.2s from the compiler pass; the
runtime win is automatic memoization.) The compiler ESLint rule needs
eslint-plugin-react-hooks v6 — a future upgrade.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace all Save buttons on the Settings page with debounced auto-save:
- useAutoSave hook: debounce with latest-payload-wins, flush() for blur,
pending-edit flush on unmount, status machine (idle/saving/saved/error)
with saved fading back to idle. Covered by 6 Vitest tests (fake timers).
- SaveStatus pill (framer-motion) in the page header and notification card
headers — Saving…/Saved/Save failed.
- Timing per control: toggles/selects/channel ~150-400ms; typed inputs
(email, URLs, grace period, drift pct) 900ms + flush on blur.
- Push token never auto-saves mid-type: saves on blur only, so a partial
token can never overwrite a working one.
- Notification cards no longer refetch parent settings on save (would
clobber in-flight edits under auto-save).
- Decision: no undo toast — settings are non-destructive and instantly
re-editable; undo would add noise without safety.
- vitest include now picks up .jsx tests; jsdom + @testing-library/react
added as devDependencies.