mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
fix(onboarding): derive the module map only from a questionnaire that was finished
The only gate on the derivation was Q1 being set, so one answer was enough to turn the whole questionnaire into a module map. Two ways that landed wrong and they compound. Somebody answers who the record is for, closes the tab, and later finishes the legacy four-step wizard, which posts to this same endpoint and knows nothing about these questions: the five unanswered ones each read as their conservative default, eleven surfaces are written off, and the once-only marker makes it unrepeatable. Or any client patches one answer and posts the confirm straight back. The gate now asks whether every question has an answer or a deliberate pass. A half-answered flow derives nothing, is not stamped complete, and keeps its confirm step pending, so finishing the questions later still does the work. The legacy arm is untouched: a caller with no setup row still answers the fixed acknowledgement it always did.
This commit is contained in:
1 parent
7a1f3fe32d
commit
cc6e6ca221
6 files changed
+165
-12
No files matched your search
@@ -376,7 +376,7 @@ export const onboardingPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Onboarding"],
|
||||
summary: "Stamp onboarding as complete, and derive the module map",
|
||||
description:
|
||||
"Marks onboarding finished and saves whatever profile fields came with it, then clears the proxy-readable pending cookie so the next navigation stops redirecting to `/onboarding`.\n\nv1.39 — this is also the needs-based flow's confirm endpoint, and the two halves live side by side. For a record that answered the questions (Q1 is set), it derives that record's module map from the answers and applies it, ONCE: the derivation marker is what stops a second confirm re-applying the questionnaire over decisions taken in Settings since, and `POST /api/onboarding/restart` clears the marker when the person asks for the questions again. The merge is one-directional — a module the answers name is switched on, a module they do not name is switched off only where the record does not already carry an explicit on. The `cycle` key is not written here at all: it delegates to the cycle profile, which this route sets to `true` when the cycle area was chosen and never to `false`. The response then carries `onboarding` beside `completed`; a caller that never entered the needs flow gets the fixed acknowledgement it always did.\n\nThe older sibling of `POST /api/onboarding/step`. It is unconditional in a way the step route is not: it stamps the completion whatever the stored step is, it re-stamps on every call rather than refusing a second one, and it writes no audit row and enforces no rate limit of its own. It also does NOT seed the dashboard from the goal selection — that only happens on the step route's completing call.\n\nCalling this mid-wizard makes every remaining `POST /api/onboarding/step` answer 409 `onboarding.step.completed`, because that route's guarded update requires the completion stamp to still be null.\n\nCookie or wildcard Bearer; `userId` is never read from the body.",
|
||||
"Marks onboarding finished and saves whatever profile fields came with it, then clears the proxy-readable pending cookie so the next navigation stops redirecting to `/onboarding`.\n\nv1.39 — this is also the needs-based flow's confirm endpoint, and the two halves live side by side. For a record that FINISHED the questions — every one of them answered or deliberately passed — it derives that record's module map from the answers and applies it, ONCE: the derivation marker is what stops a second confirm re-applying the questionnaire over decisions taken in Settings since, and `POST /api/onboarding/restart` clears the marker when the person asks for the questions again. The merge is one-directional — a module the answers name is switched on, a module they do not name is switched off only where the record does not already carry an explicit on. The `cycle` key is not written here at all: it delegates to the cycle profile, which this route sets to `true` when the cycle area was chosen and never to `false`. A half-answered flow derives nothing and is not stamped as complete: the answers become a module map, and a flow somebody abandoned after the first screen would have every remaining question read as its conservative default. The same gate is what keeps the LEGACY wizard's completion out of the derivation, since that wizard never puts these questions.\n\nThe response then carries `onboarding` beside `completed`; a caller that never entered the needs flow gets the fixed acknowledgement it always did.\n\nThe older sibling of `POST /api/onboarding/step`. It is unconditional in a way the step route is not: it stamps the completion whatever the stored step is, it re-stamps on every call rather than refusing a second one, and it writes no audit row and enforces no rate limit of its own. It also does NOT seed the dashboard from the goal selection — that only happens on the step route's completing call.\n\nCalling this mid-wizard makes every remaining `POST /api/onboarding/step` answer 409 `onboarding.step.completed`, because that route's guarded update requires the completion stamp to still be null.\n\nCookie or wildcard Bearer; `userId` is never read from the body.",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: { "application/json": { schema: onboardingCompleteRequest } },
|
||||
|
||||
Reference in new issue
Block a user