mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
docs(insights): document english tile-id contract + naming ADR
Regenerate `docs/api/openapi.yaml` so the `InsightsLayoutBody` enum carries the canonical English tile ids first, then the accepted-but-deprecated legacy German ids, with the normalisation + deprecation spelled out in the schema description. Add ADR 0001 fixing the convention — localised UI copy, English internal identifiers — and the non-breaking alias strategy. Add an iOS coordination note covering the new canonical ids, the continued acceptance of the legacy ids, and the recommended migration path.
This commit is contained in:
1 parent
607dd9e5df
commit
262a3ad70a
4 files changed
+214
-12
No files matched your search
@@ -0,0 +1,82 @@
|
||||
# 0001 — Insights naming convention: localised UI, English identifiers
|
||||
|
||||
- Status: accepted
|
||||
- Date: 2026-05-31
|
||||
|
||||
## Context
|
||||
|
||||
The Insights surface grew bilingually. The mother page (`/insights`) and its
|
||||
routed metric sub-pages were keyed by German slugs (`/insights/blutdruck`,
|
||||
`/insights/gewicht`, …) because German was the primary author voice when the
|
||||
routed strip first shipped. Over time the surface accumulated a mix: route
|
||||
folders, the tile-layout enum, and several internal maps were German, while
|
||||
later additions (`hrv`, `oxygenSaturation`, `restingHr`, `activeEnergy`,
|
||||
`workouts`) landed in English. The result was an inconsistent identifier space
|
||||
where a contributor could not predict whether a given key was German or English.
|
||||
|
||||
Identifiers leak. A German route slug shows up in URLs, in browser history, in
|
||||
the OpenAPI contract the iOS client reads, and in every internal map that pivots
|
||||
on the slug. Mixed-language identifiers make the codebase harder to navigate and
|
||||
make the public API contract read inconsistently.
|
||||
|
||||
Two surfaces also speak these identifiers across a boundary we do not control:
|
||||
|
||||
1. **URLs** — bookmarked and cached by the PWA.
|
||||
2. **The tile-layout contract** — `GET/PUT /api/insights/layout`, which the
|
||||
native iOS client persists against. The tile ids in that payload are a
|
||||
client-visible contract.
|
||||
|
||||
## Decision
|
||||
|
||||
Separate the two naming axes cleanly:
|
||||
|
||||
- **UI copy is always localised.** Every visible string resolves through an
|
||||
i18n `t()` key and is translated across all six locales (`de / en / es / fr /
|
||||
it / pl`). The user never sees a raw identifier.
|
||||
- **Internal identifiers are English.** Route slugs (`/insights/<slug>`), the
|
||||
tile-layout enum (`INSIGHTS_TILE_IDS`), query keys, and the internal
|
||||
slug→metric / slug→target maps all use established English terms. English is
|
||||
the lingua franca of the codebase and of the public API contract.
|
||||
|
||||
Concretely, v1.8.0 migrates the routed Insights slugs and the tile-layout enum
|
||||
from German to English (e.g. `blutdruck` → `blood-pressure`, `gewicht` →
|
||||
`weight`, `medikamente` → `medications`). The full rename table lives in
|
||||
`src/lib/insights/sub-page-metric.ts` (slugs) and `src/lib/insights-layout.ts`
|
||||
(tile ids).
|
||||
|
||||
## Non-breaking strategy
|
||||
|
||||
The migration must not break either client-visible boundary:
|
||||
|
||||
- **URLs.** `next.config.ts` `redirects()` emits a `permanent: true` (301)
|
||||
redirect from every legacy German slug to its English target, including a
|
||||
`:path*` variant so any nested route survives. Bookmarks and cached PWA
|
||||
navigation keep resolving.
|
||||
- **Tile-layout contract.** The layout endpoint keeps **accepting** the legacy
|
||||
German tile ids on input. The Zod enum is built from
|
||||
`ACCEPTED_INSIGHTS_TILE_IDS` (canonical English ids *plus* the legacy German
|
||||
aliases), so a `PUT` carrying old ids validates rather than tripping a 422.
|
||||
`normalizeInsightsTileId` collapses each legacy id onto its canonical English
|
||||
replacement; this normalisation runs on **both** the read path
|
||||
(`resolveInsightsLayout`) and the write path (`serializeInsightsLayout`), so:
|
||||
- a layout persisted by a `≤ v1.7.x` client surfaces canonical English ids on
|
||||
`GET` without forcing a re-`PUT`;
|
||||
- a `PUT` sending legacy ids persists canonical English ids;
|
||||
- a layout that carries both a legacy and a canonical id for one tile dedupes
|
||||
to a single canonical entry.
|
||||
|
||||
The legacy ids are accepted-but-deprecated. They will be removed from the
|
||||
accepted set in a future major version once telemetry shows clients have
|
||||
migrated. The OpenAPI `InsightsLayoutBody` schema documents the canonical ids,
|
||||
the accepted legacy ids, and the deprecation.
|
||||
|
||||
## Consequences
|
||||
|
||||
- The Insights identifier space is uniformly English and predictable.
|
||||
- No client breaks on upgrade: old URLs redirect, old tile ids normalise.
|
||||
- The legacy-alias map and the redirect table are deliberate, finite debt to be
|
||||
retired in a future major. Until then they are covered by tests
|
||||
(`src/app/api/insights/layout/__tests__/route.test.ts`) that assert the
|
||||
non-breaking round-trip.
|
||||
- New Insights surfaces follow the convention from the start: English slug,
|
||||
English tile id, localised `t()` copy.
|
||||
+36
-8
@@ -2440,17 +2440,27 @@ components:
|
||||
type: string
|
||||
enum:
|
||||
- overview
|
||||
- blood-pressure
|
||||
- pulse
|
||||
- oxygen
|
||||
- body-temperature
|
||||
- weight
|
||||
- bmi
|
||||
- active-energy
|
||||
- workouts
|
||||
- sleep
|
||||
- resting-pulse
|
||||
- hrv
|
||||
- mood
|
||||
- medications
|
||||
- blutdruck
|
||||
- puls
|
||||
- sauerstoff
|
||||
- koerpertemperatur
|
||||
- gewicht
|
||||
- bmi
|
||||
- aktive-energie
|
||||
- workouts
|
||||
- schlaf
|
||||
- ruhepuls
|
||||
- hrv
|
||||
- stimmung
|
||||
- medikamente
|
||||
visible:
|
||||
@@ -2467,7 +2477,11 @@ components:
|
||||
- version
|
||||
- tiles
|
||||
description: "Per-user Insights tile layout: an ordered list of tiles with a visibility flag. `version` is the layout
|
||||
schema version; tile ids are a closed enum derived from the server's tile registry."
|
||||
schema version. Tile ids are a closed enum: the canonical ids are English (matching the routed
|
||||
`/insights/<slug>` sub-pages). The legacy German ids (blutdruck, puls, sauerstoff, koerpertemperatur, gewicht,
|
||||
aktive-energie, schlaf, ruhepuls, stimmung, medikamente) remain accepted on input for backward compatibility and
|
||||
are normalised to their English equivalents before persisting; GET responses always carry the canonical English
|
||||
ids. The legacy ids are deprecated and will be removed in a future major version."
|
||||
CoachMessageFeedbackRequest:
|
||||
type: object
|
||||
properties:
|
||||
@@ -5935,17 +5949,27 @@ components:
|
||||
type: string
|
||||
enum:
|
||||
- overview
|
||||
- blood-pressure
|
||||
- pulse
|
||||
- oxygen
|
||||
- body-temperature
|
||||
- weight
|
||||
- bmi
|
||||
- active-energy
|
||||
- workouts
|
||||
- sleep
|
||||
- resting-pulse
|
||||
- hrv
|
||||
- mood
|
||||
- medications
|
||||
- blutdruck
|
||||
- puls
|
||||
- sauerstoff
|
||||
- koerpertemperatur
|
||||
- gewicht
|
||||
- bmi
|
||||
- aktive-energie
|
||||
- workouts
|
||||
- schlaf
|
||||
- ruhepuls
|
||||
- hrv
|
||||
- stimmung
|
||||
- medikamente
|
||||
visible:
|
||||
@@ -5964,7 +5988,11 @@ components:
|
||||
- tiles
|
||||
additionalProperties: false
|
||||
description: "Per-user Insights tile layout: an ordered list of tiles with a visibility flag. `version` is the layout
|
||||
schema version; tile ids are a closed enum derived from the server's tile registry."
|
||||
schema version. Tile ids are a closed enum: the canonical ids are English (matching the routed
|
||||
`/insights/<slug>` sub-pages). The legacy German ids (blutdruck, puls, sauerstoff, koerpertemperatur, gewicht,
|
||||
aktive-energie, schlaf, ruhepuls, stimmung, medikamente) remain accepted on input for backward compatibility and
|
||||
are normalised to their English equivalents before persisting; GET responses always carry the canonical English
|
||||
ids. The legacy ids are deprecated and will be removed in a future major version."
|
||||
Medication:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in new issue
Block a user