Two boot migrations. The first appends the missing dated days to a trip the old 365-day cap clipped, only where the dated days still run unbroken from the start date, so a trip that was re-dated by hand or lost a day in the middle is left alone; dateless days that hold content stay behind the dated ones as generateDays keeps them. The second rebuilds roadtrip_day_boundaries without the CHECK that held day_number to 366, which would have refused a boundary on a later day of a longer trip. The road-trip contracts follow the same limit: the day boundary and corridor schemas, the set_day_boundary tool and the day window's runaway guard read MAX_TRIP_DAYS instead of their own 365 or 366, and the tooLong message carries the number as a placeholder in all 23 locales.
@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.