Skip to main content

5. Build the five-domain wellness model

What we are building​

A dashboard model that keeps five areas visible while preserving where every value came from. A reflection remains a reflection; an imported sample remains a measurement.

What you should already have​

The implementation​

Use a small presentation model to drive the five cards. It describes source and meaning; it does not create a second persistence format.

export type WellnessDomain =
| "sleep"
| "movement"
| "nutrition"
| "stress"
| "recovery";

type DomainCard = {
id: WellnessDomain;
titleKey: string;
sources: Array<"questionnaire-response" | "observation">;
sourceLabelKey: string;
summaryKey: string;
};

export const wellnessDomains: DomainCard[] = [
{
id: "sleep",
titleKey: "domains.sleep.title",
sources: ["questionnaire-response", "observation"],
sourceLabelKey: "sources.selfReported",
summaryKey: "domains.sleep.reflection",
},
{
id: "movement",
titleKey: "domains.movement.title",
sources: ["questionnaire-response", "observation"],
sourceLabelKey: "sources.selfReported",
summaryKey: "domains.movement.reflection",
},
{
id: "nutrition",
titleKey: "domains.nutrition.title",
sources: ["questionnaire-response"],
sourceLabelKey: "sources.selfReported",
summaryKey: "domains.nutrition.reflection",
},
{
id: "stress",
titleKey: "domains.stress.title",
sources: ["questionnaire-response"],
sourceLabelKey: "sources.selfReported",
summaryKey: "domains.stress.reflection",
},
{
id: "recovery",
titleKey: "domains.recovery.title",
sources: ["questionnaire-response"],
sourceLabelKey: "sources.selfReported",
summaryKey: "domains.recovery.reflection",
},
];

Keep measured context in its own view model. Sleep sessions and step totals are imported in step 4; resting heart rate is another optional measurement. They complement the five domains but do not become additional reflections or a recovery score.

In each card, show the source label near the value:

  • Self-reported for a member's QuestionnaireResponse.
  • Imported from Apple Health or Imported from Health Connect for a supported Observation.
  • No data yet when there is no value. Do not fill the gap with a fabricated zero.

Important Ovok decisions​

  • Nutrition, stress, perceived sleep quality, movement intentions and perceived recovery are captured in FHIR QuestionnaireResponses, not as passively measured Observations.
  • Imported sleep-session intervals, local-day step totals and resting heart rate are separate FHIR Observations with their source coding and time semantics intact.
  • The SDK uses source coding systems for sleep and step records; do not describe them as LOINC-coded or treat an elapsed sleep interval as time asleep.
  • A QuestionnaireResponse is the historical answer record; changing a reflection creates a later response rather than rewriting how the person previously felt.
  • The model does not calculate a composite or clinical score.
  • Keep app-owned labels in Ovok CMS translation groups. The stable keys above are examples of app keys, not server FHIR fields.

Expected result​

Your dashboard has five consistent cards and a separate measured-data area. Each visible value makes clear whether it was reported by the member or imported.

Common errors and troubleshooting​

SymptomCheck
A reflection is stored as an ObservationKeep subjective answers in QuestionnaireResponse resources.
A missing metric displays as zeroUse an explicit empty state; absence is not a measured zero.
The UI says resting heart rate indicates recoveryRemove the inference. Display the measurement without a readiness label.
The cards repeat raw FHIR JSONMap the response to a presentation model while retaining the original resource for audit and navigation.

Previous / next​