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
- Browse library: Admin searches for "shoulder" → sees 50+ shoulder exercises
- Create treatment plan: Builds 8-week program by adding library exercises
- Assign to patient: Patient gets treatment plan → telerehab app shows video demos
- Patient does exercises: Logs sets/reps → system tracks adherence
- Custom exercises (optional): Clone "Wall Slide" → customize instructions for your clinic's technique
- 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 (Layer 2 ingest pipeline) → See ../../telemetry/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 + the Layer 2 Telemetry ingest path)
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
| Table | Purpose |
|---|---|
exercises | Main entity — video, metadata, taxonomy. Global (org_id NULL) or org-scoped. |
exercise_categories | Taxonomy categories (stretching, strengthening, balance). Hierarchical via parent_id. |
exercise_body_regions | Body part tags (shoulder, knee, lumbar spine). Grouped by body_area. |
exercise_equipment | Equipment catalog (resistance band, yoga mat, dumbbell). |
exercise_tags | Polymorphic M:M junction — links exercises to categories, body regions, and equipment. |
exercise_instructions | Ordered text/image instruction steps per exercise. |
exercise_contraindications | Clinical warnings/restrictions per exercise — severity is 'warning' (proceed with caution) or 'contraindicated' (do not perform). |
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 & RelaxationBody 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 BodyEquipment
No Equipment (bodyweight)
Resistance Band
Yoga Mat
Dumbbell
Swiss Ball
Foam Roller
Balance Board
TheraBandFiltering
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_atVideo Storage
Section superseded by the compositional model
The "single video_url column per exercise" model below predates the platform's move to composed videos per prescription. Exercises no longer have one canonical video — they have a bundle of raw filming primitives in S3, from which the exercise-composer service renders one MP4 per (exercise, prescription, language) tuple. Bunny video IDs are cached in exercise_renders (landing with F9.1), not stored as a column on exercises.
For the current model, see composition.md and P56 Exercise Video Composition Pipeline.
Exercises store video via a CDN-agnostic design (historical model — see above):
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 durationWhy 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, manually written instruction steps. Whoever creates the exercise (the platform team for global exercises, or clinic staff for clinic exercises) writes each step by hand through the admin UI. Instructions are typed by role:
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. When cloning an exercise, all instructions (including images) are copied and can be freely edited.
Contraindications
Each exercise can have clinical contraindications — warnings tied to specific medical conditions. Stored in exercise_contraindications:
Exercise: Shoulder External Rotation
├── [warning] "Shoulder Impingement" — reduce range of motion, stop if sharp pain
└── [contraindicated] "Acute Rotator Cuff Tear" — do not perform until cleared by physicianSeverity levels:
warning— exercise can be performed with modifications or cautioncontraindicated— exercise should not be performed by patients with this condition
Who manages contraindications:
- Platform exercises — contraindications are pre-written and maintained by the RestartiX team. Clinics cannot edit them directly (clone the exercise first).
- Clinic exercises — the clinic's specialists and admins manage contraindications. When cloning from the platform library, all contraindications are copied and can then be freely edited, added, or removed.
Display, not enforcement: Contraindications are shown as clinical guidance when a specialist prescribes an exercise. The platform does not automatically block assignment based on contraindications — the prescribing specialist makes the clinical judgment.
Cloning
Org admins can clone exercises from the global library (or from their own library) to create customized variants:
POST /v1/exercises/{id}/cloneWhat gets cloned:
- All exercise fields (name, description, taxonomy, difficulty)
- All instructions (with images)
- All contraindications
- All tags
What changes:
- New UUID
organization_idset to current orgcloned_from_idset to source exercise IDstatusreset todraft
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.idFK intreatment_plan_session_exercisesusesON DELETE RESTRICTas 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_exerciseswith 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 API (Layer 2 feature)
- Video engagement: When a patient watches an exercise video, the Patient Portal sends the standard media event lifecycle (
session_start,heartbeat,buffering_start/end,milestone,session_end) toPOST /v1/media/eventson the Telemetry API. Server-side aggregation writesmedia_session_metrics+media_buffering_events(Postgres, monthly partitioned). See ../../telemetry/media-events.md for the event spec. Consent:analyticsper-purpose flag. - Pose tracking: If enabled, MediaPipe landmark frames are batched (binary float32 + gzip, 1-sec batches) and sent to
POST /v1/pose/frames(separate endpoint). Server-side aggregation at session_end producespose_session_metrics+pose_rep_metrics(Postgres) + a replay blob in S3 ats3://restartix-telemetry/{org_id}/{session_id}.bin.gz. Consent:biometricper-purpose flag. - Errors: off-the-shelf (Sentry-equivalent) when needed; not part of telemetry. The earlier
POST /v1/errors/reportendpoint has been removed.
With S3/CDN
- Exercise videos:
{org_id}/exercises/{exercise_id}/video/{filename}(org) orglobal/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 filtersPOST /v1/exercises— Create exercise (admin: org, superadmin: global)GET /v1/exercises/{id}— Full details with instructions, tags, contraindicationsPOST /v1/exercises/{id}/clone— Clone to org libraryPOST /v1/exercises/{id}/video— Upload video
Design Principles
- Dual-scope by design — Global library is platform-curated, org libraries are private. Both use the same tables with
organization_id IS NULLvsIS NOT NULL. - CDN-agnostic — Video storage abstracted behind
video_url+video_provider. No vendor lock-in. - Exercises are content, not configuration — No sets/reps/duration on exercises. That's treatment plan config.
- Mutable, not versioned — Exercises update in-place. If you need variants, clone them.
- Soft delete for safety — Referenced exercises can't be hard-deleted (RESTRICT FK + soft delete).
- Multi-tenant by design — All tables have org-scoped RLS. Global exercises get a special
organization_id IS NULLSELECT policy.