fix(demo): the profile route writes only the baseline fields in the demo

Allowlisting `PUT /api/auth/profile` so the setup flow's baseline step could
finish also handed every visitor the shared demo account's contact email, its
display name, its full name and its insurer fields: the allowlist admits a
path and a method, and every field the handler behind it writes comes with
them. The justification beside the entry named three fields; the entry
admitted eleven.

The write is narrowed on the server, in `applyProfileUpdate`, to height, date
of birth and sex while `DEMO_MODE` is set — not in the client, which is the
party the allowlist exists to distrust. It happens ahead of the email conflict
check, which would otherwise answer "is this address registered here?" to
anybody who can open the demo. The display-name box goes read-only there, as
the anamnesis card already is, so nothing accepts input it will discard.

The entry's comment now lists what the handler writes and what is admitted.
This commit is contained in:
Marc-André Bombeck committed 2026-09-11 12:22:47 +02:00
1 parent ceefbc5571
commit 45599c527e
7 files changed
+338 -6

No files matched your search

+11 -3
View File
@@ -185,9 +185,17 @@ const DEMO_MUTATION_ALLOWLIST: ReadonlyArray<{ path: string; method: string }> =
// v1.39 — the baseline write the confirm screen makes. Without it a demo
// visitor who typed a height got a 403 and a generic toast, so only the
// empty-form/Skip path completed and the demo did not in fact walk the
// same flow (design spec §Principles 5). Date of birth, height and sex
// are closed, validated fields on the caller's own record and no health
// data.
// same flow (design spec §Principles 5).
//
// Read the HANDLER's field list, not the caller's. This route writes
// `email`, `displayName`, `fullName`, `insurerName`, `insurerIkNumber`,
// `insuranceNumber`, `locale`, `timezone`, `timeFormat`, `dateFormat` and
// `moodReminderEnabled` as well as the three the baseline step collects —
// admitting the path admits all of them, and on one shared published
// account each is the next visitor's starting state. So the write is
// narrowed on the SERVER: `applyProfileUpdate` drops everything outside
// `DEMO_WRITABLE_PROFILE_FIELDS` (height, date of birth, sex) while
// `DEMO_MODE` is set. What this entry admits is those three fields.
//
// Two neighbours of it are deliberately NOT here. The demo is one shared,
// published account, so "the caller's own" is every visitor at once: