Skip to main content

Program Catalog & User Enrollment with Intelligent Scheduling

OpenLift empowers users with structured, adaptable training through a robust Program Catalog and an intelligent enrollment and scheduling system. This document outlines how ProgramPlan entities are managed in the catalog and how users like Sam enroll in these plans, benefit from personalized snapshots, and receive dynamically generated workout schedules.

Overview

  • For Administrators/Content Creators: You build and manage a library of high-quality ProgramPlans. These plans define the structure, goals, workout templates, and progression for various training objectives.
  • For End-Users (like Sam): Sam discovers these ProgramPlans in the app. When he enrolls:
    1. A personal snapshot of the chosen plan is created just for him, ensuring his program remains consistent.
    2. He specifies his preferred training days.
    3. Our Intelligent Scheduling Service immediately populates his in-app calendar with workouts for the upcoming weeks, based on his plan snapshot and preferences.
    4. This schedule is dynamic, featuring smart catch-up for missed sessions and the flexibility for Sam to skip workouts if needed, with the system adjusting his progression accordingly.

Why This System Matters

For Administrators/Content Creators:

  • 📚 Curate Quality Content: Build a rich library of effective, structured training programs.
  • 🛠️ Flexible Program Design: Define comprehensive plan parameters, workout sequences, and weekly adjustments.
  • 👁️ Controlled Publishing: Manage the lifecycle of programs from draft to public release.

For End-Users (like Sam):

  • Access to Expert Plans: Benefit from well-designed programs.
  • 🎯 Goal-Oriented & Personalized: Find plans matching his goals, and the schedule adapts to his life.
  • 🚀 Clear, Structured Progression: Follow an intelligent path designed for improvement, with flexibility.
  • 🧘 Reduced Planning Overhead: Focus on training, not on manually figuring out what to do next.
  • 💪 Empowerment & Control: The ability to skip workouts gives Sam agency over his training load.

Core Concepts

  • ProgramPlan: The central entity in the catalog. Represents a complete, structured training plan.
    • Contains: Name, description, TrainingGoal, TrainingLevel, durationWeeks, daysPerWeek, default ProgramTrainingFocus, Visibility, isPublished.
    • Relations: Links to an ordered sequence of ProgramWorkoutTemplates via ProgramPlanTemplateLink. Can have ProgramPlanWeeklyModifiers.
  • ProgramWorkoutTemplate (PWT): A specific workout routine (e.g., "Day 1 - Upper Body Strength").
  • ProgramPlanTemplateLink: Join table linking ProgramPlan to ProgramWorkoutTemplate, defining the order of templates within the plan's cycle.
  • ProgramTrainingFocus: Defines default training parameters (reps, sets, RPE, rest) for a plan or template.
  • ProgramPlanWeeklyModifier: Allows for adjustments to training parameters for specific weeks within a master ProgramPlan (e.g., "Deload Week").
  • ProgramDefaultWeeklyModifier: Reusable templates for weekly modifiers.

Key Workflows & API Interactions

1. Catalog Plan Management (Admin Perspective)

Administrators use dedicated (typically admin-restricted) API endpoints (e.g., POST /api/catalog/, PUT /api/catalog/:id) to:

  • Create new ProgramPlans with all their details, linking ProgramWorkoutTemplates and defining ProgramPlanWeeklyModifiers.
  • View, update, publish, or soft-delete these catalog plans.
  • (Refer to specific admin documentation for detailed catalog CUD operations).

2. User Program Enrollment & Initial Scheduling (Sam's Experience)

  1. Sam Explores: Sam uses the app to view available (public, published) catalog plans.
    • API Interaction (Frontend): GET /api/plans (REST) or query { plans { ... } } (GraphQL) to list plans. May call GET /api/plans/:id or query { plan(id: ...) { ... } } for details.
  2. Sam Enrolls: Sam selects a plan (e.g., "Beginner Full Body Blast") and provides his preferred training days (e.g., Mon, Wed, Fri).
    • API Interaction (Frontend): POST /api/user-programs (REST) or mutation { enrollInProgram(...) } (GraphQL).
      • Body: { "programPlanId": "plan-bfb4w-001", "preferredTrainingDays": [1,3,5] }
    • Backend (UserProgramSchedulingService.enrollUser):
      • Validates the request.
      • Creates the ProgramUserInstance (PUI) for Sam.
      • Creates all associated snapshots (Plan, PWTs, PWEs, Weekly Modifiers) linked to this PUI.
      • Calls _generateScheduleForWindow to populate Sam's initial UserProgramScheduledWeekWorkout entries for the first few weeks.
    • Response: The newly created ProgramUserInstance DTO.
    • Frontend: Stores active PUI details, navigates Sam to his program dashboard.

3. Interacting with a Scheduled Workout (Sam's Experience)

  1. Sam Sees "Leg Day" scheduled for today and decides to start it. Let's say its scheduledWorkoutId is "sww-legday-123".
    • API Interaction (Frontend): POST /api/user-programs/scheduled-workouts/sww-legday-123/start (REST) or mutation { startScheduledWorkout(scheduledWorkoutId: "sww-legday-123") { ... } } (GraphQL).
    • Backend (UserProgramController.startWorkout calling UserProgramSchedulingService.startScheduledWorkoutSession):
      • Validates the SWW and PUI state.
      • Checks for an existing unfinished WorkoutHistoryEntry for this specific SWW.
      • If none, calls EffectiveWorkoutService.getEffectiveWorkout to get exercises and targets (based on PWE snapshots, PUI/coach overrides, weekly modifiers).
      • Creates a new "skeleton" WorkoutHistoryEntry (WHE) with endTime: null, linking it to the SWW.
      • Populates WorkoutCompletedExercise records with calculated targets and empty ExerciseSets.
      • Updates PUI.lastActivityDate.
    • Response: WorkoutHistorySkeletonResponse (the new or existing WHE skeleton).
    • Frontend: Opens the workout logging screen, pre-filled from the skeleton. Sam performs his workout, logging sets/reps/RPE into this WHE via other workout history endpoints (e.g., PUT /api/history/me/:wheId).

4. Program State Management (Pause, Resume, End, Change Preferred Days)

User-initiated actions via specific API endpoints:

  • PATCH /api/user-programs/:id/pause
  • PATCH /api/user-programs/:id/resume
  • PATCH /api/user-programs/:id/end
  • POST /api/user-programs/:id/preferred-training-days

These call corresponding methods in UserProgramSchedulingService which:

  • Update the PUI status, pauseDate, actualProgramEndDate, or preferredTrainingDays.
  • Update PUI.lastActivityDate.
  • For resume and updatePreferredTrainingDays (and pause/end), they clear relevant future SCHEDULED SWWs and call _generateScheduleForWindow to rebuild the schedule.
  • All return the updated ProgramUserInstance DTO.

Technical Deep Dive (For Developers)

Primary Data Models (User Program Context)

  • ProgramUserInstance (PUI): Core user enrollment record.
  • Snapshot Models: UserProgramPlanSnapshot, UserProgramPWTSnapshot, UserProgramPWESnapshot, UserProgramWeeklyModifierSnapshot. These form the immutable basis of the user's specific program.
  • UserProgramScheduledWeekWorkout (SWW): Dynamically generated schedule entries, linking a PUI to a UserProgramPWTSnapshot for a specific calendar day.
  • WorkoutHistoryEntry (WHE): Linked to an SWW via completedWorkoutHistoryEntryId (on SWW) if started from the schedule.
  • WorkoutCompletedExercise (WCE): Now contains targetSets, targetRepsMin, targetRepsMax, targetRestSeconds calculated by the EffectiveWorkoutService at the time of startWorkout.

Key Services & Responsibilities

  • UserProgramSchedulingService:
    • enrollUser: Handles PUI and all snapshot creation, initial schedule generation.
    • getOrGenerateScheduledWorkoutsForWeek: Main entry point for fetching weekly schedules; triggers generation if needed.
    • _generateScheduleForWindow (private): Core intelligent scheduling logic (catch-up, progression-aware population of SWWs).
    • markWorkoutAsCompleted: Updates SWW & PUI progression post-workout.
    • markWorkoutAsSkipped: Updates SWW & PUI progression for skipped workouts.
    • PUI state management methods (pauseProgramInstance, etc.).
  • EffectiveWorkoutService:
    • getEffectiveWorkout: Calculates session-specific exercises and targets by combining PWE snapshot data, PUEOs, PUAEs, weekly modifiers, and training focus overrides. Called by UserProgramController.startWorkout (or its underlying service).

Key API Endpoints (User-Facing Program Interaction)

Endpoints are primarily under /api/user-programs/.

MethodEndpointController FunctionDescription
POST/enrollInProgramEnrolls user in a plan, creates snapshots, initial schedule.
GET/activegetActiveProgramRetrieves user's active/paused PUI.
GET/active/schedule/week (with query params)getActiveScheduledWorkoutsForWeekGets (and generates if needed) weekly schedule.
PATCH/:id/pausepauseProgramPauses the PUI, clears future schedule.
PATCH/:id/resumeresumeProgramResumes PUI, regenerates schedule.
PATCH/:id/endendProgramEnds PUI by user, clears future schedule.
POST/:id/preferred-training-daysupdatePreferredTrainingDaysUpdates preferred days, clears and regenerates future schedule.
POST/scheduled-workouts/:scheduledWorkoutId/startstartWorkoutInitiates a workout session for a specific SWW, creates WHE skeleton with effective targets.
POST/scheduled-workouts/:scheduledWorkoutId/completecompleteScheduledWorkoutMarks SWW complete, updates PUI progression, regenerates schedule.
POST/scheduled-workouts/:scheduledWorkoutId/skipskipScheduledWorkoutMarks SWW skipped, updates PUI progression (pseudo-complete), regenerates schedule.

Important Technical Considerations

  • Database Transactions: Enrollment (enrollUser), workout completion (markWorkoutAsCompleted), skipping (markWorkoutAsSkipped), and other state changes that involve multiple DB writes are (or should be) wrapped in prisma.$transaction to ensure atomicity.
  • Idempotency:
    • startWorkout is idempotent for a specific SWW (returns existing unfinished WHE).
    • markWorkoutAsCompleted and markWorkoutAsSkipped are idempotent for already processed SWWs.
  • Data Flow for "Start Workout":
    1. Client calls POST .../:scheduledWorkoutId/start.
    2. Controller fetches SWW (with PUI & PWT Snapshot). Validates.
    3. Controller calls EffectiveWorkoutService.getEffectiveWorkout(puiId, sww.planWeekNumber, sww.userProgramPwtSnapshotId).
    4. Controller (within a transaction):
      • Creates WorkoutHistoryEntry (linking to SWW, PUI, PWT Snapshot, master PWT).
      • Creates WorkoutCompletedExercises based on EffectiveWorkout data (including target* fields).
      • Creates empty ExerciseSets for each WCE.
      • Updates PUI.lastActivityDate.
    5. Controller returns the WorkoutHistorySkeletonResponse.
  • Data Flow for "Complete/Skip Workout":
    1. Client calls POST .../:scheduledWorkoutId/complete (with workoutHistoryEntryId) or /skip.
    2. Controller calls respective UserProgramSchedulingService method.
    3. Service (within a transaction):
      • Validates.
      • Updates UserProgramScheduledWeekWorkout.status (and links WHE for complete).
      • Updates ProgramUserInstance progression fields.
      • Calls _generateScheduleForWindow (which performs its own DB reads/writes for SWWs).
    4. Service returns updated PUI (with snapshot details for DTO).
    5. Controller uses mapPuiToResponseDto and sends response.

Future Enhancements (Potential)

  • Storing a "reason" for skipping workouts.
  • More sophisticated rules for when/how "catch-up" workouts are presented or automatically aged out.
  • UI/UX for managing the schedule more directly (e.g., drag-and-drop rescheduling, though this adds complexity).

This updated page now integrates the user enrollment/scheduling features directly with the concept of the Program Catalog, providing a more unified view of how users interact with predefined plans. Remember to replace placeholders and add visuals!