SKI-01. The Tours planner's layer switch gains a winter layer: OpenSnowMap's transparent piste overlay over whichever base map is shown, so a ski area can be looked at while preparing a winter trip. It is offered with no tour open (a resort without any route), beside a hike for winter hiking and on an imported ski track; it needs neither a GPX import nor the ski type, and a bike tour, a run and a paddle tour do not offer it. It is off until switched on, and the choice belongs to the map view: switching it changes no point, no step and no route, and it stays on from no tour to a hike and into 3D, where the terrain draws it too. The switch goes by its icon alone, named by its tooltip, so a hike's row stays short. While the layer shows, a small key button rides beside it in the same pill, its badge the four grade colours. The key opens above the map as a popover: the downhill grades in OpenSnowMap's own colours (novice, easy, intermediate, advanced, expert, freeride), cross-country trails, winter and snowshoe trails, toboggan runs and lifts, a note that this is mapped data that says nothing about what is open or groomed, the snow or avalanches, and a link to the full key at OpenSnowMap. If the tiles stop coming, the switch turns to the warning tone with its badge and says that the map and the route still work, and the key stays away. Only the overlay is used, never OpenSnowMap's relief or base maps. Like every overlay it loads only the tiles in view: nothing is prefetched or cached by the Service Worker, as their terms forbid bulk downloads. The tiles go out with the page's origin as the referer, the attribution credits OpenSnowMap (CC BY-SA) and the OpenStreetMap contributors, and the layer stops at zoom 18, beyond which the server answers a picture instead of a transparent tile. The CSP admits tiles.opensnowmap.org for the GL map, which reads tiles through fetch.
@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.