Three things the first cut got wrong. Switching into road trip mode took its time: every leg was its own routing request, paced a second apart so the shared hosts would answer at all. The router already returns a leg per consecutive pair of the waypoints it is handed, so a day is now one request — split only where the travel mode changes, because one request carries one mode. Answers that come from the cache are no longer paced at all, which is what made returning to the view feel broken. A list of petrol stations is half an answer: which one is on your side of the road is the other half. The corridor search therefore moved out of the panel into the planner, and its hits are handed to the map like any other place suggestion — grey, because they are not part of the trip until you add one. The explore pill stands down while the mode is on: it draws into the same channel and answers the same question for a drive. The panel itself was a stack of controls without an order. It now reads as header, search, results: what is being searched (with the day's distance and driving time), what is being looked for, how far off the route, then the hits grouped by kind with a count — and a progress bar while the boxes are being worked through.
@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.