The list menu on desktop and phone gets "Sharing for Whole List": pick
Shared, Personal or Shared with people once and every item of yours in
that list moves there through the existing per-item sharing write. Items
other people added stay as they are, and the dialog says so up front.
Each attached file row now has a download icon next to its name, on the
desktop booking cards and detail dialog and on the phone's bookings and
transports cards. On the phone the file rows move out of the card body
button so open and download are two real sibling buttons.
A new app setting oidc_auto_redirect (default on) is part of the admin form
and the public app config. Off, an instance without password login no longer
sends visitors straight to the IdP: the login page shows its SSO button,
also while the cached config is read. Admin toggle on desktop and phone.
Both feed routes and the one-off export.ics take ?days=0, validated by a
shared query contract, and then skip the all-day "Day N" event per day; the
default is unchanged. The subscribe dialog gets a Day overview events switch
that adds the parameter to its links, export_trip_ics takes dayEvents and the
feed tools explain the parameter.
The tour detail gets a Maps button beside Navigation that hands the whole route
to the apps that follow one, in the tour's own mode (walking or cycling). The
stops are spread evenly along the line and capped at ten, the most a Google
Maps directions link opens. Ski, paddle and horse tours are not offered, since
a map app would route them by road; the GPX export stays the way for those.
A shared Immich or Synology album can hold hundreds of photos from other
trips. Once an album is open the picker now offers a from/to range that
filters the already loaded assets by the day the grid files them under, so
Select all only takes the photos in range. No server change.
Google Maps takes no list from outside, but My Maps imports a KML layer.
The trip export dialog and the phone export sheet get "Places for Google
My Maps" (GET places/export.kml, MCP export_trip_kml), and a list's export
menu gets KML next to GPX. The KML codec gains a pin writer; the list file
mapping moves to collections.helpers to keep the service within its size.
A read tool that answers one list a page at a time (100 by default, up to
500) as compact one-line JSON rows, filtered by status, label or "no label",
with the list's labels, the matching total and a cursor. The cursor is the
last place's position (sort_order, created_at, id), so labelling a page
while paging through unlabelled places skips none. getCollection orders by
the same keys, id last, so both tools agree on ties.
The update contract takes google_place_id, google_ftid, osm_id, website,
phone, price and currency like saving does, website with the same
normalisation and refusal. REST and update_collection_place share it, so an
agent can correct a place instead of re-saving it and losing its labels,
ratings, position and id. The assistant's change card names the new fields.
A fourth status after visited, for a place already seen that the user wants
to go back to. It joins the one-tap cycle, the filters, the pickers, the
assistant cards and the MCP status tool, and counts as visited wherever
visits are counted (isVisitedCollectionStatus), so "visited everywhere"
keeps it. The status pickers go two by two where four would not fit.
A third switch next to the page break and transport notes switches scales the
day content's type by 1.35 and darkens its greys, for readers who print the
plan. Off by default and remembered per browser like the other two; the day
content's sizes and greys now come from three CSS variables on <body>.
Mapbox Standard labels shops, restaurants and sights of its own; they look like trip
places but cannot be picked. A Hide Points of Interest switch next to the other Mapbox
options, on the desktop and the phone, turns them off on the trip map and the preview
without a rebuild. The Standard config handling moves into useStandardBasemapConfig.
A place saved with a typed address and no search pick, link or map point gets no
coordinates, so it never shows on the map, and nothing said why. The place form warns
under the address while that is so, and the inspector, the phone's place sheet and
both place lists mark such a place. No geocoding on save; the form stays unchanged
for a service stop, which explains a missing position itself.
The trip form was mounted in the planner but nothing opened it, so title, dates,
cover and currency could only be changed from My Trips. Trip settings now lists
Edit Trip at the foot of its areas for anyone with trip_edit; it swaps the dialog
for the trip form. The phone already has Edit Trip in the More sheet.
With hotel bookends on, a day whose first stop was a hire car pick-up got no morning
bookend, so the drive from the stay to the desk was missing. Only a landing means the
traveller was not at the hotel; the pick-up is the first drive of the day.
Costs always converted to the display currency from Settings, so a trip
that moves on to another country could not be read in its new local
currency. A picker in the Costs bar (beside the Expenses heading on the
phone) now reads one trip in any currency; the server already settles in
any base. The pick is per trip and kept in this browser, nothing stored.
Seeing what a trip cost without, say, food meant adding it up by hand. A
click (or tap) on a category in the breakdown now leaves it out of the
total, your share and what you paid, dimmed in place with a line naming it
and Count all to undo. View only: nothing is saved, and what is owed, open
or settled stays whole. The desktop breakdown moves into its own component.
Travellers who track what a trip costs but never split it saw an
Unfinished warning on every expense and a settle-up they had no use for.
A trip now has a costs mode (appended migration, trips.costs_mode, split
by default); totals leaves payers, shares and settling up out of Costs on
desktop and phone through the same gate as a trip of one, and saves new
expenses without a payer. PUT /api/trips/:id and update_trip take it on
budget_edit. The split chips move into their own component.
A stay shared by people who slept a different number of nights had to be
worked out by hand. The custom split now takes shares next to amounts and
percent: five nights against four split the total 5/9 to 4/9, cent-exact by
largest remainder. Only the amounts are saved, so server and MCP are
unchanged; the phone sheet gains the same unit switch, percent included.
nativeApi goes to 3 with 5.1.4, whose UI follows a widget or Live Activity
tap that starts the app. The apps refuse an older server with the hint to
update, and check a server they remember once more.
- The SSO unlink answers with a response contract (adminSsoUnlinkResponseSchema).
- It reuses linkOidcIdentity with nulls instead of a new repository method,
so UsersRepository keeps its method count and size.
- The client calls the route through apiClient, so api/client.ts does not
grow, and its confirm dialog takes no async callback.
- The pager's preview step and pagesFor keep their complexity.
A sign-in with another subject of the same provider is refused, so an
account whose provider re-issued the subject (a migrated or rebuilt IdP, a
changed sub format) was locked out: editing the email, as the wiki advised,
never touched the stored link. The edit dialog now offers "Remove SSO link"
for other accounts while SSO is set up (DELETE /api/admin/users/:id/sso,
audit admin.user_sso_unlink). The next SSO sign-in links again under the
rules of a first one, so it still needs a verified, not self-set email.
The log line names the remedy, and the wiki tells the two refusals apart.
Fixes#3065
- native-shell/amount.ts: the no-break spaces in the price pattern were
written out as characters; \s already matches them.
- widgets.ts: the Live Activity's lead time stays inside the module.
- i18n: the count strings of the new plan tiles replace the removed ones
on NOT_PLURAL, and the address placeholders of the non-Latin locales
are their own instead of English copies.
- mobile.css: the side safe-area margins of the floating bars use
margin-inline, swapped for right to left, instead of physical sides.
TREK is the application, not a thing one has a copy of: "I already have
TREK", not "a TREK". The same for the not-TREK messages in German and
Dutch and the agreement title in French, Spanish, Italian and Catalan.
The screens the app ships itself (welcome, plans, address, own server and
the states between) move from the dark card layout to a light design on an
animated aerial landscape drawn by a WebGL shader (native-shell/scenery.ts):
an island, a coastal town, farmland and mountains in one world.
- Welcome: the landscape with the TREK wordmark, three perks in one card,
"Explore cloud plans" and "I already have a TREK" as two buttons.
- Plans: one tab per plan; choosing one flies the camera to its place,
further inland with every plan. Each plan reads as a kind of trip, the
price sits in a card with a monthly/yearly switch and counts to its new
amount in the store's own format (native-shell/amount.ts), and a yearly
price shows what it makes a month. Restore purchases, the renewal terms
and the links stay as the store rules require.
- Address: the address writes itself on a glass card over the landscape;
free, the password rules and the agreement sit on white cards.
- Own server: the server address on the glass card; a failed check turns
the card red with what went wrong, proxy sign-in and client certificate
panels in the same style.
- States: server not reachable, certificate needed, already subscribed,
setting up (with its steps, then "Arrived") and the slow setup.
- iPad, an unfolded phone and a phone on its side get two columns, the
landscape beside the content; on a dual-screen device each half takes
one screen. Arabic and Hebrew mirror through logical sides only.
- The shader caps the pixel ratio at 2, drops to a lower resolution on a
slow device, stops in the background and is one still frame with
reduced motion.
- The sign-in and error page bars over a proxy's page (iOS and Android)
take the same look: a white card and a dark button.
- Plus Jakarta Sans is bundled for the text, with Montserrat standing in
for Cyrillic; the wordmark fonts and the old preview images are gone.
- New strings in all 28 languages; the keys of the old screens removed.
- The dev sample plans follow the cloud's plans (start, basis, plus, pro).
The cloud screen shows real screens of the app. The plans are a choice now: one tap marks a plan, the recommended one is marked, what every plan has is said once above them, storage says how many photos it holds, and the yearly switch shows what a year saves; one button at the foot carries the chosen plan on. The claim screen names the plan with a way to change it, shows the address as it will be once it is free, ticks off the password rules while typing, says in three words where the servers are, that it can be cancelled and that there are no ads, and puts the photo behind the form away.
One subscription per Apple ID or Google account. Choosing another plan in the app changed the running subscription on the App Store, and the redeem then failed with 'We could not set up your TREK'. The app now asks the store first and shows a screen of its own: the account already has TREK Cloud, a new one can be taken out once it has ended, with Open my TREK and the store's page to manage it. The native purchase refuses as well; a paid one that was never set up is still redeemed. On the address screens the link 'What is a TREK server?' is gone, and the small print under a purchase is set in the system text face at regular weight.
- iOS: the navigation proxy reports an error page through a callback the controller sets; it called the controller's method on itself and did not build.
- keyboard: the done key reads the field's text in the capture phase, before the field's own handler, so a list that adds an item on Enter and clears itself keeps the keyboard; the tests wire it as the app does.
- Ireland migration: the queued writes use addSql instead of awaiting inside loops; only table constants and integer ids reach the SQL.
- tests: the Dawarich GL test types its two layer specs once (strict baseline lowered), the collab test reads the id off the listed message, the reasoning test runs its four servers in parallel, and a wasm copy covers the precompressed branch without a charset.
- en wording: the deviations agreement no longer calls TREK self-hosted.
A tester could not tell which settings follow the account to every device and which stay on the phone, and looked for offline mode for a while. The section list and dropdown now stand under two headings, "Your account" and "This device". The server the app opens, the app lock and a client certificate move out of Account into a section of their own, "App", shown only in the app, next to Offline; About stands under TREK. Labels in all locales. TestFlight feedback, 5.1.3.
A multi-day hike restocks on the way: bread in the morning, food for
lunch and supper every day or two. Neither could be searched for.
- Explore pill: new `bakery` and `supermarket` chips. `supermarket`
already existed on the server (shop=supermarket|convenience) but no
pill offered it; `bakery` is new (shop=bakery).
- Along the tour: `bakery` and `supermarket` are offered to a hike,
after its existing kinds so a new hike still starts on the same three.
- TREK places index: `bakery` maps to food_and_drink>casual_eatery>bakery;
`supermarket` is narrowed to grocery and convenience stores, since the
whole food_and_beverage_store branch also brought tobacconists and
wine shops. Both paths checked against a live answer of the index.
As the more specific term, a bakery is no longer listed as a place to
eat when only `food` is asked along a tour.
- Category guess: a bakery or grocer picked from the map was preselected
as Bar/Cafe or Shopping even where the admin had made a Bakery or
Groceries category. The guess now looks for such a category first, by
name in the usual languages or by icon, and keeps the broad one when
there is none. The category icon picker offers Croissant and
ShoppingBasket, the icons the map chips use.
- Labels in every locale; MCP tool description names the new kinds.
A proxy's block page or a refused client certificate (Cloudflare's "Sorry, you have been blocked") left the app on a page without TREK's UI and no way to change the server. Any 4xx main-frame page that the client-certificate path does not handle now shows the sign-in bar with its own hint and "Change server", on iOS and Android. TestFlight feedback, 5.1.2.
The claim screen loads the agreement text and its version from /api/iap/consent, shows it with its own checkbox and buys nothing until it is ticked. The redeem sends consent { acceptedDeviations, version }; a refusal for an outdated text reloads it and asks again without a second purchase.
Behind Pangolin or authentik the app shows the proxy's sign-in page itself, and
nothing on it led back to the address screen: a failed passkey left users stuck
on every launch. A bar over that page now offers to change the server and says
that passkeys and security keys do not work there, as a web view cannot use them
for a domain the app is not tied to. It steps aside while the keyboard is up.
On iOS the page also gets the room the keyboard takes, so a button under it can
be scrolled into view. The address screen hands the bar its words in the user's
language when it connects.
The edit form fell back to the linked stay's times, the cards read only the
booking's metadata, so a hotel showed 15:00 and 11:00 when edited and no times
in the list. The reservation list now carries the stay's check-in window and
check-out, and the desktop facts and the phone card fall back to them. On the
phone they come first, so a price or a seat cannot push them off the card.
The code step drops the email field, so a password manager had no login to
match a one-time code to; the step now keeps the address in a hidden username
field. The code field names itself and sets its keyboard hints directly
(characters, no autocorrect), as autoFocus gave it focus before anything could
prepare it, and its placeholder is translated.
The fixes that keep the app's sign-in in the app live in the server's UI,
so an updated app on a 5.1.2 server still ended in the browser. The server now
reports nativeApi 2 and the app refuses anything below it, naming 5.1.3.
A server the app remembers from before is not loaded unchecked: the first
launch after the update shows the address screen filled in with it, says why
and checks it right away. A server that is new enough loads again with its
session; an older one gets the update hint.
Bookings in the Bookings tab, the day sheet, a place's sheet and the road trip
opened their editor straight away, while a transport showed its details with
a pencil to edit. Every booking now opens the same detail sheet; its edit and
delete follow the booking's own permission (reservation_edit for a stay, a
table or a ticket, day_edit for a transport). Notes keep opening for editing,
as on the desktop.
The wallet button reads "Wallet" (its accessible name still says which one),
and "On map" reads "Map" in every language.
A proxy in front of TREK (Cloudflare, nginx, Caddy, Traefik, HAProxy) can
let in only devices that show a client certificate. The apps could not, so
such a server was unusable from them.
- Address screen: the server check runs natively and notices when the
server asks for a certificate. Instead of "no server answered" it says so
and offers to add a .p12/.pfx file; a wrong password asks again, an
expired, not yet valid or keyless file is named as such.
- The certificate is shown only to the host and port it was added for.
iOS keeps it in the keychain (this device only), Android seals the key
with an Android Keystore key. The file's password is never stored.
- The web view answers the server's certificate request on both platforms;
WebSocket, service worker and API requests go through with it. The
offline copy, watch requests and the check use it too.
- When the server stops letting the app in (certificate removed, expired
or no longer trusted) while the page still comes from the service worker
or the offline copy, a native check sends the app to the address screen,
which offers to add another. A server that only asks and lets everyone
in is left alone.
- Cloudflare-style 403 and nginx-style 400 refusals without a certificate
lead to the same screen instead of staying up as an error page.
- Settings, Account: a Client certificate card (only with one stored)
shows subject, issuer, server and expiry, with Replace and Remove.
- Wiki: Native-Apps "Client certificates (mTLS)" with Cloudflare, nginx,
Caddy and Traefik setup and how to make a certificate for the app.
- The app icon on the unreachable screen is black on the light surface.
The claim screen takes the password (TREK's policy, checked before anything is
bought) and sends it with the purchase; the control plane answers with a
one-time welcome code, which the app hands to setServer. iOS and Android open
the instance's welcome page with it once after the first page, which signs the
buyer in. Without the code (a restore, an older control plane) the app opens
the instance as before.
A moment after signing in, the app asks whether to turn notifications on, once per device and only where the server offers push and the device is not signed up yet. Turning them on goes the way of the settings card, which brings up the system's question. iOS asked only when someone found that card.
The tour tab keeps desktopOnly as a plain property, so the tab list's type still has it. The wiring test follows the tab's new gate. The import sheet keeps the choice and the save with the item they were made for instead of resetting them in an effect, takes the share sheet's trip through an effect event instead of a ref read while rendering, and is split into its parts. The tours tab sets its pane while rendering, as React has it for state that follows a prop. The sheet's tests look for the texts it shows. The Android link test reads the host with java.net.URI, which a JVM unit test can run. Two locale files take Prettier's quotes.
A page or a link shared from another app now carries its address. The app asks whether to keep it among the trip's links (Collab, Links) or to read a booking from it. A link whose page the phone cannot read is no longer refused: it is handed over as the link alone, which can be kept. With Collab off a page is read as a booking, as before.