Skip to content

Exercise Library Feature

Video library of exercises with taxonomy, instructions, and equipment requirements.

What this enables

Video exercise catalog: Browse hundreds of PT exercises by body region (shoulder, knee, lumbar spine) with video demos and step-by-step instructions.

Shared vs. custom: Use platform exercises ("Bird Dog", "Wall Slide") or clone and customize them for your clinic protocols.

Assign to treatment plans: Build telerehab programs from library exercises—"Day 1: 3x Shoulder External Rotation, 2x Wall Slide".

Track patient adherence: See which exercises patients complete, how many reps, if they're struggling.

Clinical taxonomy: Organize by category (stretching, strengthening, balance), body region, equipment needed, and clinical contraindications.

How it works

  1. Browse library: Admin searches for "shoulder" → sees 50+ shoulder exercises
  2. Create treatment plan: Builds 8-week program by adding library exercises
  3. Assign to patient: Patient gets treatment plan → telerehab app shows video demos
  4. Patient does exercises: Logs sets/reps → system tracks adherence
  5. Custom exercises (optional): Clone "Wall Slide" → customize instructions for your clinic's technique
  6. Analytics: See which exercises patients struggle with, which get best results

Technical Reference

Overview

The exercise library is a global + organization-scoped video exercise database for telerehabilitation. Organizations browse, search, and assign exercises to treatment plans. Exercises contain a video demonstration, text/image instructions, and full clinical taxonomy metadata.

Core Concept

Exercise Library = What exercises exist (content domain)
Treatment Plans  = How exercises are prescribed (clinical domain)  → See treatment-plans/
Telemetry        = How exercises are tracked (analytics domain)    → See integrations/

An exercise defines:

  • What it is (name, description, difficulty, taxonomy)
  • How to perform it (video + ordered instruction steps)
  • What's needed (equipment, contraindications)

An exercise does NOT define:

  • Sets, reps, or duration (that's configured per-exercise in treatment plan sessions)
  • Who should do it (that's on treatment plans → patient enrollment)
  • Tracking data (that's in patient_exercise_logs and Telemetry)

Dual-Scope Model: Global + Organization

┌─────────────────────────────────────────┐
│         GLOBAL LIBRARY                  │
│  (organization_id IS NULL)              │
│  Platform-curated by superadmins        │
├─────────────────────────────────────────┤
│  exercises                              │
│  ├── Shoulder External Rotation         │
│  ├── Wall Slide                         │
│  ├── Bird Dog                           │
│  └── Clamshell                          │
└─────────────────────────────────────────┘
          ↓ visible to all orgs
┌─────────────────────────────────────────┐
│         ORG LIBRARY                     │
│  (organization_id = org.id)             │
│  Created by org admins                  │
├─────────────────────────────────────────┤
│  exercises                              │
│  ├── Custom Knee Protocol Step 1        │
│  ├── Post-ACL Warm-up (cloned)         │
│  └── Balance Board Series               │
└─────────────────────────────────────────┘

Visibility rules:

  • All authenticated users see global exercises (published)
  • Org staff see global + their org's exercises
  • Patients see published exercises only (through their treatment plans)
  • Only superadmins can create/modify global exercises
  • Org admins can create/modify their org's exercises
  • Org admins can clone global exercises into their org library for customization

Key Tables

TablePurpose
exercisesMain entity — video, metadata, taxonomy. Global (org_id NULL) or org-scoped.
exercise_categoriesTaxonomy categories (stretching, strengthening, balance). Hierarchical via parent_id.
exercise_body_regionsBody part tags (shoulder, knee, lumbar spine). Grouped by body_area.
exercise_equipmentEquipment catalog (resistance band, yoga mat, dumbbell).
exercise_tagsPolymorphic M:M junction — links exercises to categories, body regions, and equipment.
exercise_instructionsOrdered text/image instruction steps per exercise.
exercise_contraindicationsClinical warnings/restrictions per exercise.

Taxonomy

Exercises are tagged with three independent taxonomies. Each taxonomy is also dual-scoped (global + org):

Categories (Hierarchical)

Stretching
├── Static Stretching
├── Dynamic Stretching
└── PNF Stretching
Strengthening
├── Isometric
├── Isotonic
└── Plyometric
Balance & Proprioception
Mobility
Breathing & Relaxation

Body Regions (Grouped by Area)

Upper Body
├── Shoulder
├── Elbow
├── Wrist / Hand
└── Cervical Spine

Core
├── Lumbar Spine
├── Thoracic Spine
└── Abdominals

Lower Body
├── Hip
├── Knee
├── Ankle / Foot
└── Glutes

Full Body

Equipment

No Equipment (bodyweight)
Resistance Band
Yoga Mat
Dumbbell
Swiss Ball
Foam Roller
Balance Board
TheraBand

Filtering

The GET /v1/exercises endpoint supports multi-taxonomy filtering:

GET /v1/exercises?category_id=5&body_region_id=3&difficulty=beginner&equipment_id=2&status=published&q=plank&sort=-created_at

Video Storage

Exercises store video via a CDN-agnostic design:

sql
video_url               TEXT        -- CDN URL (Bunny Stream, S3, etc.)
video_provider          TEXT        -- 'bunny_stream' | 's3'
video_thumbnail_url     TEXT        -- poster frame
video_duration_seconds  INT         -- cached duration

Why CDN-agnostic: The platform supports Bunny Stream (EU-first CDN with built-in HLS transcoding) or S3 + CloudFront. The video_provider field allows the upload/playback layer to adapt without schema changes.

See video-upload.md for the full upload flow and adaptive streaming design.

Instructions Model

Each exercise has ordered instruction steps with types:

Exercise: Shoulder External Rotation
├── [preparation] "Lie on your side with a towel roll under your arm"
├── [step] "Rotate your forearm upward, keeping elbow at 90°"
├── [form_cue] "Keep your elbow pinned to your side"
├── [breathing] "Exhale as you rotate up, inhale on return"
└── [safety] "Stop if you feel sharp pain in the shoulder joint"

Instruction types: preparation, step, form_cue, breathing, safety

Each instruction can have an optional image (S3 upload) for visual demonstration.

Cloning

Org admins can clone exercises from the global library (or from their own library) to create customized variants:

http
POST /v1/exercises/{id}/clone

What gets cloned:

  • All exercise fields (name, description, taxonomy, difficulty)
  • All instructions (with images)
  • All contraindications
  • All tags

What changes:

  • New UUID
  • organization_id set to current org
  • cloned_from_id set to source exercise ID
  • status reset to draft

The clone is fully independent — editing the source does not affect the clone.

Soft Delete

Exercises use soft delete (deleted_at timestamp) because they may be referenced by active treatment plans. A soft-deleted exercise:

  • Is hidden from library search/browse
  • Remains visible in existing treatment plans (with a "discontinued" indicator)
  • Cannot be added to new plans
  • The exercises.id FK in treatment_plan_session_exercises uses ON DELETE RESTRICT as a safety net

Exercise Status

draft → published → archived
  • draft: Only visible to admins/superadmins. Work in progress.
  • published: Visible to all authorized users. Can be used in treatment plans.
  • archived: Hidden from new plan creation but remains in existing plans.

Integration Points

With Treatment Plans Feature

  • Exercises are added to treatment_plan_session_exercises with per-plan configuration (sets, reps, duration, rest)
  • Exercise data (video, instructions) is always "live" — updates to an exercise are immediately visible in all plans
  • Plan version snapshots capture exercise IDs (not exercise content), so the current exercise state is always shown

With Telemetry Service

  • Video performance: When a patient watches an exercise video, the frontend sends the full media event lifecycle (session_start, heartbeat, buffering_start/end, milestone, session_end) to POST /v1/media/events. Stored in ClickHouse media_sessions. See ../../telemetry/media-events.md for the event specification. Consent: Level 2+.
  • Pose tracking: If enabled, MediaPipe landmark frames are batched and sent to POST /v1/pose/frames (separate endpoint). Stored in ClickHouse pose_tracking_frames. Includes accuracy scores, rep counting, ROM degrees, and form feedback. Consent: Level 2+ (analytics) + biometric consent from patient.
  • Error reporting: Video playback errors reported via POST /v1/errors/report for support troubleshooting. Consent: Level 1+.

With S3/CDN

  • Exercise videos: {org_id}/exercises/{exercise_id}/video/{filename} (org) or global/exercises/{exercise_id}/video/{filename} (global)
  • Instruction images: {org_id}/exercises/{exercise_id}/instructions/{sort_order}/{filename}
  • Thumbnails: {org_id}/exercises/{exercise_id}/thumbnail/{filename}

API Endpoints

See api.md for full API documentation.

Key endpoints:

  • GET /v1/exercises — Browse/search with taxonomy filters
  • POST /v1/exercises — Create exercise (admin: org, superadmin: global)
  • GET /v1/exercises/{id} — Full details with instructions, tags, contraindications
  • POST /v1/exercises/{id}/clone — Clone to org library
  • POST /v1/exercises/{id}/video — Upload video

Design Principles

  1. Dual-scope by design — Global library is platform-curated, org libraries are private. Both use the same tables with organization_id IS NULL vs IS NOT NULL.
  2. CDN-agnostic — Video storage abstracted behind video_url + video_provider. No vendor lock-in.
  3. Exercises are content, not configuration — No sets/reps/duration on exercises. That's treatment plan config.
  4. Mutable, not versioned — Exercises update in-place. If you need variants, clone them.
  5. Soft delete for safety — Referenced exercises can't be hard-deleted (RESTRICT FK + soft delete).
  6. Multi-tenant by design — All tables have org-scoped RLS. Global exercises get a special organization_id IS NULL SELECT policy.