The map route ran first-activity to last-activity only, while the sidebar
already showed the hotel-to-first-stop and last-stop-to-hotel legs with
their drive times. Feed the day's accommodation bookends into the map
route too, reusing the same getDayBookendHotels lookup and the
"optimize from accommodation" gate, so the drawn line starts and ends at
the hotel, including single-activity and transfer days.
Adding an expense required at least one participant, so a cost you only
want to record — e.g. a booking paid on-site later — could not be saved
without splitting it. Drop the participant requirement: with nobody
selected the expense saves as a recorded total, counted in the trip
total and shown as Unfinished, and kept out of settlements until
who-paid is filled in. The shared schema and server already supported
this case.
Removing the only item of a user-created category deleted the whole
category. Turn that row back into the existing ... placeholder in
place instead, so the category keeps its position and colour; adding an
item reuses the placeholder slot. Deleting the placeholder (or the
category menu) still removes an empty category.
When the backend or identity provider was unreachable, a returning user with a
persisted session landed on the dashboard with an empty trip grid and no error.
That looks identical to a logged-in user who simply has no trips, so people
assumed their data had been lost.
Three client-side layers were quietly swallowing the failure: the auth check
only cleared state on a 401, so a 5xx or a network error left the stale session
in place and kept rendering the protected route; the offline-first trip repo
turned a failed fetch into the empty cache without throwing; and the dashboard
had neither an error nor an empty state, so a blank grid meant both "outage" and
"no trips".
The auth check now tells genuine offline (keep serving the cache silently, the
PWA happy path) apart from a server outage while online (keep the session but
flag it). The dashboard shows a reassuring "couldn't reach the server, your
trips are safe" banner with a retry, and a real zero-trip account finally gets a
proper empty state so the two cases never look alike. New strings added across
all locales.
On OIDC-only instances the bootstrap admin (first SSO user) rarely carries the configured admin claim, so a forced re-login — e.g. after a JWT-secret rotation — re-derived its role purely from claims and demoted it to user, locking the instance out with no recovery. The OIDC login role sync now skips a downgrade that would strip the last remaining admin, and the admin user-update endpoint guards the same case.
The day-plan route bar lost its Open in Google Maps action in the 3.1.0 redesign. A small button with the Google logo (monochrome, theme-aware) now sits next to the Route toggle and opens the day stops, in planned order, as a Google Maps directions link in a new tab.
The "How to Update" modal always rendered Docker commands and claimed the instance runs in Docker, even on bare-metal / LXC installs like Proxmox Community Scripts. It now branches on the is_docker flag the backend already returns: non-Docker installs get a generic "re-run your install method" note plus a link to the update guide. Docker stays the default when the flag is absent, so existing installs are unaffected.
The gzipped admin0 GeoJSON is still a few MB, so behind a slow reverse proxy or Cloudflare Tunnel it could exceed the global 8s axios timeout and abort, leaving the map with no countries. It now gets a 30s per-request timeout, matching the existing /maps/pois exception.
When no trip is ongoing the spotlight falls back to a trip gradient, and several of those are light enough that the white title vanished in light mode. A subtle text-shadow on the hero title and trip-card names keeps them readable without affecting dark covers or dark mode.
A long expense title pushed the "Unfinished" pill into the price on narrow screens. On mobile the status now shows as a small marker on the category icon, freeing the title and price row; desktop keeps the labelled pill.
Follow-up to raising the day-note time cap to 250: the unit test still sent 151 chars expecting a 400, which now passes validation and fell through to an unmocked service call.
The PVC templates rendered no storageClassName and values exposed no key, so clusters without a default StorageClass (or needing a specific class) couldn't install. Add persistence.{data,uploads}.storageClassName, omitted when empty so the default class is still used.
The PDF photo pre-fetch only fired for places with a google_place_id, so OSM/Nominatim places (osm_id only) fell back to category icons even though they show photos in-app. Recover osm_id from the full places pool (the assignment projection drops it) and key the photo off google_place_id || osm_id || coords, matching the UI.
The day-note 'time' field capped at 150 server-side while the dialog and shared schema allow 250, so 151-250 char notes 400'd with a confusing 'time must be 150...' message. Raise the controller and MCP limits to 250. Also lift the toast container above modal overlays so the error toast isn't rendered behind the modal's backdrop blur.
The trips/days widgets filtered out archived trips while places, countries and flight distance did not, so archiving a trip zeroed only those two. Drop the is_archived filter so all stats stay consistent.
Firefox/Chrome enforce object-src, so object-src 'none' blocked the inline <object> PDF preview (worked only in Safari). Relax to 'self' for same-origin file previews.
The admin-0 country GeoJSON served at /api/addons/atlas/countries/geo is
~30 MB uncompressed. With no compression in the request pipeline the
transfer aborts (~8s, net::ERR_FAILED despite a 200) behind reverse
proxies / Cloudflare Tunnel, so the Atlas map never colours visited
countries. LAN is unaffected.
Add the `compression` middleware to the shared applyGlobalMiddleware
pipeline (gzip brings ~30 MB down to ~4 MB). text/event-stream is
excluded so the /mcp StreamableHTTP (SSE) transport is not buffered.
Adds BOOT-008 asserting content-encoding: gzip on the geo endpoint.
Fixes#1254
Co-authored-by: pai <pai@stabpablo.eu>
The expense Total Amount, per-person "Who paid", and settlement amount
inputs used type="number" with a bare parseFloat. On desktop the number
input normalized comma→dot for free, but mobile keyboards drop the comma
before onChange fires, so parseFloat("39,99") silently became 39.
Switch the three inputs to type="text" inputMode="decimal" and normalize
comma→dot in their onChange handlers, matching the pattern already used
by the other budget inputs (BudgetPanelInlineEditCell, BudgetPanelAddItemRow,
DashboardPage). Both comma and dot now work on every device.
Closes#1256
"description":"Shared API contracts (Zod schemas) — single source of truth for TREK server and client.",
"type":"module",
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.