The three figures under a traveler's final budget came from the server, netted in integer trip cents at the rate frozen on each expense. The rows listed under them did not: both shells converted the expense list again with whatever live rate they had, and with none loaded yet (first render, offline) the raw foreign amount went out under the display currency's symbol. On any trip with a foreign-currency expense the rows could not add up to the line above them. The settlement response now carries the rows with the figure: `sources` on each finalBudgets entry lists what the person fronted per expense, the recorded transfers on their side and the open flows, in display cents. They are filled by the same two loops that fill the totals, so an expense with no split members stays out of them as it stays out of the ledger, and each list is spread over its figure's already allocated cents with the same largest-remainder split, so the sum is exact in every display currency. The shells print those cents and only resolve names; the rows carry the sign of the line they sit under.
@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.