mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
docs(openapi): publish the illness episode + day-log CRUD contract
Register /api/illness/episodes (list + create), the {id} resource
(read + edit + soft-delete), the {id}/resolve verb, and the
{id}/day-logs upsert in the OpenAPI route table, and add the Illness
tag. Request bodies + queries reuse the runtime Zod schemas from
validations/illness so the wire contract stays single-source; the
response shapes mirror the server-authoritative episode + day-log DTOs.
Regenerated docs/api/openapi.yaml; openapi:check is in sync.
This commit is contained in:
1 parent
0338f18b50
commit
c1d804809d
4 files changed
+954
No files matched your search
@@ -41,6 +41,7 @@ tags:
|
||||
- name: Cycle
|
||||
- name: MeasurementReminders
|
||||
- name: Labs
|
||||
- name: Illness
|
||||
- name: Admin
|
||||
- name: Meta
|
||||
paths:
|
||||
@@ -6167,6 +6168,373 @@ paths:
|
||||
"404": *a9
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
/api/illness/episodes:
|
||||
get:
|
||||
tags:
|
||||
- Illness
|
||||
summary: List illness episodes (v1.18.1)
|
||||
description: Returns the caller's live (non-deleted) illness/condition episodes, newest-first by onset.
|
||||
`includeResolved=false` hides episodes that already carry a `resolvedAt`. Born-gated.
|
||||
parameters:
|
||||
- in: query
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
- in: query
|
||||
name: includeResolved
|
||||
schema:
|
||||
anyOf:
|
||||
- type: string
|
||||
const: "true"
|
||||
- type: string
|
||||
const: "false"
|
||||
responses:
|
||||
"200":
|
||||
description: The caller's illness episodes.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ListIllnessEpisodesEnvelope"
|
||||
"401": *a1
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
post:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Open an illness episode (v1.18.1)
|
||||
description: Creates one episode for the caller. `onsetAt` defaults to 'now' when omitted; the optional note is
|
||||
AES-256-GCM encrypted before write. A `parentConditionId` must reference an owned, live episode. Audits as
|
||||
`illness.episode.create`. Born-gated.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 120
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- INFECTION
|
||||
- ALLERGY
|
||||
- INJURY
|
||||
- MENTAL_HEALTH
|
||||
- AUTOIMMUNE
|
||||
- CHRONIC
|
||||
- OTHER
|
||||
lifecycle:
|
||||
default: ACUTE
|
||||
type: string
|
||||
enum:
|
||||
- ACUTE
|
||||
- CHRONIC_ONGOING
|
||||
- RECURRING
|
||||
- FLARE
|
||||
onsetAt:
|
||||
type: string
|
||||
format: date-time
|
||||
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])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
resolvedAt:
|
||||
anyOf:
|
||||
- type: string
|
||||
format: date-time
|
||||
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])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
- type: "null"
|
||||
parentConditionId:
|
||||
anyOf:
|
||||
- type: string
|
||||
minLength: 1
|
||||
maxLength: 40
|
||||
- type: "null"
|
||||
note:
|
||||
anyOf:
|
||||
- type: string
|
||||
maxLength: 2000
|
||||
- type: "null"
|
||||
required:
|
||||
- label
|
||||
- type
|
||||
responses:
|
||||
"201":
|
||||
description: Episode created.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateIllnessEpisodeEnvelope"
|
||||
"401": *a1
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
/api/illness/episodes/{id}:
|
||||
get:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Read a single illness episode (v1.18.1)
|
||||
description: Returns the episode including its decrypted `note`. Owner-scoped; a cross-user or tombstoned id 404s. Born-gated.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: The episode.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GetIllnessEpisodeEnvelope"
|
||||
"401": *a1
|
||||
"404": &a11
|
||||
description: Illness episode not found (or owned by another user).
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
patch:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Edit an illness episode (v1.18.1)
|
||||
description: Partial edit; omitted fields are left untouched. A re-parent must point at an owned, live episode (and
|
||||
never the episode itself). Audits as `illness.episode.update`. Owner-scoped + born-gated.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 120
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- INFECTION
|
||||
- ALLERGY
|
||||
- INJURY
|
||||
- MENTAL_HEALTH
|
||||
- AUTOIMMUNE
|
||||
- CHRONIC
|
||||
- OTHER
|
||||
lifecycle:
|
||||
type: string
|
||||
enum:
|
||||
- ACUTE
|
||||
- CHRONIC_ONGOING
|
||||
- RECURRING
|
||||
- FLARE
|
||||
onsetAt:
|
||||
type: string
|
||||
format: date-time
|
||||
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])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
resolvedAt:
|
||||
anyOf:
|
||||
- type: string
|
||||
format: date-time
|
||||
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])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
- type: "null"
|
||||
parentConditionId:
|
||||
anyOf:
|
||||
- type: string
|
||||
minLength: 1
|
||||
maxLength: 40
|
||||
- type: "null"
|
||||
note:
|
||||
anyOf:
|
||||
- type: string
|
||||
maxLength: 2000
|
||||
- type: "null"
|
||||
additionalProperties: false
|
||||
responses:
|
||||
"200":
|
||||
description: Episode updated.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UpdateIllnessEpisodeEnvelope"
|
||||
"401": *a1
|
||||
"404": *a11
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
delete:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Soft-delete an illness episode (v1.18.1)
|
||||
description: Stamps `deletedAt` (tombstone). Idempotent — a re-delete is a no-op. Returns 204 No Content. Audits as
|
||||
`illness.episode.delete`. Owner-scoped + born-gated.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
"204":
|
||||
description: Soft-deleted (no body).
|
||||
"401": *a1
|
||||
"404": *a11
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
/api/illness/episodes/{id}/resolve:
|
||||
patch:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Mark an illness episode recovered (v1.18.1)
|
||||
description: Stamps `resolvedAt` (defaults to 'now' when the body omits it). A CHRONIC_ONGOING episode has no recovery
|
||||
date and 422s with `errorCode:"illness.episode.chronic-no-resolve"`. Audits as `illness.episode.resolve`.
|
||||
Owner-scoped + born-gated.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
required: false
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
resolvedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
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])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
responses:
|
||||
"200":
|
||||
description: Episode resolved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ResolveIllnessEpisodeEnvelope"
|
||||
"401": *a1
|
||||
"404": *a11
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
/api/illness/episodes/{id}/day-logs:
|
||||
get:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Read one day-log for an episode (v1.18.1)
|
||||
description: Returns the day-log for the episode + `date`, or `null` when nothing is logged that day (lets the log-day
|
||||
sheet pre-fill). The parent episode must be owned + live. Born-gated.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: date
|
||||
schema:
|
||||
type: string
|
||||
pattern: ^\d{4}-\d{2}-\d{2}$
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: The day-log, or null.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GetIllnessDayLogEnvelope"
|
||||
"401": *a1
|
||||
"404": *a11
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
post:
|
||||
tags:
|
||||
- Illness
|
||||
summary: Upsert an episode day-log (v1.18.1)
|
||||
description: "Upserts the day's symptom / functional-impact / fever timeline row on `(episodeId, date)`: 201 on insert,
|
||||
200 on update. The parent episode must be owned + live; the optional note is encrypted at rest. Audits as
|
||||
`illness.day-log.upsert`. Born-gated."
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
date:
|
||||
type: string
|
||||
pattern: ^\d{4}-\d{2}-\d{2}$
|
||||
functionalImpact:
|
||||
anyOf:
|
||||
- type: integer
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
- type: "null"
|
||||
feverC:
|
||||
anyOf:
|
||||
- type: number
|
||||
minimum: 30
|
||||
maximum: 45
|
||||
- type: "null"
|
||||
symptoms:
|
||||
maxItems: 40
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 80
|
||||
severity:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
required:
|
||||
- key
|
||||
note:
|
||||
anyOf:
|
||||
- type: string
|
||||
maxLength: 2000
|
||||
- type: "null"
|
||||
loggedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
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])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
required:
|
||||
- date
|
||||
responses:
|
||||
"200":
|
||||
description: Existing day-log updated.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UpsertIllnessDayLogUpdatedEnvelope"
|
||||
"201":
|
||||
description: New day-log created.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UpsertIllnessDayLogCreatedEnvelope"
|
||||
"401": *a1
|
||||
"404": *a11
|
||||
"422": *a3
|
||||
"429": *a4
|
||||
components:
|
||||
schemas:
|
||||
PasskeyLoginVerifyRequest:
|
||||
@@ -17822,6 +18190,260 @@ components:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
ListIllnessEpisodesEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/IllnessEpisode"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
IllnessEpisode:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
label:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- INFECTION
|
||||
- ALLERGY
|
||||
- INJURY
|
||||
- MENTAL_HEALTH
|
||||
- AUTOIMMUNE
|
||||
- CHRONIC
|
||||
- OTHER
|
||||
lifecycle:
|
||||
type: string
|
||||
enum:
|
||||
- ACUTE
|
||||
- CHRONIC_ONGOING
|
||||
- RECURRING
|
||||
- FLARE
|
||||
onsetAt:
|
||||
type: string
|
||||
resolvedAt:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: "null"
|
||||
parentConditionId:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: "null"
|
||||
note:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: "null"
|
||||
createdAt:
|
||||
type: string
|
||||
updatedAt:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- label
|
||||
- type
|
||||
- lifecycle
|
||||
- onsetAt
|
||||
- resolvedAt
|
||||
- parentConditionId
|
||||
- note
|
||||
- createdAt
|
||||
- updatedAt
|
||||
additionalProperties: false
|
||||
description: A stored illness/condition episode. `note` is the decrypted free-text (or null on a key-rotation gap —
|
||||
fail-soft, never 500). `resolvedAt` is null while the episode is open. `parentConditionId` links a
|
||||
FLARE/RECURRING bout to its parent condition.
|
||||
CreateIllnessEpisodeEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/IllnessEpisode"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
GetIllnessEpisodeEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/IllnessEpisode"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
UpdateIllnessEpisodeEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/IllnessEpisode"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
ResolveIllnessEpisodeEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/IllnessEpisode"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
GetIllnessDayLogEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
anyOf:
|
||||
- $ref: "#/components/schemas/IllnessDayLog"
|
||||
- type: "null"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
IllnessDayLog:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
episodeId:
|
||||
type: string
|
||||
date:
|
||||
type: string
|
||||
functionalImpact:
|
||||
anyOf:
|
||||
- type: integer
|
||||
minimum: -9007199254740991
|
||||
maximum: 9007199254740991
|
||||
- type: "null"
|
||||
feverC:
|
||||
anyOf:
|
||||
- type: number
|
||||
- type: "null"
|
||||
symptoms:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/IllnessSymptom"
|
||||
note:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: "null"
|
||||
updatedAt:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- episodeId
|
||||
- date
|
||||
- functionalImpact
|
||||
- feverC
|
||||
- symptoms
|
||||
- note
|
||||
- updatedAt
|
||||
additionalProperties: false
|
||||
description: A stored day-log for an episode. `date` is the `YYYY-MM-DD` it covers. `functionalImpact` (0–3) and
|
||||
`feverC` are plaintext; `symptoms` flattens the link rows; `note` is the decrypted free-text (or null).
|
||||
IllnessSymptom:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
severity:
|
||||
anyOf:
|
||||
- type: integer
|
||||
minimum: -9007199254740991
|
||||
maximum: 9007199254740991
|
||||
- type: "null"
|
||||
required:
|
||||
- key
|
||||
- severity
|
||||
additionalProperties: false
|
||||
description: "A symptom link on a day-log: the catalog `key` plus an optional 0–3 severity (`null` = a plain presence link)."
|
||||
UpsertIllnessDayLogUpdatedEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/IllnessDayLog"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
UpsertIllnessDayLogCreatedEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/IllnessDayLog"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
MedicationScheduleOutput:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in new issue
Block a user