Files
TREK/shared
Maurice 8f691bff5a feat(i18n): untranslated strings per locale may only shrink
Parity proves a locale has every key, not that the key holds the
locale's language: copying the en string passes it, so a feature could
add 26 English copies and stay green. Nothing counted them either. Today
the locales hold 3157 strings marked `// en-fallback` and 1252 unmarked
values identical to en.

scripts/i18n-untranslated.mjs counts both per locale and file and holds
them at scripts/i18n-untranslated-baseline.json, recorded from today's
tree. i18n-parity --strict runs it, so the existing CI step enforces it.
The two counts are separate on purpose: dropping a marker without
translating moves the string from one count to the other and still
fails. --update lowers the baseline to the current counts and never
raises an entry. A missing or malformed baseline, a locale lacking one
of en's files or a value the reader cannot parse is an error, not a
pass.

An identical value is not counted when it reads the same in every
language: after dropping placeholders, markup, URLs, e-mail addresses,
paths and a short list of multi-word names (Google Maps, Home
Assistant), at most one plain word may be left, where acronyms, single
letters and names with an inner capital are not plain words. That
excuses "{count} km", "GPX", "OAuth" and "Budget" and keeps "Source
code" counted.
2026-10-08 13:04:41 +02:00
..
2026-06-18 20:13:30 +02:00
2026-06-16 22:22:45 +02:00
2026-06-16 22:22:45 +02:00
2026-06-16 22:22:45 +02:00
2026-08-27 13:22:39 +02:00

@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): via paths in server/tsconfig.json.
  • Client (vite): via resolve.alias in client/vite.config.ts (+ paths for 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.