chore(api): regenerate the OpenAPI contract

Picks up the managed-profile read and edit endpoints, the sex field on the
create body, the record-scoped module map on the account payload, and the
delegated cycle field on the record's module settings.

Refs #939
This commit is contained in:
Marc-André Bombeck committed 2026-09-10 00:02:15 +02:00
1 parent fb1cb4e3ed
commit 90ca2cd899
1 file changed
+173 -16
+173 -16
View File
@@ -18446,6 +18446,82 @@ paths:
schema:
$ref: "#/components/schemas/ErrorEnvelope"
/api/managed-profiles/{id}:
get:
tags:
- Account sharing
summary: Read a managed record's identity
description: "What the record is right now — the five fields its creation took. The read an edit form fills itself from,
and the reason it exists: `accountAccess.accounts` on the account payload carries the record's name and nothing
else, so a form offered from the Guardian's own panel had no way to show the timezone, the language or the date
of birth it was about to overwrite. Cookie transport only, an ACTOR surface (the profile is named in the path
and the caller acts as themselves, so it answers without switching into the record), and NOT step-up gated: this
is a read, it discloses to a Guardian only what they already administer, and the gate belongs to the acts."
parameters:
- in: path
name: id
schema:
type: string
required: true
responses:
"200":
description: The record as it stands.
content:
application/json:
schema:
$ref: "#/components/schemas/ManagedProfileEnvelope"
"401": *a1
"404":
description: "No such managed profile, or the caller is not one of its Guardians (`meta.errorCode:
managed_profile.not_found`). The two are byte-identical, so the refusal is not an enumeration oracle."
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorEnvelope"
"422": *a4
"429": *a5
patch:
tags:
- Account sharing
summary: Change a managed record's identity
description: "Edit the record after it exists — the name that was a placeholder, the timezone that moved with the
household, the date of birth somebody finally has, the sex that decides whether the cycle module is on. Any
active Guardian may do it, from a cookie session with a fresh second factor: the same gate creation and deletion
carry, because the three acts mint, change and end an account that can never prove anything about itself.
Answers with the whole record, so a client re-renders from the server's version rather than from what it sent."
parameters:
- in: path
name: id
schema:
type: string
required: true
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateManagedProfileRequest"
responses:
"200":
description: The record as it now stands.
content:
application/json:
schema:
$ref: "#/components/schemas/ManagedProfileEnvelope"
"401":
description: No fresh second-factor proof, or none enrolled. Same unconditional gate as creation and deletion.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorEnvelope"
"404":
description: "No such managed profile, or the caller is not one of its Guardians (`meta.errorCode:
managed_profile.not_found`). The two are byte-identical."
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorEnvelope"
"422": *a4
"429": *a5
delete:
tags:
- Account sharing
@@ -28012,6 +28088,14 @@ components:
type: string
minLength: 1
maxLength: 64
gender:
anyOf:
- type: string
enum:
- MALE
- FEMALE
- OTHER
- type: "null"
required:
- displayName
- locale
@@ -28021,12 +28105,58 @@ components:
The caller becomes its first Guardian in the same transaction, through an ordinary MANAGE grant with the new
record as grantor, so the profile appears in `accountAccess.accounts` on the next `GET /api/auth/me` and is
switched into like any other shared record. `displayName` is the only required text; `dateOfBirth` is an
optional `YYYY-MM-DD` and is never synthesised from a year. `locale` and `timezone` belong to the RECORD and not
to the Guardian reading it: they decide how the profile's own reminders are worded and when its day starts.
Strict — an unexpected field is a 422 rather than an ignored key. Cookie transport only and step-up gated
optional `YYYY-MM-DD` and is never synthesised from a year. `gender` is optional and takes the same three values
`PATCH /api/auth/me` takes for an ordinary account (`MALE`, `FEMALE`, `OTHER`) or null; absent and null both
mean not recorded, and the value is what the cycle module derives its default from, so a record created for a
child who does not need it starts with it off. `locale` and `timezone` belong to the RECORD and not to the
Guardian reading it: they decide how the profile's own reminders are worded and when its day starts. Strict — an
unexpected field is a 422 rather than an ignored key. Cookie transport only and step-up gated
(`requireFreshMfa`, unconditional): a Bearer caller cannot mint a credential-less person and a permanent
management relationship, and an account with no second factor enrolled is refused rather than waved through.
Rate-limited to ten an hour per caller."
UpdateManagedProfileRequest:
type: object
properties:
displayName:
type: string
minLength: 1
maxLength: 80
dateOfBirth:
anyOf:
- type: string
format: date
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))$
- type: "null"
locale:
type: string
enum:
- de
- en
- es
- fr
- it
- pl
- ko
timezone:
type: string
minLength: 1
maxLength: 64
gender:
anyOf:
- type: string
enum:
- MALE
- FEMALE
- OTHER
- type: "null"
additionalProperties: false
description: "Change what a managed record is, from the Guardian's own panel. The same five fields creation takes, every
one of them optional, and at least one required — an empty body is a 422 rather than a no-op that audits a
change nobody made. Absence means leave the field alone; an explicit null on `dateOfBirth` or `gender` clears
it, and the two are different answers. Nothing else on the record is reachable here: credentials, provider
connections, notification routing and the health profile are not identity, and the wider configuration surface
is `PATCH /api/record-settings/{family}`, which is guardian-fenced and answers only while switched into the
record. Strict, cookie-only and step-up gated, like every act in this family."
InviteManagedProfileGuardianRequest:
type: object
properties:
@@ -28291,10 +28421,15 @@ components:
vaccinations:
type: boolean
additionalProperties: false
required:
- modulePreferences
cycleTrackingEnabled:
type: boolean
additionalProperties: false
description: Partial module toggle. Merged onto the record's current preferences; omitted keys keep their value.
description: "Partial module toggle. `modulePreferences` is merged onto the record's current preferences; omitted keys
keep their value. `cycleTrackingEnabled` is separate because `cycle` is a DELEGATED module: its state lives in
the record's own cycle profile and `modulePreferences.cycle` is refused, so this is the field that turns cycle
tracking on or off for the record — an explicit boolean overrides the default the record's sex would derive.
Both fields are optional and at least one is required; an empty body is a 422 rather than a save that changed
nothing."
RecordNotificationSettingsPatch:
type: object
properties:
@@ -43748,9 +43883,12 @@ components:
- nutrients
- vaccinations
additionalProperties: false
description: Fully-resolved per-user module enable/disable map. Every toggleable module key is present. `false` means
the surface should disappear end-to-end (nav, dashboard, insights, …). `cycle` mirrors `cycleTrackingEnabled`;
`coach` mirrors the resolved per-user opt-out + operator master flag.
description: Fully-resolved module enable/disable map. Every toggleable module key is present. `false` means the surface
should disappear end-to-end (nav, dashboard, insights, …). `cycle` mirrors `cycleTrackingEnabled`; `coach`
mirrors the resolved per-user opt-out + operator master flag. On `GET /api/auth/me` it answers for the RECORD
the session is inside rather than for the caller, because every surface it gates shows the record's data; with
no switch — which is every native request, since the Bearer transport carries none — the two are the same
account and the payload is unchanged.
PatchModulesResponse:
type: object
properties:
@@ -66252,13 +66390,31 @@ components:
description: The profile's account id — the value `POST /api/account/switch` and the `X-HealthLog-Account` selector
take, and the `{id}` in this family's paths.
displayName:
type: string
anyOf:
- type: string
- type: "null"
dateOfBirth:
anyOf:
- type: string
- type: "null"
description: "`YYYY-MM-DD`, or null. The same date-only shape the request takes — this is a calendar date, not an
instant, and publishing it with a time would invite a client to apply a zone to it."
gender:
anyOf:
- type: string
enum:
- MALE
- FEMALE
- OTHER
- type: "null"
description: "`User.gender` for this record. Null means not recorded, which is a real answer and not a missing one."
locale:
type: string
anyOf:
- type: string
- type: "null"
description: The record's own language. Every profile this family creates carries one, because creation requires it; the
column is nullable, so null means a row written before that and a client renders its own language rather
than the word.
timezone:
type: string
recordKind:
@@ -66270,15 +66426,16 @@ components:
- id
- displayName
- dateOfBirth
- gender
- locale
- timezone
- recordKind
additionalProperties: false
description: "A record somebody looks after, as its creation answers with it. There is deliberately no list endpoint:
the profiles a Guardian looks after are the `managed` entries of `accountAccess.accounts` on GET /api/auth/me,
because a Guardian's relationship to a profile IS a MANAGE grant. Re-read the account payload after any change
here; a client that refreshed only its own panel would leave the new record out of the switcher and the banner
until the next boot."
description: "A record somebody looks after, as its creation, its read and its edit all answer with it. There is
deliberately no list endpoint: the profiles a Guardian looks after are the `managed` entries of
`accountAccess.accounts` on GET /api/auth/me, because a Guardian's relationship to a profile IS a MANAGE grant.
Re-read the account payload after any change here; a client that refreshed only its own panel would leave the
new record out of the switcher and the banner until the next boot."
DeletedManagedProfileEnvelope:
type: object
properties: