**"Today" was read off UTC while the clock beside it is local.** `localDate.ts` exists for exactly this and says so in its own comment: between local midnight and the UTC rollover the two disagree, so east of Greenwich the up-next card hung on yesterday's stage for the first hours of every night, which is when somebody on a long stage is actually driving. Both the stage hook and the corridor hook now ask the same helper the rest of the app asks. **A refused day end left the switch showing a state the trip never reached.** The writer catches its own failures and shows a toast, so it never throws and the sheet's catch could not fire, which left the optimistic value standing. It answers whether the day end moved now, and the switch comes back when it did not. The desktop control ignores that answer, as it reads its state back from the trip. **A timed-out corridor search reported more unsearched boxes than it had.** Every worker still alive ran the deadline branch and each added the whole remainder, so three workers reported three times the boxes left, which can exceed the number of boxes there ever were. The remainder is claimed before it is counted, which also ends the other workers' loops. **A night that fell mid-leg had its morning drive dropped from the stage map.** The join mark went on the first leg of every day opening on an automatic night, but only a night standing ON a stop is a connection between two days. `dayWindow` records that difference as a whole `position` against a fractional one, and where it is fractional the morning drive is the last stretch to this day's own first stop. It was being filtered off the stage while its distance stayed in the day's total.
@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.