Rework the private-packing flag into a full sharing model. Every item is now Common (the group pool — where all existing items live, so nothing breaks), Personal (private to its owner) or Shared with specific people (it shows up on those travelers' own lists, marked "by <bringer>"). is_private discriminates restricted from common; a new packing_item_recipients table holds who a shared item covers, and packing_item_contributors records "I can bring that too" pledges on Common items. The panel gains a Gemeinsam / Meine Liste view switch, each item a sharing control (owner sets the tier + the people it covers), and Common items can be co-brought or cloned onto your personal list. Visibility is enforced server-side in listItems and the WebSocket broadcasts are scoped to exactly who can see an item across every tier transition. All 22 locales stay in parity.
@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.