Programs & Workout Builder
The core content creation system for trainers. Create structured workout programs with exercises, sets, reps, and sections. Publish to the marketplace, assign to clients, and manage program lifecycle.
Overview
The Programs feature is the revenue-driving core of My Trainer Connect. Trainers create workout programs from scratch or templates, building a structured hierarchy of workouts containing sections, exercises, and prescribed sets. Each program can be published to the marketplace with pricing, difficulty level, and category metadata for discovery.
The Program Builder provides a rich editing experience with a tree-structured data model: Programs contain Workouts, which contain Workout Sections (regular, circuit, AMRAP, timed), which contain Section Exercises (supporting supersets, circuits, complexes, EMOM, tabata groupings), which contain Prescribed Sets with detailed parameters (reps, weight, RPE, RIR, tempo, rest, distance).
The system uses concurrent-safe optimistic updates via a shared mutation key pattern, allowing rapid edits without race conditions. Programs support three visibility levels (private, clients-only, marketplace) and three statuses (draft, published, archived). Trainers can duplicate programs as templates and search from a database of 1,500+ exercises with filtering by category, difficulty, equipment, and muscle groups.
User Stories
Trainer Stories
As a trainer, I want to create a new program with a title, description, and category so that I can start building workout content.
As a trainer, I want to add workouts with exercises, sets, reps, and rest periods so that clients have a structured plan to follow.
As a trainer, I want to group exercises into supersets, circuits, and EMOM blocks so that I can create varied training modalities.
As a trainer, I want to set pricing and publish my program to the marketplace so that anyone can purchase it.
As a trainer, I want to duplicate an existing program as a template so that I can quickly create variations.
As a trainer, I want to search from a large exercise database with filtering so that I can find the right movements quickly.
As a trainer, I want to assign programs to specific clients so that they can follow my prescribed training plan.
As a trainer, I want to archive old programs without deleting them so that I can keep my library organized.
Client Stories
As a client, I want to view assigned programs with a clear workout breakdown so that I know exactly what to do each day.
As a client, I want to browse the program marketplace and purchase programs so that I can follow expert-designed training plans.
Data Model
| Table | Key Columns | Description |
|---|---|---|
| programs | id, trainer_id, title, description, category, difficulty, status, visibility, price, discount_price, currency, session_duration_min, workout_count, equipment_required[], goals[], tags[], cover_image_url, preview_video_url, is_template, is_featured, is_platform_provided, rating_avg, review_count, enrollment_count, target_audience | Root program entity. Status: draft/published/archived. Visibility: private/clients_only/marketplace. |
| program_workouts | id, program_id, name, workout_type, sort_order, description, focus_area, estimated_duration_min, warmup_notes, cooldown_notes, notes | Individual workouts within a program. Types: regular, circuit, interval. Ordered by sort_order. |
| workout_sections | id, workout_id, name, section_type, sort_order, rounds, time_cap_seconds, rest_between_rounds_seconds, notes | Sections within a workout. Types: regular, circuit, amrap, timed. |
| section_exercises | id, section_id, exercise_id, sort_order, group_type, group_id, group_order, rest_seconds, notes | Exercise entries within sections. Group types: none, superset, circuit, complex, emom, tabata. |
| prescribed_sets | id, section_exercise_id, set_type, sort_order, reps, reps_min, reps_max, weight, weight_unit, rpe_target, rir_target, percentage_1rm, tempo, duration_seconds, distance, distance_unit, rest_seconds, notes | Set prescriptions. Types: normal, warm_up, backoff, drop_set, failure, rest_pause. Units: kg/lbs, meters/km/feet/miles. |
| exercises | id, name, category, difficulty, equipment, primary_muscles[], secondary_muscles[], thumbnail_url, tracking_type | Master exercise database (1,500+ entries). 13 categories, 3 difficulty levels. Full-text search supported. |
| program_purchases | id, program_id, user_id, price_paid, currency, purchased_at | Enrollment records for marketplace purchases. |
| program_reviews | id, program_id, user_id, rating, review_text, created_at | 5-star ratings and text reviews from enrolled users. |
Builder Tree Structure
Program
└ Workout (name, type: regular | circuit | interval)
└ Section (name, type: regular | circuit | amrap | timed, rounds, time_cap)
└ Exercise (exercise_id, group_type: none | superset | circuit | complex | emom | tabata)
└ Set (type: normal | warm_up | backoff | drop_set | failure | rest_pause)
reps, weight, rpe, rir, tempo, duration, distance, rest
Program Categories
Exercise Categories
Screens & Routes
| Route | File | Description |
|---|---|---|
| /programs | src/routes/_authed/_onboarded/programs/index.tsx | Program list page — grid view of trainer's programs with status badges, search, and filters |
| /programs/new | src/routes/_authed/_onboarded/programs/new.tsx | Create new program form — title, description, category, difficulty, pricing |
| /programs/$programId | src/routes/_authed/_onboarded/programs/$programId/ | Program detail/builder page — full workout tree editor with exercises and sets |
Acceptance Criteria
API Surface
Server Functions
| Function | Method | Input Schema | Source |
|---|---|---|---|
| getMyPrograms | GET | none | src/api/programs/functions.ts |
| getProgram | GET | { program_id } | src/api/programs/functions.ts |
| createProgram | POST | createProgramSchema | src/api/programs/functions.ts |
| updateProgram | POST | updateProgramSchema | src/api/programs/functions.ts |
| updateProgramStatus | POST | updateProgramStatusSchema | src/api/programs/functions.ts |
| deleteProgram | POST | deleteProgramSchema | src/api/programs/functions.ts |
| getProgramBuilder | GET | { program_id } | src/api/program-builder/functions.ts |
| syncBuilderTree | POST | syncBuilderTreeSchema | src/api/program-builder/functions.ts |
| duplicateProgram | POST | duplicateProgramSchema | src/api/program-builder/functions.ts |
| searchExercises | GET | searchExercisesSchema | src/api/exercises/functions.ts |
| listExercises | GET | listExercisesSchema | src/api/exercises/functions.ts |
React Query Hooks
| Hook | Type | Source |
|---|---|---|
| myProgramsQueryOptions | queryOptions | src/api/programs/hooks.ts |
| programQueryOptions(id) | queryOptions | src/api/programs/hooks.ts |
| useCreateProgram | useMutation | src/api/programs/hooks.ts |
| useUpdateProgram | useMutation | src/api/programs/hooks.ts |
| useUpdateProgramStatus | useMutation | src/api/programs/hooks.ts |
| useDeleteProgram | useMutation | src/api/programs/hooks.ts |
| useBuilderMutation(id) | shared helper | src/api/program-builder/hooks.ts |
Query Keys
programKeys.all → ['programs']
programKeys.myPrograms() → ['programs', 'my-programs']
programKeys.detail(id) → ['programs', 'detail', id]
programBuilderKeys.builder(id) → ['program-builder', 'builder', id]
programBuilderKeys.autoSave(id) → ['program-builder', 'auto-save', id]
Current Status
- Program CRUD (create, read, update, delete)
- Program list page with grid view
- Full workout builder with tree structure
- Exercise search and filtering
- Set prescription editor (all set types)
- Section types (regular, circuit, AMRAP, timed)
- Exercise grouping (supersets, circuits, etc.)
- Auto-save with sync builder tree
- Concurrent mutation safety
- Program duplication
- Status management (draft/published/archived)
- Visibility controls
- Optimistic updates on all mutations
- Program assignment to clients
- Cover image upload
- Preview video upload
- Client view of assigned programs
- Marketplace purchase flow
- Program reviews & ratings
- Program templates library
- Workout logging (client-side)