A ride recorded elsewhere comes in through the one Tours GPX import (HOR-02): pick the file, choose Horse ride in the preview and confirm. Once a ride is chosen, the preview says in three badges what the import will and will not do for it: the line stays as the file recorded it, no riding time is worked out, and nothing checks whether its ways may be ridden. Each badge gives its reason in a tooltip, reachable by keyboard. Nothing is stored before the confirmation. Opened again, the ride's rail carries a Recorded ride card with the same badges above its measures, and names heights the file did not carry instead of showing them as zero. Its origin and file name stay in the tour's provenance, it goes on a day like any tour, and no editable version is planned from it on foot. The import itself was already canonical and needed no change; end to end tests now pin what this card promises: the stored line equals the recorded points, the ride keeps its origin, distance and heights and has no riding time, a file without heights keeps them unknown, a failed or refused import leaves an existing ride and its place untouched, and the same file twice is skipped.
@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.