Both failed the deletion test in the telling direction:
- @trails-cool/ui: Button/Input/Card had zero consumers — both apps
roll their own elements inline. The only live part was a 6-line
styles.css (the Tailwind entry + one keyframe), which now lives in
each app as app/styles.css.
- @trails-cool/map: MapView and RouteLayer had zero consumers; the
package was otherwise a re-export of two map-core constants, and the
two import sites now use @trails-cool/map-core directly. The
"map components go in @trails-cool/map" convention had drifted long
ago — the real map components live in apps/planner/app/components.
CLAUDE.md's repository structure and conventions updated to match
reality (including pointing shared-type guidance at the post-#515
sources: db row types, api contracts, Waypoint in types). Dockerfiles
no longer COPY the deleted package manifests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
maximum-scale=1 + user-scalable=no prevents the browser UI from
zooming when pinching. Map zoom (Leaflet) still works since it
handles touch events independently.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- viewport-fit=cover enables safe area insets in Safari
- Header: pt-[max(0.5rem,env(safe-area-inset-top))] clears the notch
- Elevation chart: pb-[max(0.5rem,env(safe-area-inset-bottom))] clears
the home indicator bar
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split initI18n() into separate server/client initialization paths
inspired by remix-i18next's architecture:
- initI18nServer(lng): no LanguageDetector, per-request language from
Accept-Language header
- initI18nClient(): LanguageDetector reads <html lang> first to match
server, then localStorage and navigator
- detectLanguage(request): parses Accept-Language for best match
Fixes rehydration errors caused by v26 removing initImmediate option
(replaced with initAsync) and LanguageDetector running on the server
where browser APIs don't exist.
Also makes <html lang> dynamic instead of hardcoded "en".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move initI18n() from entry.client.tsx to root.tsx in both Planner and
Journal so i18n is initialized before any component renders. Downgrade
react-i18next to 16.6.1 and i18next to 25.10.4 to avoid hydration
mismatch issues introduced in newer versions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
With custom entry.client.tsx, initI18n() in root.tsx runs too late —
the client hydrates before i18n is initialized, showing raw translation
keys. Move initI18n() to entry.client.tsx where it runs before
startTransition/hydrateRoot.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Client ErrorBoundary: skip captureException for HTTP errors < 500.
Server beforeSend: drop events where __serialized__.status is 404.
Resolves JOURNAL-2 and JOURNAL-8 (scanner bot noise).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Initialize i18n via initI18n() in both root.tsx files and replace all
hardcoded user-facing strings with useTranslation() calls. Adds missing
translation keys for planner (profiles, connection states, save flow)
and journal (auth pages, route management, passkey prompts).
Both English and German translations are complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Planner (client + custom server) and Journal (client + entry.server):
- Client: @sentry/react with browser tracing + replay on error
- Server: @sentry/node for unhandled exceptions
- ErrorBoundary captures React errors via Sentry.captureException
- Disabled in dev, 10% trace sample rate in production
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both apps now have proper ErrorBoundary exports in root.tsx:
- 404: "Page not found"
- 503: "Service temporarily unavailable"
- Other: shows error message
Simplified withDb re-throw check: anything with a "status" property
is treated as a React Router response (covers Response and
ErrorResponseImpl). DB errors throw a plain Response(503) that
the error boundary renders nicely.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>