The editor gains a card under the waypoints: along the tour. It offers what the tour type stops for as chips (a hike viewpoints, huts and shelters, drinking water, food, summits, toilets, picnic spots, campsites, sights; a paddle tour put-ins, boat rental and the like, the first three ticked) and how far from the route to look, 250 m to 2 km. Only its button searches. Each place found shows how far it lies from the route, straight across, and where along the route; its pin is on the map in its category's colour, and a click there opens it in the card. Opened, a place says its kind and source, its address, opening hours as the source has them with a note to check them, and its website. The answer says when it is out of date (the route or the choices changed since), offline, failed, partly searched, cut short at the first part of a long tour, or more than shown. Nothing about the tour changes by searching. An opened place can go in as a stop: after the point chosen, the one before it along the route suggested, by the button alone, as one step undo takes back. It becomes a stop of the tour on the place's spot, not a place of the trip. A leg drawn by hand or a fixed line (a via ferrata, a portage) is not cut: the point after which it would go says why and offers no button. Once the new route is in, the card says what the stop added, as the difference of the route planned before and after; while it is planned it says so, and where either route could not be planned it says that rather than guess. The search merges a place OpenStreetMap maps twice, as a point and as its outline, by its name and spot. The library repository takes its offline error from a shared online-only module, which the search uses too.
@trek/shared
Single source of truth for TREK's API contracts, expressed as Zod schemas and consumed by both the server (request validation + inferred DTO types) and the client (typed requests/responses).
This package is part of the incremental NestJS + React 19 migration (see the "Brownfield Rewrite" board). It is intentionally dormant until modules start importing it — adding it changes nothing for users.
Rules
- One folder per domain:
src/<domain>/<domain>.schema.ts(+.spec.ts). - Domain-agnostic building blocks live in
src/common/. - A route is only considered migrated once its contract lives here.
- Schemas are the source of truth; server DTOs and client types are inferred from them
(
z.infer<typeof schema>), never hand-duplicated.
Consumption (dev)
Both apps resolve @trek/shared to this package's TypeScript source:
- Server (
tsx): viapathsinserver/tsconfig.json. - Client (
vite): viaresolve.aliasinclient/vite.config.ts(+pathsfor the type-checker).
Production packaging (Docker / workspace wiring) is introduced in card F2, when the server first depends on this package at runtime. Until then prod builds are untouched.
Not yet here
The canonical error envelope is finalised in card F5 (it must match TREK's current Express error responses byte-for-byte), so it is deliberately not invented in F1.