Skip to content

Coach item — session_card

Block type: session_card · Domain: coach-content

Coach items[] discriminator 'session_card'. Hosts a deep link into a Naluma session. Two authoring forms: LITERAL (authored title/activity_type/duration) and REFERENCE (no title — title/image/duration resolved at compose time from the content.sessions row named by session_slug). session_id (SessionKind.name) is required in both forms. The anyOf below mirrors the shipped app parser (lib/data/coach_json.dart _sessionCard), which drops a card carrying neither title nor session_slug; a hybrid card with both is valid (authored fields win, slug routes).

Rules

  • Requires at least one of: title / session_slug

Fields

Field Type Required Allowed values Notes
id string no minLength 1
title string no Headline rendered on the card. — minLength 1
activity_type string no ActivityType.name from the Dart enum. Unknown values render with a fallback. The schema does not enumerate the closed set here because additions land in Dart without a Postgres-side gate; the live-fixture test in naluma-app pins the legal set. TODO(coach-content-validate): if a typo regression ever appears, mirror the closed ActivityType.name enum into this schema (lockstep with naluma-app/lib/data/coach_json.dart) and add the matching pgTAP assertion. — minLength 1
duration string no Free-text duration label (e.g. '6 min'). — minLength 1
session_id enum yes audioGuided, breathing, chipExercise, valuesSort, experiment, insight, reframe, sentenceCompletion SessionKind.name value identifying the session template. The closed set mirrors the Postgres enum content.session_template_type (8 values). completion and notificationPrimer Dart enum values are NOT legal in session_card.session_id — they are internal navigation-only kinds.
session_slug string no Directus session slug. REQUIRED in the reference form (when title is omitted) — it is the resolution key the app uses to pull title/image/duration from content.sessions, and the routing key for GatedNavigator.openSessionBySlug. Optional in the literal form. The hook verifies the slug resolves to a content.sessions row (existence check). — minLength 1

Example

{
  "type": "session_card",
  "session_id": "breathing",
  "session_slug": "box-breathing"
}