Commit Graph

4701 Commits

Author SHA1 Message Date
Maurice db0fbc1ccd fix(storage): stop deleting covers, place images and journey photos another row may still show
Replacing a trip or list cover, changing or deleting a place or saved-place
image and deleting a journey photo removed the bytes at once, without asking
whether a trip copy, a journey, a saved place or another photo row still
named them (#2924). Those paths now leave the object in place and the reclaim
job removes it once no row names it. A journey photo the user deletes takes
its local photo row with it when nothing else links it, so its bytes become
reclaimable instead of being kept by a row nobody sees.

A place image copied from a trip file is still dropped at once when the
update that would name it fails: that copy was never anyone else's.

Size and warning baselines follow the shrunk files.
2026-11-01 13:59:28 +01:00
Maurice 095bed2db8 feat(storage): let every owner of an upload column tell the reclaim pass what it still names
Trips, collections, places, the contribution queue, journeys, photos, trip
files and users each register a reference source from their own domain. A
source reads its own columns and parses every spelling they hold through the
storage helpers, and the free-form columns claim every reclaimable category,
since a cover or an image can point into any of them. The contribution queue
joins the ledger as its own source, because place-contrib owns that table.
2026-11-01 13:59:19 +01:00
Maurice fb2429ebb2 feat(storage): find and reclaim upload objects no row names any more
Domains whose rows name stored objects register a reference source with
StorageReclaimRegistryService; storage never imports them. A ledger in
storage decides per category whether it is reclaimed at all and which
sources must have answered first, and a category whose resolved location
overlaps another one is left alone.

A nightly pass at 04:05 lists the root level of files, journey, covers,
avatars and places, skips objects younger than a day or without a
modification time, asks every source in pages of 500 and marks the rest.
Only with deletion switched on, and only for marks a week old, it asks every
source about the single key again and deletes through StorageService. A
category is skipped and its marks start over when a source is missing or
fails, the listing fails, or more than a fifth of its objects look
unreferenced. A pass shares the one-job slot with backfills and migrations,
never runs on a demo instance and stops when the database is reopened.

Admins switch deletion and run a pass on demand under
/api/admin/storage/reclaim; both are audited, and GET /api/admin/storage
carries the switch and the last report. Deletion is off after install and
upgrade.
2026-11-01 13:37:53 +01:00
Maurice 29298dcfe5 feat(storage): keep a mark per stored object no row names
storage_reclaim_marks records since when the reclaim pass has seen an object
unreferenced, keyed by category and key. A mark is never moved forward, so
its age is how long the object has been unreferenced without a break; it goes
once the object is named again or gone. Owned by the storage domain.
2026-11-01 13:37:44 +01:00
Maurice 630f15b5ea feat(storage): describe the reclaim report, its switch and the run request in the shared contract
The admin state now carries the reclaim switch and the last pass's report.
A report covers every served category, the legacy photos folder included,
with the objects a pass looked at, the unreferenced, eligible and deleted
counts and bytes, and the reason a category was skipped.
2026-11-01 13:37:37 +01:00
Maurice 04debce79e fix(planner): keep the lint and size ratchets where they were
The zone helpers of the day order take the merged row's own type instead
of an explicit any, and the day list's size baseline follows it down.
2026-11-01 11:41:56 +01:00
Maurice 4003769a5c fix(planner): keep the date whole and rename the title where it stands with the date first
With "date first in day headings" a long day title squeezed the date in
the day list to "Th…" (#2920); the name now gives way and the date stays
whole. The day panel and the mobile day sheet kept the rename pencil on
the heading, which then is the date, and the input replaced it (#2921);
pencil and input now go with the title line under the date.
2026-11-01 11:41:56 +01:00
Maurice 7faf771f9c fix(docker): look at the volume roots only, and say when chown is refused
The ownership check still read every inode of the volumes on each start.
It now looks at the dirs and what sits directly in them, hands a volume
over once when it is not node's, and logs a warning instead of walking a
volume that refuses chown (NFS with root_squash).
2026-11-01 11:41:56 +01:00
Maurice 51b991f851 fix(docker): the container starts on large volumes and under runAsUser 1000
The entrypoint no longer runs chown -R over data and uploads on every start;
it only hands over files that are not node's yet, and logs when it does.
Started as a non-root user, it skips chown and gosu and runs Node directly.
The chart exposes podSecurityContext and securityContext for that setup.
2026-11-01 11:41:56 +01:00
Maurice 8692b8790c fix(planner): judge a move by the order a day is drawn in across time zones
The checks behind a drag and the up/down buttons read each booking's raw
clock, so on a day whose flights were put in the order they happen every
move of a timed stop asked to change its time (desktop) or was refused
(mobile). They now read the same key the day is ordered by.
2026-11-01 11:41:56 +01:00
Maurice 1b6a156969 fix(planner): order flights across time zones by when they actually leave
A booking's time is local to its own airport, so a flight leaving
Auckland at 20:20 and landing in Los Angeles at 12:25 the same date
was drawn below the 17:00 flight on from Los Angeles. Bookings whose
dated time has a known zone now take their clock slots in real order.
2026-11-01 11:41:55 +01:00
Maurice f076cb82da docs(readme): link dataforest cloud wherever the sponsor section names it 2026-11-01 10:20:21 +01:00
Maurice 073db83421 fix(assistant): answer the calls of a stopped step and ask for the words behind wordless follow-ups
A step stopped while its calls ran (the user left the page) kept the
provider's whole record of it but answers only for the calls that ran, so
Anthropic and the Responses API refused that thread with HTTP 400 from then
on. Replaying the thread now answers every recorded call that never ran,
which also mends threads already stuck that way.

Claude Sonnet 5.5 at times ends a turn on suggest_follow_ups alone, without
writing its answer, and the turn failed as empty_answer. That step now goes
back to the model whole, its follow-ups answered that the user saw nothing
yet, and their chips come under the answer it then writes. The prompts no
longer say the call goes alone in its step.
2026-11-01 10:18:27 +01:00
Maurice cafc8dd46e fix: link dataforest cloud with /en again
The 5.1.0 popup, the sponsor panel in Settings > About and the README had
switched to https://cloud.dataforest.net/?mtm_campaign=trek. The link stays
https://cloud.dataforest.net/en?mtm_campaign=trek everywhere.
2026-10-31 12:26:36 +01:00
github-actions[bot] dc36c21c08 chore: bump version to 5.1.0 [skip ci] v5.1.0 2026-10-31 11:12:52 +00:00
Maurice 175413b3c1 ci(release): take ci-ok from an earlier commit when main only changed workflows [skip ci]
A fix to a release workflow changes nothing that the tests cover, yet the
gate wanted a full new test run on it. With ci_from the release takes ci-ok
from the commit main's code comes from, provided that commit is an ancestor
of main, everything outside .github/ is identical, and one of its ci-ok runs
is green.
2026-10-31 12:10:35 +01:00
Maurice 030918cfa9 ci(release): check the dialect with node's types
TypeScript 6 includes no @types unless a file imports from them, and the
issued dialect imports nothing from node. Type-checked on its own it did
not know Buffer, so the 5.1.0 release threw away a valid dialect as one
that does not type-check. The check config names node now.
2026-10-31 12:09:32 +01:00
Maurice 75d65ccb1b test(release-notes): build the new cases without non-null assertions
The four cases added with the 5.1.0 popup patched the fixture through
n.release! and read the support card through card!, six warnings over the
tests baseline of the eslint ratchet. They go through a withRelease()
helper and optional chaining instead.
2026-10-31 11:31:13 +01:00
Maurice def8b8a24d release notes: the 5.1.0 popup, and dataforest cloud in Settings > About
The release popup now shows 5.1.0: place search, shared place details
and faster routing as three cards side by side, each with its own
drawing. The support band is set as a card like the promise above it
(optional supportLabelKey; a release without it keeps the plain line),
and the two support buttons get the same glass look in their colours.

Settings > About gets a full-width panel for dataforest cloud, who
sponsor the servers behind place search, address search and routing.
Both logos ship in client/public/brands, so opening Settings reaches no
third party. Wherever a line names dataforest cloud it links to
https://cloud.dataforest.net/?mtm_campaign=trek, the link dataforest
gave us; the README moves to it too.

All 28 locales carry the new copy, and the old 5.0 card keys are gone.
2026-10-31 11:04:19 +01:00
Maurice f4e524f3c3 place-enrichment: the details lookup is a standalone cache fill
The service reads a community place's details before the result cache and
every other place's after it, so the lookup has two call sites of which one
runs. It only fills the details row cache and turns a failure into no
details, so it is tagged @txStandalone and the enrich baseline drops to the
four writes it holds without it.
2026-10-31 06:45:13 +00:00
Maurice 682ae19143 test(place-enrichment): a cached OSM place still reads its details for the community version
An OSM element can hold community values, so the service reads its details
before the cache to learn the version it is served under. The second request
reads them once and then answers from the row cache without another lookup.
2026-10-31 06:27:31 +00:00
Maurice 255607b750 place-contrib: format the settle filters of the outbox repository
The id and cid lists the settle writes match on come from two small helpers,
which keeps each filter on one line in Prettier's layout.
2026-10-31 06:27:31 +00:00
Maurice ce7437a46f i18n: translate the place sharing, services card and refresh pill strings into Hebrew
The Hebrew locale arrived on dev while this branch was open, so its 80 new
admin.contribute, admin.servicesCard and places.refresh keys were missing
there.
2026-10-31 03:25:56 +00:00
Maurice 36d8cc2e7b wiki: the New place details pill offers the description too 2026-10-31 03:25:56 +00:00
Maurice dc76efc418 admin: a withdrawal that went through is reported even when the state re-read fails 2026-10-31 03:25:56 +00:00
Maurice 314b087f98 planner: the refresh pill compares with the place picked anew in the search box
After another place was picked while editing, the pill still offered the
saved place's details and would have written them onto the new one.
2026-10-31 03:25:56 +00:00
Maurice 2f689ea9ca maps: stop reading a community picture at its size cap
An answer without a content-length was buffered whole before its size was
checked. The read now stops at the cap.
2026-10-31 03:25:56 +00:00
Maurice 41edbcf67a maps: validate the community values and OSM elements the TREK Places API answers
Both answers were taken as typed. A value outside the published shape, such
as hours that are no text, reached the hours parser and failed the details
request. A place outside the shape is now left out of /v1/community, and an
element outside it sends the lookup to Overpass.
2026-10-31 03:25:56 +00:00
Maurice 6945b53c10 place-enrichment: a community summary the request carried stays out of the shared cache
Like an OpenStreetMap summary, a summary credited to the community is read
straight off the request's details, so any caller could have it served to
every user of the instance for a week under the community's name.
2026-10-31 03:25:56 +00:00
Maurice 7ade99c8ce place-contrib: audit a switch-off whose withdrawal the service did not confirm
Switching sharing off commits before the withdrawal asks the service. When
the service did not confirm, the decision had taken effect but left no audit
row. It is now audited with withdrawFailed, and the admin still gets the
error.
2026-10-31 03:25:56 +00:00
Maurice 593df53993 places: a picture route records the origin of the picture only
The upload and the trip-file routes vouched for every field that changed
between their read and their answer. A website the assistant or a
collaborator changed while a large picture uploaded was then recorded as
typed by the user and queued for the TREK Places API. Those writers now name
the one field they write, and other changes keep the origin their own writer
recorded.
2026-10-31 03:25:56 +00:00
Maurice aa41c67a20 place-contrib: settle a sent value only while its queue row still holds it
A value saved while the request for its predecessor was out rewrote the same
outbox row with a new cid; the answer for the old value then deleted the row,
or charged it an attempt, and the newer value was never sent. The settle
writes now match the cid that was sent as well as the id, so such a row stays
queued for the next run. A replaced value also counts its age from the
replacement, so a long pause cannot expire a value queued days ago.
2026-10-31 03:25:56 +00:00
Maurice c10a698b9f planner: keep a place's enrichment in the tab for ten minutes, not for good
A saved place reopened for editing has no community version in its key, so
the answer the tab kept the first time stayed until the tab closed: a picture
another installation contributed since never showed. Kept answers now carry
when they were fetched and are asked again after ten minutes, the same span
the server keeps an empty answer. The key version moves to 5 so open tabs drop
what they kept in the old shape.
2026-10-31 03:25:56 +00:00
Maurice e2756dab22 places: a picture another installation contributed shows on the next edit
Two gaps kept it out. The service writes absolute picture URLs on its own
host, and the community service only took relative paths, so every picture
was dropped; it now takes the path of a URL on the configured service and
nothing from another host. And a saved place opened for editing sends no
details, so no community version, and the cached answer kept for a week; for
an index or OSM place the details are now read before the cache, so a new
version is a new answer.
2026-10-31 03:25:56 +00:00
Maurice 330644e88b places: show the community's published pictures first in Pick a picture
The service delivers the pictures review approved for a place, but TREK never
read them. A new TrekCommunityService in the maps domain asks the TREK Places
API for them (the index row for a gers place, /v1/community for an OSM one),
accepts only paths of the service's picture store, and fetches the bytes with
the installation's key, capped at 4 MB. Enrichment puts them ahead of Google
and Commons, through the same photo cache, credited as TREK Community under
CC BY 4.0. The enrichment cache now follows the community version for OSM
places too, so a newly approved picture shows on the next open.

Also lowers the client's no-non-null-assertion baseline to 380: moving Use
this text into the description card removed two.
2026-10-31 03:25:56 +00:00
Maurice 0b86a13b51 admin: fold the transmission log to its newest five rows
A busy log pushed the rest of the card down. It shows the newest five rows,
a Show more toggle opens the rest, and the page buttons appear once it is
open.
2026-10-31 03:25:56 +00:00
Maurice 8d8629516b places: offer a newer description in the refresh pill
The pill compared website, phone, e-mail and hours only, so a description
the community published never showed up on a saved place. It now reads the
index description or the OSM summary, compares it as plain words against
the editor's markup, and shows it clamped to three lines.
2026-10-31 03:25:56 +00:00
Maurice 5822910f40 places: put Use this text right under the description it copies
The button was pinned to the foot of the details column, away from the text
it adopts. It now sits inside the description card, under the source line,
with the reason it is blocked directly beneath it.
2026-10-31 03:25:56 +00:00
Maurice ce5ec7132f places: a description the community shared is credited to the TREK community
A community description laid over OSM details or an index row showed up as
OpenStreetMap under ODbL, or as the place's own website. It now has a source of
its own, community, credited as TREK Community under CC BY 4.0, like the
service publishes it.
2026-10-31 03:25:56 +00:00
Maurice 7f2a3b6039 planner: keep REFRESH_FIELDS inside its module; docker: leave shared/node_modules out of the build context
A checkout where npm install ran once carried shared/node_modules into the
image build, and its stale packages broke the client build with a vite that
lacked vite/internal.
2026-10-31 03:25:56 +00:00
Maurice 3e860dd9ca place-contrib: tag enqueue's send run as independent of its queue write 2026-10-31 03:25:56 +00:00
Maurice c28604b891 planner: the details refresh reads through a repository, and the form drops what moved out
The fresh lookup behind New place details goes through placeDetailsRepo
(online-only, like the service identity) instead of api/ directly. The form
loses the Translate type and the comment that moved with the head band's
pills, which takes it under its line limit and out of the size baseline; the
maps service suite's test-size entry follows its shorter count.
2026-10-31 03:25:56 +00:00
Maurice aba329b1b1 planner: a saved place offers newer details from its provider, field by field
Editing a saved place looks it up again. Where the lookup has a website,
phone, e-mail or opening hours that differ from the place, a New place details
pill in the form's head band shows how many, and opens what the place holds
beside what the lookup has. Empty fields are ticked, filled ones are left to
the person and say they would replace; Take over writes only the ticked
fields, with the provider as their origin, and nothing the lookup does not
know is ever emptied.

The head band's pills move to PlaceFormHeaderPills.tsx, which brings the form
from 1157 to 1002 lines.
2026-10-31 03:25:56 +00:00
Maurice 04458bee12 place-contrib: community hours in the details' own shape, and no origin rows for collection copies
Community opening hours laid over OSM details now go through the same parser
as OSM's own, so they arrive as one line per day with open-now and the periods,
and a community description lands in the details' summary. A place copied from
a collection no longer records its values as an import: without an origin row a
value is never sent anyway, and a later edit marks only the fields it changes.
2026-10-31 03:25:56 +00:00
Maurice f01ffc2c67 maps: OSM details come from TREK's own copy of OpenStreetMap first
Opening an OSM place asked the public Overpass servers for its tags, which
took five seconds and more and answered nothing while they were down. Where
the TREK services are in use, the details now come from the Places API's
details layer (/v1/osm), with the community values in the same answer, and
Overpass is asked only for an element the layer does not hold.
2026-10-31 03:25:56 +00:00
Maurice 5cfe925b78 place-contrib: no promise in the job's condition; the OSM details test counts the community call 2026-10-31 03:25:55 +00:00
Maurice a2414685ad wiki: what the API Keys card still saves 2026-10-31 03:25:55 +00:00
Maurice a1ca1aae44 admin: place search and routing get a card of their own, the keys keep theirs
The TREK API, the transit provider, the place search provider and the search
log move out of API Keys into a card of their own, which keeps them together
and saves as they change. API Keys holds only Google Maps, Unsplash and Amap,
and is not shown on a managed install, where the keys are the operator's.
Allowed File Types moves to the left column, which had room for it.
2026-10-31 03:25:55 +00:00
Maurice 56536ae803 admin: the allowance and the sharing blocks take the settings' own card head
Both blocks in the TREK API card now use SettingsCard like Single Sign-On and
two-factor: an icon tile, the title with its state as a badge, the note under
it and the switch or badges on the right, with a flush variant for a card
inside a card. A figure badge no longer cuts the last pixels of its value, and
the withdrawal toast names how many values it took back.
2026-10-31 03:25:55 +00:00
Maurice 59154b34c9 maps: OSM details carry the values installations published for the element
A place found through Photon or Overpass, a relation or a way, is no row of the
TREK index, so the community values the index lays over its own rows never
reached it. Opening its details now asks /v1/community for the element and
lays what is published over the record, with the version, where the TREK index
is in use. No answer leaves the details as they were.
2026-10-31 03:25:55 +00:00