# Phase 4: Workout Modification **Started:** 2026-03-01 **Goal:** Let users customize program workouts by swapping or adding exercises, creating personal forks ## Problem Statement Users want flexibility within their program structure. Currently: - Can't swap an exercise (e.g., replace bench press with dumbbell press due to equipment availability) - Can't add exercises to a program workout (e.g., add face pulls to Push day) - Any modification would require building a completely custom workout ## Solution: Workout Forking When user modifies a program workout, we: 1. Copy the program workout to `custom_workouts` table 2. Store modifications in `custom_workout_exercises` table 3. Save workout logs with `source_type = 'custom'` to track lineage 4. Original program remains unchanged for future sessions ## Phase Plans ### 04-01: Database Schema Migration - Create `custom_workouts` table - Create `custom_workout_exercises` table - Add `source_type` enum column to `workout_logs` - Migration script with rollback ### 04-02: Backend API for Custom Workouts - POST /api/custom-workouts (create from program workout) - PUT /api/custom-workouts/:id (update exercises) - GET /api/custom-workouts/:id (fetch with exercises) - GET /api/custom-workouts (list user's custom workouts) - Update workout log save to handle source_type ### 04-03: Frontend - Workout Edit Mode - "Edit Workout" button on WorkoutSelectPage - Exercise picker modal/component - Swap exercise UI flow - Add exercise UI flow - Fork confirmation dialog ## Success Criteria - [ ] User can replace any exercise in a program workout - [ ] User can add exercises to a program workout - [ ] Modified workout saves as custom_workout (original program unchanged) - [ ] Subsequent workout sessions use the forked custom workout - [ ] User can see which workouts are custom vs program originals ## Database Schema ```sql -- custom_workouts: Stores the forked workout header custom_workouts ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, description TEXT, original_program_day_id INTEGER REFERENCES program_days(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- custom_workout_exercises: Stores exercises in custom workout custom_workout_exercises ( id SERIAL PRIMARY KEY, custom_workout_id INTEGER REFERENCES custom_workouts(id) ON DELETE CASCADE, exercise_id INTEGER REFERENCES exercises(id) ON DELETE CASCADE, set_order INTEGER NOT NULL, sets INTEGER DEFAULT 3, reps INTEGER DEFAULT 10, weight_preset DECIMAL(5,2), UNIQUE(custom_workout_id, set_order) ); -- workout_logs.source_type: Tracks where log came from ALTER TABLE workout_logs ADD COLUMN source_type VARCHAR(20) DEFAULT 'program'; -- Values: 'program', 'custom' ``` ## Out of Scope - Building completely custom workouts from scratch (v2/CUS-01) - Reusable custom workout templates (v2/CUS-02) - Complex program modifications (reordering days, changing structure)