Replace the OS system font stack with IBM Plex: the variable-weight
sans (100-700, one file per subset) for UI and headings, and Plex Mono
400 for the public keys, packet hashes, and hex that font-mono renders
across the app. Latin + latin-ext subsets only (shipped locales are
en/nl); no italics; mono is never rendered bold here.
Fonts are self-hosted from @fontsource packages via the existing
build.js vendor pipeline (no CDN), copied to static/vendor/fonts/ with
a hard build failure on wrong filenames. Wiring:
- input.css: @theme --font-sans/--font-mono + @font-face rules with
unicode-ranges taken verbatim from the package CSS; Tailwind v4
derives the document default from --font-sans, re-fonting daisyUI
components with no other changes.
- spa.html: preload the latin sans variable woff2 (crossorigin, URL
identical to the @font-face src) to minimize FOUT.
- charts.js: Chart.defaults.font.family to match (Chart.js otherwise
uses Helvetica/Arial).
- error.html: name-prepend only; the page stays dependency-free.
- middleware.py: long-term immutable cache for /static/vendor/fonts/
(stable names referenced from CSS, so ?v= versioning can't apply),
with a matching test.
- app.css: slight hero-title letter-spacing tightening for Plex at
display sizes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bundle SPA JavaScript with esbuild for production builds, generating
content-hashed filenames for immutable caching. Vendor assets (Leaflet,
Chart.js, QRCode.js) get SHA256-based query params. Locale JSON files
get a combined hash version. Falls back to unbuiltsources when dist/
is absent.
Implement cache-control middleware to optimize browser caching and reduce
bandwidth usage. Static files are cached for 1 year when accessed with
version parameters, while dynamic content is never cached.
Changes:
- Add CacheControlMiddleware with path-based caching logic
- Register middleware in web app after ProxyHeadersMiddleware
- Add version query parameters to CSS, JS, and app.js references
- Create comprehensive test suite (20 tests) for all cache behaviors
Cache strategy:
- Static files with ?v=X.Y.Z: 1 year (immutable)
- Static files without version: 1 hour (fallback)
- SPA shell HTML: no-cache (dynamic config)
- Health endpoints: no-cache, no-store (always fresh)
- Map data: 5 minutes (location updates)
- Custom pages: 1 hour (stable markdown)
- API proxy: pass-through (backend controls)
All 458 tests passing, 95% middleware coverage.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>