A fourth built-in channel next to email, webhook and ntfy. Browsers register per device, the server encrypts per RFC 8291 and signs per RFC 8292 with node:crypto and sends only to known push services through the SSRF guard. The event matrix decides per category what arrives by push; admins switch the channel on under Notifications. VAPID keys come from the environment or are generated once, only while neither stored row exists, and kept encrypted. A pair that does not decrypt or match is never overwritten and never swapped for another one: push stays off with an error in the log and every device stays registered until the key is fixed. The subject is VAPID_SUBJECT, then an https APP_URL, then the project URL. Only chat messages collapse into one notification per trip, and a replacement still alerts. A 403 removes a device only after three failures in a row; 404 and 410 remove it at once. Password change, reset and an admin setting a password drop the user's devices with the other credentials. The request log redacts subscriptions and endpoints, boot errors print *** for every secret variable, and logout forgets the device with a plain fetch so an expired session cannot redirect midway. Addresses discussion #894.
9.2 KiB
Offline Mode and PWA
TREK can be installed as a Progressive Web App (PWA) and used without an internet connection for previously synced trips.
Install as an app (PWA)
TREK must be served over HTTPS — the install prompt does not appear on plain HTTP.
iOS (Safari):
- Open TREK in Safari.
- Tap the Share button.
- Select Add to Home Screen.
Android (Chrome / Edge):
- Open TREK in the browser.
- Tap the browser menu.
- Select Install app or Add to Home Screen.
Once installed, TREK launches in standalone mode (fullscreen, no browser UI) using the TREK icon.
The installed app starts at the app root, so the Start page setting decides what you see when you tap the icon — the dashboard, or straight into your active trip on a tab of your choice. See Display-Settings.
Push notifications
Web Push shows TREK notifications on a phone or computer even while TREK is closed. It needs two things from the setup above:
- HTTPS everywhere. Browsers only allow push on a secure origin. On plain
http://(for example a LAN address) the card under Settings → Notifications says that push needs HTTPS. - The installed app on iPhone and iPad. iOS and iPadOS 16.4 or later deliver push only to TREK added to the Home Screen. Install it as described above, open it from the Home Screen icon, and switch push on there. In a Safari tab the card asks you to add TREK to the Home Screen first.
Push is switched on per device: each phone, tablet or browser you want to receive notifications on needs its own Turn on for this device. Logging out switches it off for that device. The admin has to enable the Web Push channel first, and which events arrive follows the Push column. See Notifications.
What works offline
TREK uses Workbox service-worker caching plus an IndexedDB database (Dexie) for structured trip data. The following content is available offline after the first sync:
Service-worker cache (Workbox)
| Content | Cache name | Strategy | Duration | Max entries |
|---|---|---|---|---|
| Raster map tiles (OpenStreetMap, CartoDB, custom XYZ) | map-tiles |
CacheFirst | 30 days | 12 288 |
| Mapbox GL and OpenFreeMap style documents | gl-map-styles |
NetworkFirst (5 s timeout) | 30 days | 20 |
| Mapbox GL glyphs, sprites and vector tiles | mapbox-tiles |
StaleWhileRevalidate | 30 days | 3 000 |
| OpenFreeMap glyphs, sprites and vector tiles | gl-map-offline |
CacheFirst | 90 days | 6 000 |
Cover images and avatars (/uploads/covers, /uploads/avatars) |
user-uploads |
CacheFirst | 7 days | 300 |
| App shell and every page of the app (HTML / JS / CSS) | precache | Precached | Until next deploy | — |
Note: API responses are never stored in the service-worker cache. Workbox keys its entries by URL and cannot vary them on the session cookie, so on a shared device one account's cached data could be served to the next. Offline reads come from the per-user IndexedDB cache described below instead.
Note: The precache covers every page, not just the one you happen to open first. A page you have never visited still works after you lose connectivity — at the cost of a larger initial install.
IndexedDB (Dexie) — structured trip data
On login, when the browser comes back online, and when you lift Force offline mode, TREK runs a background sync that writes full trip bundles into IndexedDB — you can also start one by hand with Re-sync now, with Download for offline use for a progress-tracked run, or by re-enabling a trip's offline toggle:
- Trips, days, places, packing items, to-dos, budget items, reservations, accommodations, trip members, tags, and categories.
- File attachments that are neither photos nor videos (PDFs, documents, etc.) are downloaded and stored as blobs in IndexedDB. Videos are deliberately skipped — a single clip can be hundreds of megabytes and would evict the trip's real documents.
- Map tiles are pre-fetched into the service-worker
map-tilescache for zoom levels 0 to 16 across each trip's bounding box, stopping at the zoom level that would push the total past 12 288 tiles (roughly 180 MB). If the browser refused persistent storage, prefetching stops at zoom 12 so the app shell cannot be evicted. - The places around each trip, up to 3000 from the TREK Places API in one request (about a megabyte for a city), so place search and suggestions still answer offline. They are downloaded whether or not Store map tiles offline is on, refreshed only when the trip's area changes, and removed with the trip. See Searching offline.
Note: A WebSocket reconnect does not run this sync. It replays your queued changes and then re-reads the trip you currently have open — days, places, packing items, to-dos, budget items, reservations and files — which refreshes that one trip's cached rows. It never re-downloads the bundles for your other trips, the file blobs or the map tiles; skipping the full sync there is deliberate, so a dropped socket on an otherwise online device doesn't run into the server's rate limiter.
Sync scope and eviction
- Only ongoing and future trips are cached (trips whose
end_dateis today or later, or has no end date). - Trips that ended more than 7 days ago are automatically evicted from IndexedDB on the next sync.
Settings → Offline
The Offline tab gives you control over what is stored on this device and lets you go offline deliberately.
Offline mode
- Force offline mode — a switch that first downloads everything you need (see Prepare for offline below) and then routes the whole app to the local cache, queueing every change you make. Flip it back off to reconnect: queued changes are replayed and the cache is refreshed. The override is remembered across app restarts, so a session forced offline before a flight stays offline when the PWA relaunches.
- Prepare for offline → Download for offline use — a one-tap, progress-tracked download of trip data, documents and map tiles for every trip you keep offline. Unlike a background sync it waits for the downloads to finish, so the completion state means you really have everything.
- Re-sync now — refreshes the cache from the server. Disabled while offline.
What to store offline
- Store map tiles offline — map tiles use the most storage by far. Turn this off to keep only trip data and documents on the device; the pre-downloaded tile cache is cleared immediately.
- Per-trip toggle — each trip has its own on/off switch. Turning a trip off evicts its cached read data from the device (your unsynced edits are kept and still sync).
Sync conflicts
If a change you made offline collides with a newer change on the server, it is surfaced as a conflict instead of silently overwriting anything. The conflict list lets you keep mine or keep theirs per item. A default rule (Ask me each time / Always keep my version / Always keep the server version) is configurable under When a conflict happens. Conflict detection covers places and packing items.
Stats & cache
The stats panel shows cached trips, pending changes, conflicts and failed changes. Clear cache removes all offline data from IndexedDB (you can re-sync any time while online). Each cached trip entry shows its date range, place/file count and last successful sync.
Limitations
- Offline editing is supported for places and packing items (with conflict detection), plus a visit's start and end time, its End the day here flag and the road trip Driving settings (queued, without conflict detection). Other entities — budget, to-dos, reservations, days — require connectivity to edit; while forced offline those edits still go to the live server when a connection is actually present.
- A change you made offline that deletes an item wins over a concurrent server edit of that same item ("delete wins"); only edit-vs-edit conflicts are surfaced for resolution.
- The conflict token has one-second resolution, so two edits to the same field within the same second can't be told apart and fall back to last-write-wins (only relevant to sub-second races; normal offline windows are unaffected).
- Creating a trip requires connectivity. Trip creation is not queued, so a new trip cannot be started while offline.
- Photo uploads require connectivity. Photo and video attachments are not pre-cached; every other file attachment is pre-cached automatically during sync.
- Real-time collaboration features require an active WebSocket connection.
- The Leaflet basemap is pre-downloaded, whether it is an OpenFreeMap vector style (style, sprite, glyphs and the vector tiles for the trip's area) or a raster template. Mapbox GL tiles are not pre-downloaded. With map-tile storage off, individually viewed tiles may still be cached opportunistically by the service worker.
