The card was a flat list: two key fields, four Google switches and a large weather panel, all at the same level. That gave a switch you set once the same weight as the key it depends on, and gave the loudest treatment on the page to the one thing with nothing to configure. Now three comparable provider blocks. The TREK index carries the accent and the recommendation, because a key should be the exception rather than the expected setup. Google carries no border badge, so it does not stand out, and says plainly what it costs beyond money. Weather has left the card: it needs no key and had nothing to set. The "recommended" badge moved from Google to the index, which is the whole point of the change. Also here, and both are their own thing: - The settings tab is two columns from xl up. Nearly every card is "label left, switch right", so the middle stayed empty while the page scrolled for ages. Explicit columns rather than a grid over the flat list, because a grid pairs cards row by row and leaves a hole under the shorter one, and these differ by hundreds of pixels. - Pictures: the nearby fallback drops from 300m to 60m and is skipped entirely for shops and gastronomy. Measured across 600 places in six cities, 2 percent of ordinary businesses have a picture on Wikimedia against 70 percent of churches, so for a cafe the curated rungs never fire and the fallback always does. That is how the town hall ended up over the doner shop. It fails open on an unknown category, so landmarks keep the fallback that works for them. vite.config reads the dev port and the API target from the environment, defaulting to what they were. Several worktrees could not run side by side.
@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.