Roel and gfRally asked for three things: how far the car goes on a tank, how long you are willing to sit behind the wheel in one go, and how much driving belongs in a day. They are one feature. All three are a threshold, a walk over the legs, and a finding. Two things they deliberately are not. They are durations and distances rather than times of day, because with no stop pinned to a clock the cascade produces no times at all, for any stop, and a limit on an hour would simply never fire. And the day limit is called driving time, not travel time, because the figure it is measured against is exactly that: the badge beside it, which counts no time spent at stops and no leg to a hotel. The card says so out loud rather than leaving it to be discovered. The range budget carries across midnight, since a tank does not empty overnight, and resets after a finding: without that, 1800 km on a 600 km range flags every leg after the first overrun. Only fuel and charging reset it, never the other four service kinds — a two-hour lunch fills nothing, and nobody here knows whether the restaurant has a charger in its car park. Kilometres in storage, the traveller's own unit on screen. Skipping that round trip means an imperial user types 400 meaning miles, 400 km is stored, and the warnings arrive a third too early from then on. No stop is suggested and no vehicle is modelled. OSM does not know what car this is and neither do we, so the range is a number you type. Furkot does the same, for the same reason.
@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.