A GPX track imported in 4.x is a plain place: a line, no tours row. It never
showed under Tours, and importing the same file there was refused as a
duplicate by its name, so there was no way to turn it into a tour (#2810).
The tour import now takes over a track of the trip that has the same name
and is no tour yet: the place keeps its name and line and gets the tours
row, with the recorded times the file adds. The preview says so instead of
"Already in the trip". New and taken-over tracks commit in one transaction.
The overview of a trip's tours decides for itself when it shows, which keeps the planner page hook inside its complexity and length limits, and adds nothing to the camera's key while there is no tour to frame. The elevation helper names its empty case for the strict type check, the self-host wording exemption for the retired Dawarich card goes, the day plan test reads the wrapping pills, and the new tests drop their non-null assertions and loops.
Ascent and descent were the raw sum of every height difference, so a flat walk across Venice (highest point 16 m) read 121 m of climbing. Heights now count once they move 5 m from the last one that counted; the server's stored figures and the planner's live analysis share the one function.
P6: insert_tour_stop and remove_tour_stop take a place into a saved hike or
city walk as one stop and out again, each the other's undo, with change
cards in the chat. The planner's insertion rule (poiInsertion) moved to
shared so the planner and the server place a stop the same way. "+ Tour" on
a found place holds it as a stop of the saved tour open in the planner.
P7: GPX, KML and KMZ files attached in the chat are read into their tracks
and each is held as a change that takes it in as a hike through
import_tour_gpx, undoable per track; the GPX text stays on the held call.
The assistant can now search a round hike of about a wished length from one
point and the router's other ways for one leg of a hike, with the planner's
own search, and propose each one as a hike card to compare and take. It can
also search the user's wanderer trails, preview one as a card, import it and
check a wanderer tour against its source.
The round search, its loop geometry, the test whether two lines are one way,
the other ways among a router's offers and the pins that hold a chosen way
move to @trek/shared; the planner and the road trip use them from there.
City walk changes take edit, reverse and close_loop; edits alone keep the
saved way and never ask the router. update_tour turns a hike round or closes
its loop with reshape. New MCP tools mirror the Tours tab's REST writes and
reads: update_tour_details, set_tour_route_color, copy_tour,
classify_ski_track, set_paddle_plan, decide_paddle_obstacles,
restore_recorded_track, get_tour_trail_details and find_horse_routes, with
change cards, undo where the answer keeps the values before, and broadcast
parity cases.
The assistant can now plan and save every type the Tours tab plans. A bike
tour or a run is proposed and created through the hike's own plan and save
(propose_tour, create_tour), routed on the server with the costing of its
profile, now kept once in shared and read by the planner as well. A paddle
or ski tour planned with plan_paddle_route or plan_ski_route is saved with
create_paddle_tour or create_ski_tour, and "Plan this" takes those plans,
bike tours and runs too. Every create has its card and its way back.
- propose_hike, create_hike and update_tour take stage_end on the stops a day
ends at, checked by the tours' own stage rules (never at the start or the
end, at most 60 stages) on REST and MCP alike.
- A proposal over several days names its stage ends and sets no single day's
schedule; its card counts the stages and marks the stops they end at.
- New points for a hike in stages keep the keys of the stops they stand on,
so a stage keeps its day; they are refused only where they would drop every
stage end.
- The tours group and the prompt name the stages, how to put each on its day,
and what to offer once a tour is planned: places along it, its packing, the
GPX file.
The hiking costing moves to shared, so the planner and the server ask the
router the same way. The road trip router learns to plan a hike on foot
with that costing (Valhalla only: OSRM knows no trail difficulty), to read
heights along a line in chunks and to read the OSM ways a line follows,
all through its one paced queue. A hike router builds on it: the way, its
heights, distance, climb and DIN walking time, and the SAC grades of its
stretches from the trail grade service, each part best effort.
New MCP tools in HikePlanMcp, in the assistant's tours group:
- propose_hike plans a hike without saving it.
- create_hike saves a confirmed hike through the planner's own creation;
a router that does not answer leaves it pending for the planner, a way
that cannot be planned is refused and nothing is saved.
- update_tour changes a saved hike against its revision, keeping linked
stations and refusing what would silently drop drawn legs or stages.
- import_tour_gpx takes a GPX file's text in as tours, like the import.
Same permission checks as REST, broadcasts from the services.
In the assistant a new hike or city walk is an "Add tour" card with its
route and difficulty, undone through delete_place while the tour is
untouched, and a hike being planned shows as a live step.
Every help screen checked against the v5 redesign. Tours is documented for
the first time, as a screen of its own with twelve screens under it, and
notifications get help of their own. All pictures are taken again on a
realistic demo trip, with short loops where a still cannot show the motion.
The English is plain and every language is written naturally rather than
word for word.
The switcher shows two levels at most, a screen's overview lists its
sub-screens as cards above its guides, each wiki page is linked once, and
the help sidebar is wider.
Fixes found along the way: Save to Collection keeps a tour's route, a track
dropped on the places column opens the Tours import, tour Share on desktop,
the unsaved tour draft lives on the account, a route click no longer adds
an end point, Trip places leaves the trip's tours out, Escape closes a
stage's day menu, confirms before destructive deletes, DWD warnings sharing
one id kept apart, a booking's date moves with it, and smaller fixes across
notifications, bookings, the day plan, stays, Atlas, Collections, Vacay and
the admin screens.
A saved ski tour now opens with the line, heights, time, build and
planned legs it was saved with, read from the place this device keeps,
and nothing is asked of the piste router until a point, an option or the
discipline changes. Opened offline, while TREK Places is down or with
piste routing switched off, it no longer turns every leg straight, and a
rename saves the planned tour as it was. A kept line whose length is not
the tour's is another save's, and the tour is planned afresh.
- the save names the legs the router planned (ski_planned_legs, checked
against the tour's own legs); get_tour_plan reports each leg routed or
drawn from them instead of from the build alone, a tour that names none
counting as planned only with the router's time
- copies keep ski_options in every path: in the trip, taken over, kept
in a collection and made from one (collection_tours gets the column in
the same unshipped migration)
- the route summary shows the data build, the km of runs, the height
skied down on them and the lift rides, and the credit the server sends
in place of a fixed one; a tour opened as saved says so
- answers refused while piste routing is off, or planned on an older kept
copy, are not remembered, so they are asked again later
- terrain heights between known ones are filled in one walk along the line
- i18n: five summary keys in all 27 locales
A ski tour with a discipline now sends its legs to the piste router and
takes back runs, lifts and trails: each stretch is coloured by its grade
in the area's scheme, links and lift rides down are dotted, and a leg the
router cannot plan stays straight and unrouted with its reason and the one
change that would plan it. Snowshoe and winter hike legs off the piste
data follow summer paths instead, said so. The router's time and heights
are used once every leg is planned, and the options, the build and the
time are saved with the tour.
- skiRouteRepo and api: one request per tour, batched, remembered unless
the answer may change, offline legs failed as offline
- planner: router options per discipline, leg steps and failure rows with
fixes, a piste route summary, draft and reopen keep the options
- admin: switch for the piste router under Tours
- i18n: new ski keys in all 27 locales, ski info and time texts rewritten
A ski tour now saves the options its legs were planned with and the piste
data build they ran on, as one JSON column (a new migration, since the
ski migrations have shipped on this branch); the server keeps only the
options its discipline reads. Both stay off every other type. The refusal
of a ski time is lifted: the piste router works one out, and the planner
sends it only when every leg followed the piste data. get_tour_plan names
the legs of a tour the router planned as routed, and list_tours says what
the new fields hold.
A new Nest domain plans the legs of a ski and winter tour on the runs,
lifts, cross-country trails, ski touring and winter paths the Places host
builds from OpenStreetMap, one SGR1 graph per ski area. TREK fetches the
index once, downloads an area by its id when a planner first plans in it,
checks it against the index's SHA-256 and keeps it in data/ski; no
clicked point ever leaves the server. A leg whose area is slower than two
seconds answers loading, and an older copy stands in while the host is
down.
The reader decodes the writer's golden file byte for byte, including the
two edge flags it added (area_has_run, type_unknown). The search is A* in
a worker thread over a profile per discipline (alpine, snowboard,
cross-country by technique, touring, snowshoe, winter hike) with the
times and penalties of the cost model, up to five snap candidates per
point, lift stations as entry points, legs that go on from each other,
pieces of a split network stitched by their boundary nodes, other ways by
the penalty method, and a failed leg explained by relaxing one rule at a
time (difficulty, lift class, technique, riding down, uphill) without ever
handing out the relaxed line.
POST /api/trips/:tripId/ski/route, GET .../ski/area-near and
GET .../ski/network/:areaId sit behind Tours and the trip, with
plan_ski_route as their MCP twin. A daily job looks for a new build and
sweeps areas unused for 90 days. The admin switch ski_routing_enabled is
on wherever TREK Places is.
A hike imported from GPX, KML/KMZ or wanderer had no time at all, so
several hikes on one day could not be planned against each other. It now
gets the walking time the planner times a hike by (DIN 33466), worked out
from its own distance, ascent and descent; a run gets its distance at the
pace entered. Without heights in the track the time is unknown rather
than the time on the flat, and types timed by a router, by a speed of
their own or by nothing get no estimate.
The estimate is derived on every read and never stored, so tours imported
before get it too and no stored or entered time is touched. The rule moved
to @trek/shared, where the planner, the client and the server read it.
The tour list, the day rows on desktop and phone and the tour detail say
it as an estimate, apart from a planned total; list_tours and
get_tour_plan carry it as time_estimate and name it as derived.
Ski becomes "Ski & winter", a type the planner plans with six disciplines
(alpine, snowboard, cross-country, ski touring, snowshoeing, winter hiking),
nothing preselected; saving needs a discipline, and a technique for
cross-country. Every leg is drawn straight between the points through
planner/skiRouting.ts, the one place the piste router will plug in, with its
heights from the elevation source and no ski time worked out.
The hike's winter label goes entirely: its migration, column, field, marks,
GPX rule, MCP field and strings. A hike is summer only; a ski tour with the
snowshoe discipline exports as snowshoeing. The unreleased ski migration takes
the six disciplines and the collection migration loses the winter column.
The pistes are offered for a ski tour, shown until switched off, and with no
tour open, never for a hike. Export, copy, collections, stages (untimed),
actual tracks, the atlas, list and day marks (one glyph per discipline), 3D,
planning over a ski import and list_tours/get_tour_plan know the planned ski
tour.
The collection copy keeps the winter, run, ski, bike and stage columns,
but its list item only carried the older fields, so a kept ski track lost
its discipline mark, a snowshoe hike its winter mark, a run its pace and
a multi-day tour its stage count. The item now carries them, and a kept
tour's card shows the pace and the stages beside its measures.
Types, test expectations and helpers the seven tracks each changed on their
own, brought in line with the integrated code. tours.service.ts and the tours
repository grew past the size limit with every track and hand their row and
write helpers to modules of their own.
A tour can now point at the packing list of its trip, as a whole or at one
of its categories (say "Hiking gear" for a hike), and shows it in its detail.
The new Packing list section reads the list live as the user may see it: the
backpack tile with the item count on its corner and the category's own
colour, how many are packed with a thin progress bar, the first items ticked
off or not with their quantity, how many more there are, and a button that
opens the trip's Lists tab. Who may change the tour links one, changes it or
lets go through a dialog that lists the whole list and every category with
its colour and item count, and writes only on its confirm.
It is a reference, never a copy: the items stay in Packing, are ticked off
and edited there, and each traveller sees in the tour only the items Packing
shows them, so an item kept to oneself never shows through a tour. A
category that is renamed, cleared or only holds items of others reads as
missing, an empty one as empty, a link that could not be read says so with a
retry, and while Lists are switched off the link stays, dimmed, and can
still be let go. Removing the link, or the tour, leaves the list and every
item as they are. Nothing suggests or changes an item by itself.
On the server the link is a row of its own in the tours domain
(tour_packing_links, migration 046110), one per tour and gone with it.
GET, PUT and DELETE /api/trips/:tripId/tours/:placeId/packing-link read it
with the trip and change it with place_edit; linking needs the Lists addon
and, for a category, an item of it the user can see. The writes answer the
tour with its link and tell the trip through tours:changed, so the offline
client queues them as writes of the tour and replays them like one. A copied
trip keeps its tours' links, a tour saved as new or taken over does not.
The MCP tools get_tour_packing, link_tour_packing and unlink_tour_packing run
over the same service and checks; the read also hands the tour's facts as
context for suggesting what to pack, which only becomes an item through the
packing tools. The empty category placeholder now lives in @trek/shared so
both sides leave it out alike. All 27 locales carry the new strings, and
the wiki describes the link and the tools.
A saved tour can now be kept in a collection, apart from any trip, and
later made into a tour of another trip. The bookmark button in a tour's
footer and in the planner's head (waiting for the save while there are
unsaved changes) opens a dialog with every list of the user; a list they
may only read stays in it, dimmed with a lock and a tooltip. The list
keeps an independent copy: the line, the type, every measure and setting,
the waypoints in order with their roles, the origin, and the trip and tour
it was saved from as they were called then. Its days, its links to places
of the trip and its obstacle decisions stay in the trip, and later changes
to the tour do not reach the copy.
A collection shows its kept tours as cards above its places: the grade
tile with the source badge, measures and the waypoint count as badges,
the trip it came from, and who kept it. The owner or an admin of the list
can remove one after a question; tours made from it stay. "Add to a trip"
shows the kept tour on a map with its facts and numbered waypoints, lists
the user's trips (the ones they may not add tours to dimmed), and asks
outright whether the waypoints come along. "Line only" keeps the line as
saved and adds no waypoints; a tour kept without a line can only bring
them. The new tour has an id of its own, no days and no new places, and
names the trip and tour it was saved from; the dialog then offers to open
that trip. Neither the collection nor the original tour changes.
On the server the kept tours are a table of their own in the tours domain
(collection_tours, migration 046100), each row written whole once. Every
copy, the in-trip "save as new tour", the take-over from another trip and
both directions here, now goes through one copy model (tour-copy.helpers)
instead of a second one. Reading and removing follow the collection's
roles, keeping one also needs access to the source trip, and taking one
over needs place_edit on the target trip; the kept tour is read again
inside the write, so one removed meanwhile leaves no half-made tour. The
MCP tools list_collection_tours, get_collection_tour,
save_tour_to_collection, take_over_collection_tour and
delete_collection_tour run over the same service and checks. All 27
locales carry the new strings, and the wiki describes the flow.
A route planned in Google My Maps or Google Earth can now become a tour
without converting it to GPX first. The import button and a file dropped on
the tours workspace take .kml and .kmz files beside .gpx, through the same
preview, the same import routes and the same transaction as a GPX file.
The preview shows every line of the file on its own, numbered, with its
distance and heights; two lines of one placemark are numbered after its name
and never joined. Heights count only where they are heights: kept for an
absolute line, dropped for any other altitude mode and for the all-zero
placeholder My Maps writes, so a missing height stays unknown. What the file
holds besides its lines (pins, areas, overlays, links to other files) is
counted in a dashed card, and nothing is fetched from elsewhere.
The KML reading reuses the place import's codec. A KMZ only ever has its KML
entry unpacked, counted byte by byte against the decompressed cap whatever
its header claims. A file that cannot be read is refused with its reason
(damaged, an archive without KML, too large unpacked), and the toast names
the file and the reason. A KML or KMZ import keeps the gpx origin of a file
import; its provenance names the real format from the stored file name.
A multi-day tour in the planner's list of the trip's tours now unfolds into
its stages (MDT-02), so the stages can be seen together and fitted into the
trip without leaving the one route they are cut from.
- The fold beside a multi-day tour lists its stages in route order, each
from stop to stop with its distance, climb, descent and moving time, read
off the saved tour the way the planner reads them, and below them what the
whole tour adds up to. A value no stage tells is left out, a total some
stages do not tell is marked as at least that much and says for how many,
and a stage whose route is not planned yet says so.
- Each stage has its own day: a pill opens the trip's days, moves the stage
to another one or takes it off again. A stage without a day shows a dashed
"No day" pill. A day holds a tour, or one of its stages, once, and a stage
is on one day at most; the plan's own offline path writes it.
- A stage opens in the planner: the tour opens as any tour does and the
stage is shown once its points are in.
- The day plan names the stage a day holds with its own figures, and the
day's route runs to that stage's start and on from its end; the trip map
draws that stretch only. The tour list still counts a tour once, however
many days hold it or its stages.
- A saved change that takes a stage away (its stage end gone, the tour a day
tour again, back to the recorded track) takes it off its day in the same
write and tells every client; the planner says so before the save.
- REST and the assign_place_to_day tool take the stage by the key of the
stop it starts at, with the same checks; list_tours names the stops
between the stages and the stage each day holds.
A day assignment remembers its stage by that key (migration 046010); every
assignment made before holds the whole tour, as it did.
A hut-to-hut hike or a paddle trip over several days is now planned in the
Tours planner as one tour: the whole route is planned as before, and stops
along it are marked as stage ends (MDT-01). The stages are read off that one
route in its order, never kept as copies, so a change inside a stage changes
the whole tour and every figure on it.
- A Day tour / Multi-day tour switch beside the tour type; a stop's menu
ends a stage there or lets it go on. Back to a day tour removes every stage
end after a confirmation, as one step undo brings back.
- The list of points is headed per stage with its distance and moving time;
a stop that ends a stage carries a moon at its number, on the map too.
- The overview lists the stages from stop to stop with distance, climb,
descent and time (hiking rule per stage, paddle estimate per stage, the
router's time shared by distance otherwise), marks where each ends across
the elevation profile, and a stage of more than a day on the move warns.
- A stage end a change cannot keep (its stop removed, moved to an end or
made a shaping point) is dropped and said so, with undo, never moved
to another point.
- A multi-day tour may take a day a stage, so its time limit grows with its
stages; the tour keeps its one type, portages included.
- The list and the MCP tools show the stage count and where stages end.
Stage ends are a flag on the waypoint (migration 046000); a tour without one
is a day tour, as every tour saved before.
A day of a tour that names nobody now counts for every member of the trip,
not only for its owner. In the planner an empty participant list means
everyone, and a full member list is stored back as empty, so members got
nothing for most shared tours. Only a day that names participants without
the user stays theirs. The tours of a shared trip on no day or only on
undated days are now named as not counting for members as well.
A whole route a multi-day tour's stages were planned from is no longer
dropped on the server as soon as any stage has a day. Each entry carries
derived_from_place_id and the shared summary leaves the route out only
while one of its stages is done, counted and in the period and type. A
route walked last year now still counts when a stage of it is planned for
next month or was left out because it fell through, in the Atlas and over
MCP alike.
A tour on several days is dated on the last of them, as is a recording on
no day, so it no longer counts while it is still under way.
The info text, the get_tour_activity_stats description and the wiki say so.
With the Tours addon on, the Atlas panel gets a third tab, Tours, beside
Stats and Bucket List: what you have done on your tours across all your
trips. A period (all time, this year, the last 12 months or an earlier year)
and a tour type narrow it; the tab shows the distance large with the number
of tours at its corner, the ascent and descent, and the types with their
distance. "Show tours" opens every tour of the period in a dialog with the
same filters, the sums, the split by type and one row per tour.
What counts is said, never guessed. A tour counts once the day it is on is
over, with the values of the planning, badged "Planned" and explained as
not measured. A linked actual track (ACT-01) replaces those values for its
execution, badged "Recorded" and named, and is never added on top nor
counted as a tour of its own. A tour on several days counts once, a whole
route does not count beside the stages planned from it, a paddle tour sums
no heights, and a value nobody knows stays out of the sum, which then reads
"at least". Only the user's own part counts: a day names them among its
participants, or names nobody on a trip of their own; being able to open
somebody else's trip makes none of its tours theirs. Tours still ahead, on
no day or only on undated days are named as not counting. A tour that fell
through can be left out of the sums ("Leave out"): it stays in the plan
and in the list, dimmed, and "Count again" brings it back. Only the user's
own numbers change.
Server: GET /api/tours/activity-stats answers the user's activity entries
across every trip they can open, and PUT /api/tours/activity-stats/exclusions
leaves a tour out or counts it again (the tour must be in such a trip, else
404). A tour_activity_exclusions table keeps the exclusions per user and
tour. The sums are added up by a shared summary in @trek/shared, so the
Atlas and the assistant say the same numbers. MCP: get_tour_activity_stats
and set_tour_activity_excluded over the same service. The tab reads live
and needs a connection, like the rest of the Atlas statistics.
Each actual track in a tour's detail now stands beside the plan instead of
on its own: a table names the plan and the actual track as columns, each with
the line it is drawn as on the map, and sets distance, ascent, descent and the
time with breaks side by side. The difference is shown, signed and with an
arrow, only where both values are known and mean the same thing; a planned
total that leaves a stay out reads "at least" and is not subtracted from. A
value one side does not carry is named as missing ("Not in the plan", "Not in
the track", "No time stamps"), never estimated. Below the table, how far the
track left the planned line: its farthest point and the recorded stretches
more than 50 m away, or that there is no line to compare.
On the desktop plan map, "Compare on map" draws the actual track dotted in
the colour of done next to the plan, which stays picked in its own track
colour (and is put back should it be hidden on the map). The recording leaves
the map as a tour of its own meanwhile, so it is never drawn twice or in a
plan's colour. A frosted legend over the map names both lines and ends the
comparison; so do closing the detail, comparing another track, or the track
being unlinked. Comparing only reads: neither the plan nor the track changes.
The track is laid into the day's route lines the map already draws, so both
renderers show it without a layer of their own. distancesToLine in the shared
route corridor measures many points against one line laid flat once; a long
recording is measured in at most 1500 samples.
A tour detail that cannot be read (offline without a cached copy, or a server
error) no longer shows "No actual track yet" while the trip list names tracks
of the tour; the section says they could not be loaded and offers no link over
them.
The day a track was recorded on is the viewer's calendar day of its first time
stamp, not the UTC one, in the tour detail, the link dialog and the GPX
preview alike, through one helper.
Taking a tour off a day keeps its actual track without a day, so "no day" can
hold several. A change now starts on the track it was asked for, and the link
dialog names every track it replaces, as the server clears all of them. The
migration, repository, service and MCP texts say so.
The refusal for linking a tour to itself or a track with tracks of its own now
reads "This track cannot be linked to this tour", which is true of both, and
the offline helper of the tour cache sits above the doc of replaceTripTours
again.
A planned tour can now be given the track it was actually done with. In the
tour's detail, "Add actual track" opens a dialog that asks for the day the
tour was done on (or none) and a recording of the trip: an import nobody
planned over, or a new one through the existing GPX import, its preview
preset to the tour's type. What the choice measures is shown before anything
is written, and only "Link" writes. The linked track keeps its own name and
source; the detail shows its distance, heights, profile and, only where the
file carried time stamps, the time it took, marked as actual values next to
the untouched plan. A track can be changed or unlinked again.
Server: a tour_activities table points a tour's execution (a day assignment,
or none) at a recording of the same trip, and the tours GPX import keeps the
first and last time of a track whose every point carries one. The values are
read from the recording's own line on every read, so a changed recording
updates them while the plan's line, measures and revision stay as they were.
Every check runs inside the write: the recording must be an import of this
trip not planned over, documenting no other tour; the day must be one of this
tour; a refusal names its reason and changes nothing. PUT and DELETE
/api/trips/:tripId/tours/:placeId/activities answer the detail, which now
carries the actual tracks; the list names them per tour and per recording.
MCP: assign_tour_track and unassign_tour_track over the same service and
checks, get_tour_plan reads the values without the line.
A recording linked as a tour's actual track is no longer counted as a tour of
its own in the trip's tour summary, and the GPX preview imports a city walk
as one instead of as a hike.
The hike's "SAC grades" card becomes "Trail details": one switch, then a
segmented choice between SAC, Surface and Way type, three things kept
apart and drawn along the route on the planner map one at a time. Every
facet reads from the same answer: the ways under the line are matched on
foot once, their OpenStreetMap values fetched once through the
trail-grades read MAP-03 already uses, and each stretch is placed against
the tour's own line once. Switching facets asks nothing new.
The server now hands on a way's surface and highway tags as OpenStreetMap
wrote them, only trimmed and bounded. The planner groups them (asphalt or
concrete, paving stones, compacted, gravel, natural ground, grass, rock,
wood or metal, unpaved without a kind, other; path, footway, steps, farm
or forest track, cycle path, minor road, road, via ferrata, other), and
each row's tooltip names the values recorded, such as surface=gravel,
surface=pebblestone. The router's own surface reading is never used: it
is normalised and a default where nothing is recorded.
What is not known stays unknown and says why, in every facet: no value
recorded, a value no group takes or two at once (unclear, never the
nearest group), no way clearly under the tour's line, or a way that could
not be asked about. Imported tracks and hand-drawn stretches keep their
geometry; a matched way only counts where it keeps within 25 m of it.
A summary badge gives the known share and the most common class; the SAC
facet keeps its highest step and routing limit badges. Nothing about the
tour, its places or its days changes, and no routing preference is set.
A hike in the planner, being edited or viewed as an import, now has an
"SAC grades" card. Switched on, it asks the router which OpenStreetMap
ways lie under the line (matched on foot, every grade of path open) and
the server reads their sac_scale through the Overpass mirrors, the same
trail-grades read the mountain bike grades use. The grades are drawn
along the route on the planner map in one ramp of a single hue, T1 to
T6, and listed by share and length; a row draws its class alone. Each
row names its source in a tooltip: the SAC hiking scale and the
sac_scale value OpenStreetMap wrote.
What is not known stays unknown and says why, never T1: a way without
a grade, a grade that names no single step (handed on as written), a
stretch with no way clearly under the tour's line, or a way that could
not be asked about. For imported tracks and stretches drawn by hand a
matched way only counts where it keeps within 25 m of the tour's own
line, so the original line is kept and nothing is guessed. The router's
own reading of the scale is not asked for, since it may be normalised.
The routing limit of a planned hike sits apart as a setting with its
own badge, and a known step above it is marked. Nothing about the tour,
its places or its days changes; switched off, the map is as it was.
No regional colour categories and no grade derived from slope, height
or trail markings.
The expected_revision field told assistants to read now.revision of the
preview, but prepare_tour_undo never returns that field: the revision sits
at undo.expected_revision. An assistant following the description either
guessed or left the value out and ran into a validation error or a revision
conflict. The description now names the real field, and the schema spec
pins it.
An assistant can now take back a change it saved with save_tour_change,
the way the change was saved: listed, shown, then taken back only after
the traveller said yes. Until now a saved step could be followed but not
undone; the traveller had to rebuild the walk by hand in the planner.
- list_tour_change_steps lists the steps of a tour, the latest first, with
the changes as confirmed and where each stands: latest, undone, later
change on top or no readable earlier state. Planner saves are no steps.
- prepare_tour_undo shows what taking a step back does without writing
anything: the tour now, with the stations visited or skipped, set
against the tour exactly as the step kept it, the stations kept, coming
back and removed, and the distance and walking time stored then.
- undo_tour_change restores that tour whole or not at all, through the
write the planner's save uses: line, stations with their keys and the
measures stored then, in one transaction with the mark on the step, and
the trip is told after the commit. It needs place editing on the trip
and checks everything again inside the write.
- Only the tour's latest change goes back. A step something was saved on
top of since, in the planner or by another step, is a conflict on the
tour's one revision (no second one), so no later edit is lost unseen; a
preview read at another revision is a conflict too. Taking back a step
that would remove a station visited or skipped since, or bring back a
station whose place of the trip is gone, is refused with every reason,
and so is a step without a readable earlier state. Every refusal and
failure leaves the tour as it is.
- A step is taken back once: tour_change_steps records the revision that
raised the tour to, who confirmed it and when, and nothing else is kept.
- None of it touches a planner draft: the planner's own undo stays in the
browser, and discarding a draft never changes a saved tour. The tool
descriptions and the wiki say so.
The write of a tour's line and points and the tour as the answer gives it
now come from one place for the save and the undo.
An assistant can now save the change prepare_tour_change prepared, once the
traveller said yes to it exactly as shown. Until now a proposal could only
be looked at; the traveller had to redo it by hand in the planner.
- The save names the proposal: the same changes, the revision it was
prepared on, the proposal_id the preparation answered and confirmed true.
Anything else, a change altered on the way or no yes, is refused and
nothing is saved.
- Place editing on the trip and the tour are checked again before anything
is written. A tour changed since the proposal was prepared is a conflict
on the tour's one revision (no second one), telling the assistant to
prepare the change anew instead of writing over newer edits. The changes
are laid on the saved tour once more inside the write, so a station
visited or skipped meanwhile, or a place of the trip gone, refuses the
save with every reason.
- The change goes through the write the planner's save uses, in one
transaction: line, stations, keys, measures and visits together or not at
all, and the trip is told only after the commit. Stations kept keep their
keys and visits. Where the router gives no way on foot the walk keeps its
stations only and waits for the planner, as a created one does.
- Every save is kept as a step of the tour (tour_change_steps): the
proposal, the revision it was prepared on and the one it raised the tour
to, the changes and the tour as it was before them, so the step can be
followed and taken back later. Nothing of the conversation is kept.
- A new walk has no revision to name and stays with create_city_walk; both
tool descriptions and the wiki say which is which.
An assistant can now prepare a change to a saved city walk and show the
traveller what it would do before anything is saved. Preparing writes
nothing: no tour, station, visit or day plan changes, and turning the
proposal down keeps the plan as it was.
- The changes apply in order and name the saved stations by their keys:
add a station after another (a spontaneous stop is an add after the
station the traveller is at), remove, replace and move. Stops put after
the same station keep the order they were given in.
- What the travellers did stays as it is: a station visited or skipped on
any day of the walk is never removed, replaced or moved, nothing goes
before the last station already done, a protected station keeps its
place and a leg drawn by hand stays as drawn. A proposal breaking a rule
is refused whole, naming every change and why. Other tour types, and a
walk that is a recorded track, are refused too: so far only a city walk
takes prepared changes, since the others plan their way with routing of
their own the server cannot run.
- The answer sets the walk after the change against the saved one: each
station with what changed it and where it stood, what was removed, the
way on foot before and after planned by the same router (the stored
distance and walking time given apart, never mixed in), the stays as far
as known, every leg with the new ones marked, the gaps that could not be
worked out, a warning for a must station removed or replaced, and each
new station as create_place takes it, to keep it for later as a place of
the trip instead.
- The proposal names the revision it was prepared on, so a save of it is
refused once the tour has moved on, and says whether the traveller may
change the trip's places at all.
The way on foot of a new walk, its creation and a prepared change now come
from one CityWalkFootWayService instead of a copy in the briefing service.
A ride sends its full line with heights and every horse route section's
own line besides, about fifty bytes a point, so a ride along a few
thousand points of bridleway hit the API's 100kb body ceiling and the
save failed with a 413. Creating and editing a tour are now measured
against TOUR_WRITE_MAX_BYTES (2 MB), like the book and list file
routes; every other route, the tour copy among them, keeps 100kb.
The horse routes kept in memory are now bounded by section points as
well as by count (64 answers, 500k points), so panning a dense map can
no longer grow the server by hundreds of megabytes.
A search that found no connection can be asked again on the view whose
routes are shown, and a ride with a recorded time shows the horseshoe
beside its riding time instead of footprints.
A tour can now be a ride (HOR-01). The planner offers "Horse ride" as a
tour type with its own horseshoe, and a Horse routes card beside the
waypoints looks, when asked, for the route=horse relations OpenStreetMap
knows in the map view. A route opens in a dialog that shows it on a map in
the sections it is made of, split at forks, gaps and crossings, so nothing
is ever joined across a gap. The rider picks a section and its direction,
sees what the horse=* tags along it say (open, limited, closed, or unknown
where untagged) and whether it is signposted the other way, and takes it as
one undoable step. A section that does not start where the ride ends is
only joined by a straight manual stretch once the rider switched that on.
Nothing of a ride is routed: every leg follows a section or is drawn by
hand, and the waypoint list and the map say which (a section as a solid
line with its route, a manual stretch dashed and marked unchecked). A point
at a section stays where the route has it, a ride works out no riding time,
and distance, heights, day assignment, GPX import and export, the 3D view
and the reversed ride keep working with each leg's origin saved and opened
again. A failed lookup leaves the ride and the routes already found as they
were.
The server reads the routes through the shared Overpass client
(GET /api/trips/:tripId/tours/horse-routes, Tours addon, trip access),
keeps an answer twelve hours per grid-aligned view, and the tour contract
refuses a routed leg, a via ferrata or a riding time on a ride and a horse
route section on any other type. A migration enables the horse tour type.
SKI-02. Ski joins the types a GPX file can be imported as, offered in the
import preview's type field only: TREK routes no ski track, so the planner
never offers it. The preview asks for the discipline on purpose (alpine,
snowboard, cross-country or ski touring, none chosen at first) and, for
cross-country, the technique (classic, skating or unknown); Import waits
until both are named, and the technique stays in sight but dimmed for the
other disciplines. The track is stored exactly as recorded, with its file
name as provenance, its distance and heights from the file and no time:
no ski time is worked out and no hiking estimate stands in for one.
Opened in the planner, a ski track gets a rail card with its discipline on
a tinted tile, a cross-country technique as a badge beside it, the ski time
said as not worked out, and an info dot on what TREK does not say (snow,
avalanches, open runs, and that the 3D gradient colours are no difficulty
or avalanche rating). Change opens a dialog to classify the track again;
only the classification changes, through the offline core, with the
revision it was made at. Planning over the import is not offered for ski.
The existing 3D terrain view, the elevation profile and its focus work on
the track as for any import, with the standard map, topo and satellite and
no via ferratas. Lists, the day plan and the detail show the discipline as
a frosted corner badge on the tile and as a pill with the technique inside;
day assignment, copies and take-overs work as for any tour. The corner
badge is now one component that the winter label shares.
The server keeps tours.ski_discipline and tours.ski_technique (CHECK lists,
NULL on every other type), switches the ski type on without a routing
profile, refuses a ski import without its discipline, a technique outside
cross-country and ski fields on any other type, and takes a planned save's
classification off. PUT /api/trips/:tripId/tours/:placeId/ski classifies a
ski track again (place_edit, 409 on a stale revision, 400 for a tour that
is no ski track) and broadcasts tours:changed. GPX export names the
discipline (alpine_skiing, snowboarding, cross_country_skiing,
backcountry_skiing), and list_tours describes both fields with what a ski
track does not say. Ski is labelled plainly as Ski in every language, so
it no longer reads as ski touring.
RUN-02. Trail running joins Running as a run profile, chosen on purpose in
the planner and in the GPX import. It asks Valhalla's pedestrian costing for
tracks wherever they serve (use_tracks 1) and admits mountain paths up to T2
(max_hiking_difficulty 2), never T3 and above, with ferries only where no
way on land exists. Checked with trace_attributes against the public
instance: above Freiburg Guenterstal up to the Schauinsland the route went
from 82 % roads and 83 % paved (running) to 78 % forest tracks and 81 %
compacted, gravel and dirt; Rathen to the Bastei took 28 % of T2 path that
running leaves out; Heidelberg's old town stayed as it was. Leaning on
footways (walkway_factor) was tried and left out, it moved runs onto paved
footways.
While a run is planned, a card says what it runs on: its surfaces, the
hiking grades of its paths (sac_scale, T1 to T6, as mappers gave them) and
its kinds of way, each as shares with lengths that point at their stretches
on the map. A way without a grade or a surface is its own row, unknown and
never easy, and an info dot says the grades say nothing about whether a way
can be run. The head carries the unpaved share and the hardest graded path
as badges. The line is matched on foot for this, so steps and mountain
paths stay on it; a bike tour's is matched as before. Reading fails, goes
offline or is retried as for a bike tour, and nothing of it changes the run.
Pace and time are RUN-01's: the running time stays the distance at the
runner's pace, with climbs, descents and difficulty left out, whatever the
profile. A profile change plans the route again and keeps the pace; a
failed trail route keeps the last route and holds Save back. The card's
building blocks moved out of the bike card into RouteWaySections, so both
cards share one set of rows, bars and status lines.
The run_profile column already allowed trail (RUN-01), so no migration.
GPX export names a trail run trail_running, list_tours describes the
profile as a routing preference, never a statement that a way can be run.
RUN-01. Run joins the tour types in the planner, with Running as its first
profile, chosen on purpose like a bike tour's. A run is routed on foot for
runnable, mostly paved ways: tracks and ferries only where there is no other
way (use_tracks 0, use_ferry 0, measured against the public Valhalla), no
hiking limit and no via ferrata. The runner types a pace in min/km; the
running time is the distance at that pace and nothing else, shown under the
field as badges (8 km x 6:00 /km = 48 min). TREK suggests no pace: without
one the time stays unknown and Save waits, text that is no pace or a pace
outside 2:00 to 20:00 is marked. The info dot, the overview and the head say
climbs, descents and difficulty are not in the time, and the time reads as
planned everywhere, so it never passes for a recorded one; the heights are
shown as for any tour on land.
Type, profile, pace and route come back on opening, survive a draft reload,
an undo of the type, a copy and a take-over; switching to another type drops
profile and pace. Day assignment, the 3D terrain view (with topo and
satellite, no ferratas) and a routing failure keeping the last route work as
for every tour. A GPX file can be imported as a run with its profile and no
pace, and planned over as a run. Runs export to GPX as running and get their
own places along the way (water, toilets, parks, viewpoints).
The server keeps tours.run_profile (CHECK list, already holding trail for
RUN-02, since SQLite cannot widen a CHECK in place) and
tours.run_pace_seconds_per_km (120 to 1200), switches the run type on,
refuses a run without a profile and run fields on any other type, and
list_tours names both with what the planned time does not include.
HIK-01. The details of the hiking planner gain an optional Winter activity
switch, off by default, so the normal hiking flow asks for nothing more.
Switched on, the hike is a winter hike or a snowshoe hike; the choice stays
dimmed and out of reach while the switch is off. The label is saved with the
tour, comes back when it is opened, survives a draft reload, a copy and a
take-over, and switching it off takes only the label away: the route, its
grade and the days stay as they were.
The label is a label only. Routing, the walking time and the 3D terrain view
work as for any hike, and the info dot and the head pill's tooltip say that
nothing was checked for snow, avalanches or whether a path can be walked in
winter. The saved label shows as a frosted snowflake on the corner of the
tour's tile in the tour list and the day plan, and as a pill beside the type
in the tour's detail.
The server keeps it in tours.winter_activity (CHECK list, NULL for every tour
saved before and for every other type), refuses it on a bike tour, a city walk
and a paddle tour, and keeps the stored label when an older client saves a
hike without the field. A snowshoe hike exports to GPX as snowshoeing.
list_tours names the field, with the same words on what it does not say.
A search for sights along a tour now also asks the places index for the best
known places near the line, ranked by how often their Wikipedia articles are
read (QRank). A row the index already found is marked as a highlight; a
famous sight no kind names, like a square, is added as a sight of its own.
Stations, hotels and restaurants rank a row they match but are never added.
Highlights are listed first with a star in the list and a badge in the map
card. A place counts as a highlight from 40000 views a year, or the best
three from 5000 where fewer reach that. An index without ranks, or one older
than the endpoint, leaves the search as it was.