Skip to main content

Progression Playbook Service

The Progression Playbook Service provides intelligent exercise progression recommendations and rule management for OpenLift, analyzing workout performance to suggest optimal progression strategies.

Overview​

The Progression Playbook Service handles:

  • Exercise-specific progression rule management
  • Workout performance analysis for progression decisions
  • Intelligent progression recommendations based on user performance
  • Progressive overload strategy implementation
  • Deload and recovery period recommendations
  • Plateau detection and breakthrough strategies

Key Features​

🧠 Intelligent Progression Rules​

  • Exercise-Specific Rules: Different progression strategies for different exercise types
  • Performance-Based Decisions: Analyze RPE, reps, and completion rates
  • Adaptive Recommendations: Adjust progression based on user response patterns
  • Multi-Factor Analysis: Consider volume, intensity, and recovery indicators

πŸ“ˆ Progressive Overload Management​

  • Weight Progression: Intelligent weight increases based on performance
  • Volume Progression: Set and rep adjustments for continued growth
  • Intensity Progression: RPE-based intensity management
  • Periodization Support: Long-term progression planning and cycling

🎯 Personalized Strategies​

  • User-Specific Patterns: Learn from individual response patterns
  • Goal-Oriented Progression: Align progressions with user fitness goals
  • Equipment Adaptations: Adjust progressions based on available equipment
  • Experience Level Scaling: Different strategies for beginners vs advanced users

Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client App β”‚ β”‚ Progression β”‚ β”‚ Database β”‚
β”‚ β”‚ β”‚ Playbook β”‚ β”‚ β”‚
β”‚ β€’ Recommendations│◄───│ β€’ Rule Engine │◄───│ β€’ Rules & Logic β”‚
β”‚ β€’ Progress View β”‚ β”‚ β€’ Performance β”‚ β”‚ β€’ User Data β”‚
β”‚ β€’ Feedback β”‚ β”‚ Analysis β”‚ β”‚ β€’ History β”‚
β”‚ β€’ Adjustments β”‚ β”‚ β€’ Adaptation β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Service Responsibilities​

βœ… Progression Playbook Service Handles​

  • Exercise progression rule creation and management
  • Workout performance analysis and interpretation
  • Progression recommendation generation
  • Plateau detection and breakthrough strategies
  • Deload timing and recovery recommendations
  • User progression pattern learning and adaptation

❌ Progression Playbook Service Does NOT Handle​

  • Actual workout execution or logging
  • Program template creation or management
  • Real-time workout guidance
  • Social features or progress sharing
  • Nutrition or recovery recommendations (outside of deloads)

Core Data Models​

Progression Rule​

interface ProgressionRule {
id: string;
name: string;
description: string;

// Rule scope
exerciseIds?: string[]; // Specific exercises, or null for general
exerciseTypes?: string[]; // e.g., 'compound', 'isolation'
muscleGroups?: string[];

// Conditions for progression
conditions: ProgressionCondition[];

// Progression actions
actions: ProgressionAction[];

// Rule metadata
priority: number; // Higher priority rules evaluated first
isActive: boolean;
validityPeriod?: {
startDate?: Date;
endDate?: Date;
};

// Analytics
successRate?: number;
timesApplied: number;

createdAt: Date;
updatedAt: Date;
}

Progression Conditions​

interface ProgressionCondition {
type: 'rpe_average' | 'completion_rate' | 'consecutive_completions' | 'plateau_detected';

// Condition parameters
threshold?: number; // e.g., RPE < 7.5
operator: 'lt' | 'le' | 'eq' | 'ge' | 'gt';
timeframe?: number; // weeks to analyze

// Specific condition data
rpeThreshold?: number;
completionRateThreshold?: number;
consecutiveSessionsRequired?: number;
plateauDetectionWeeks?: number;
}

interface ProgressionAction {
type: 'increase_weight' | 'increase_reps' | 'increase_sets' | 'deload' | 'maintain';

// Action parameters
weightIncrement?: number; // kg or lbs
repIncrement?: number;
setIncrement?: number;
deloadPercentage?: number; // e.g., 0.85 for 15% deload

// Conditions for action
maxWeight?: number;
maxReps?: number;
maxSets?: number;
}

Progression Recommendation​

interface ProgressionRecommendation {
id: string;
userId: string;
exerciseId: string;

// Recommendation details
recommendationType: 'progression' | 'deload' | 'maintain' | 'exercise_change';
recommendation: string;
reasoning: string;

// Specific adjustments
currentParameters: ExerciseParameters;
recommendedParameters: ExerciseParameters;

// Confidence and priority
confidenceScore: number; // 0-1
priority: 'low' | 'medium' | 'high';

// Timing
recommendedStartDate: Date;
validUntil?: Date;

// User interaction
userResponse?: 'accepted' | 'rejected' | 'modified';
userFeedback?: string;

// Analytics
ruleId: string; // Which rule generated this recommendation
performanceData: PerformanceDataPoint[];

createdAt: Date;
}

interface ExerciseParameters {
weight?: number;
sets?: number;
reps?: number;
targetRpe?: number;
restSeconds?: number;
}

Key Operations​

Get Progression Recommendations​

query GetProgressionRecommendations($userId: ID!, $exerciseIds: [ID!]) {
progressionRecommendations(userId: $userId, exerciseIds: $exerciseIds) {
id
exercise {
id
name
}
recommendationType
recommendation
reasoning
confidenceScore
priority

currentParameters {
weight
sets
reps
targetRpe
}

recommendedParameters {
weight
sets
reps
targetRpe
}

recommendedStartDate
}
}

Analyze Exercise Performance​

query AnalyzeExercisePerformance(
$userId: ID!,
$exerciseId: ID!,
$weeks: Int = 4
) {
exercisePerformanceAnalysis(
userId: $userId,
exerciseId: $exerciseId,
weeks: $weeks
) {
exerciseId
analysisWeeks

# Performance trends
weightProgression {
week
averageWeight
trend
}

rpeProgression {
week
averageRpe
trend
}

volumeProgression {
week
totalVolume
trend
}

# Analysis insights
plateauDetected
plateauWeeks
progressionVelocity
recommendedAction

# Performance indicators
completionRate
consistencyScore
fatigueIndicators
}
}

Apply Progression Recommendation​

mutation ApplyProgressionRecommendation(
$recommendationId: ID!,
$userResponse: UserResponseInput!
) {
applyProgressionRecommendation(
recommendationId: $recommendationId,
userResponse: $userResponse
) {
id
userResponse
appliedParameters {
weight
sets
reps
}
nextReviewDate
}
}

Integration Patterns​

Flutter Progression Interface​

class ProgressionPlaybookService {
final GraphQLClient _client;

// Get personalized progression recommendations
Future<List<ProgressionRecommendation>> getRecommendations({
required String userId,
List<String>? exerciseIds,
}) async {
const query = '''
query GetProgressionRecommendations(
\$userId: ID!,
\$exerciseIds: [ID!]
) {
progressionRecommendations(
userId: \$userId,
exerciseIds: \$exerciseIds
) {
id
exercise {
id
name
}
recommendationType
recommendation
reasoning
confidenceScore
priority
currentParameters {
weight
sets
reps
targetRpe
}
recommendedParameters {
weight
sets
reps
targetRpe
}
}
}
''';

final result = await _client.query(QueryOptions(
document: gql(query),
variables: {
'userId': userId,
'exerciseIds': exerciseIds,
}..removeWhere((key, value) => value == null),
));

return (result.data!['progressionRecommendations'] as List)
.map((json) => ProgressionRecommendation.fromJson(json))
.toList();
}

// Analyze exercise performance for progression insights
Future<ExercisePerformanceAnalysis> analyzeExercise({
required String userId,
required String exerciseId,
int weeks = 4,
}) async {
const query = '''
query AnalyzeExercisePerformance(
\$userId: ID!,
\$exerciseId: ID!,
\$weeks: Int
) {
exercisePerformanceAnalysis(
userId: \$userId,
exerciseId: \$exerciseId,
weeks: \$weeks
) {
plateauDetected
progressionVelocity
completionRate
consistencyScore
recommendedAction
weightProgression {
week
averageWeight
trend
}
rpeProgression {
week
averageRpe
trend
}
}
}
''';

final result = await _client.query(QueryOptions(
document: gql(query),
variables: {
'userId': userId,
'exerciseId': exerciseId,
'weeks': weeks,
},
));

return ExercisePerformanceAnalysis.fromJson(
result.data!['exercisePerformanceAnalysis']
);
}
}

Progression Dashboard Widget​

class ProgressionDashboard extends StatefulWidget {
final String userId;

@override
_ProgressionDashboardState createState() => _ProgressionDashboardState();
}

class _ProgressionDashboardState extends State<ProgressionDashboard> {
List<ProgressionRecommendation> recommendations = [];
bool isLoading = true;

@override
void initState() {
super.initState();
_loadRecommendations();
}

Future<void> _loadRecommendations() async {
try {
final recs = await progressionService.getRecommendations(
userId: widget.userId,
);

setState(() {
recommendations = recs;
isLoading = false;
});
} catch (e) {
setState(() => isLoading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to load recommendations: $e')),
);
}
}

@override
Widget build(BuildContext context) {
if (isLoading) return const CircularProgressIndicator();

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Progression Recommendations',
style: Theme.of(context).textTheme.headline6,
),
const SizedBox(height: 16),

if (recommendations.isEmpty) ...[
const Text('No progression recommendations available'),
const Text('Complete more workouts to get personalized suggestions'),
] else ...[
...recommendations.map((rec) => ProgressionCard(
recommendation: rec,
onAccept: () => _acceptRecommendation(rec),
onReject: () => _rejectRecommendation(rec),
)),
],
],
);
}

Future<void> _acceptRecommendation(ProgressionRecommendation rec) async {
await progressionService.applyRecommendation(
recommendationId: rec.id,
userResponse: UserResponse.accepted(),
);

ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Applied progression for ${rec.exercise.name}')),
);

_loadRecommendations(); // Refresh
}
}

Progression Rule Engine​

Rule Evaluation Logic​

class ProgressionRuleEngine {
async evaluateProgressionForExercise(
userId: string,
exerciseId: string,
performanceData: PerformanceDataPoint[]
): Promise<ProgressionRecommendation[]> {

// Get applicable rules for this exercise
const applicableRules = await this.getApplicableRules(exerciseId);

const recommendations: ProgressionRecommendation[] = [];

for (const rule of applicableRules) {
const conditionsMatch = await this.evaluateConditions(
rule.conditions,
performanceData
);

if (conditionsMatch) {
const recommendation = await this.generateRecommendation(
rule,
userId,
exerciseId,
performanceData
);

if (recommendation) {
recommendations.push(recommendation);
}
}
}

// Sort by priority and confidence
return recommendations.sort((a, b) =>
(b.confidenceScore * this.getPriorityWeight(b.priority)) -
(a.confidenceScore * this.getPriorityWeight(a.priority))
);
}

private async evaluateConditions(
conditions: ProgressionCondition[],
performanceData: PerformanceDataPoint[]
): Promise<boolean> {

for (const condition of conditions) {
const result = await this.evaluateCondition(condition, performanceData);
if (!result) return false; // All conditions must be met
}

return true;
}

private async evaluateCondition(
condition: ProgressionCondition,
performanceData: PerformanceDataPoint[]
): Promise<boolean> {

switch (condition.type) {
case 'rpe_average':
const avgRpe = this.calculateAverageRpe(performanceData, condition.timeframe);
return this.compareValues(avgRpe, condition.threshold!, condition.operator);

case 'completion_rate':
const completionRate = this.calculateCompletionRate(performanceData, condition.timeframe);
return this.compareValues(completionRate, condition.threshold!, condition.operator);

case 'consecutive_completions':
const consecutive = this.countConsecutiveCompletions(performanceData);
return consecutive >= (condition.consecutiveSessionsRequired || 0);

case 'plateau_detected':
return this.detectPlateau(performanceData, condition.plateauDetectionWeeks);

default:
return false;
}
}
}

Performance Analysis​

class PerformanceAnalyzer {
analyzeExerciseProgression(
performanceData: PerformanceDataPoint[]
): ProgressionAnalysis {

// Analyze weight progression
const weightTrend = this.calculateTrend(
performanceData.map(p => ({ date: p.date, value: p.weight }))
);

// Analyze RPE progression
const rpeTrend = this.calculateTrend(
performanceData.map(p => ({ date: p.date, value: p.averageRpe }))
);

// Analyze volume progression
const volumeTrend = this.calculateTrend(
performanceData.map(p => ({ date: p.date, value: p.totalVolume }))
);

// Detect plateau
const plateauDetected = this.detectPlateau(performanceData, 4);

// Calculate progression velocity
const progressionVelocity = this.calculateProgressionVelocity(performanceData);

return {
weightTrend,
rpeTrend,
volumeTrend,
plateauDetected,
progressionVelocity,
completionRate: this.calculateCompletionRate(performanceData),
consistencyScore: this.calculateConsistencyScore(performanceData),
};
}

private detectPlateau(
performanceData: PerformanceDataPoint[],
weeks: number
): boolean {
if (performanceData.length < weeks) return false;

const recentData = performanceData.slice(-weeks);
const weightVariance = this.calculateVariance(
recentData.map(p => p.weight)
);

// Plateau if weight has barely changed and RPE hasn't decreased
const rpeIncrease = recentData[recentData.length - 1].averageRpe -
recentData[0].averageRpe;

return weightVariance < 0.5 && rpeIncrease > 0.5;
}
}

Event System Integration​

Progression Events​

interface ProgressionEvents {
'progression.recommendation_generated': {
userId: string;
exerciseId: string;
recommendationType: string;
confidenceScore: number;
};

'progression.recommendation_accepted': {
userId: string;
exerciseId: string;
recommendationId: string;
appliedChanges: ExerciseParameters;
};

'progression.plateau_detected': {
userId: string;
exerciseId: string;
plateauWeeks: number;
recommendedAction: string;
};

'progression.deload_recommended': {
userId: string;
exerciseId: string;
deloadPercentage: number;
reason: string;
};
}

Event Listeners​

class ProgressionEventHandlers {
// Trigger coaching recommendations when plateau detected
@EventListener('progression.plateau_detected')
async handlePlateauDetected(event: PlateauDetectedEvent) {
await this.coachingService.generatePlateauBreakthroughGuidance(
event.userId,
event.exerciseId
);
}

// Update analytics when progression recommendation accepted
@EventListener('progression.recommendation_accepted')
async handleRecommendationAccepted(event: RecommendationAcceptedEvent) {
await this.analyticsService.trackProgressionSuccess(
event.userId,
event.recommendationId
);
}
}

Machine Learning Integration​

Adaptive Rule Learning​

class AdaptiveProgressionEngine {
// Learn from user responses to improve recommendations
async adaptRulesBasedOnOutcomes(
userId: string,
recommendations: ProgressionRecommendation[]
): Promise<void> {

for (const rec of recommendations) {
if (!rec.userResponse) continue;

const outcome = await this.measureRecommendationOutcome(rec);

if (rec.userResponse === 'accepted' && outcome.wasSuccessful) {
// Increase confidence in this rule pattern
await this.reinforceRulePattern(rec.ruleId, outcome.successMetrics);
} else if (outcome.wasUnsuccessful) {
// Reduce confidence or modify rule
await this.adjustRuleBasedOnFailure(rec.ruleId, outcome.failureReasons);
}
}
}

// Personalize rules based on user's response patterns
async personalizeRulesForUser(userId: string): Promise<void> {
const userHistory = await this.getUserProgressionHistory(userId);
const patterns = this.analyzeUserPatterns(userHistory);

// Create or adjust user-specific rules
if (patterns.prefersConservativeProgression) {
await this.createConservativeProgressionRules(userId);
}

if (patterns.respondsWellToVolumeProgression) {
await this.emphasizeVolumeProgressionRules(userId);
}
}
}

Error Handling​

Progression Service Errors​

try {
final recommendations = await progressionService.getRecommendations(
userId: userId,
);
} on GraphQLError catch (e) {
switch (e.extensions?['code']) {
case 'INSUFFICIENT_DATA':
showError('Not enough workout data for progression analysis');
break;
case 'INVALID_EXERCISE':
showError('Exercise not found or not accessible');
break;
case 'ANALYSIS_FAILED':
showError('Unable to analyze performance data');
break;
case 'NO_APPLICABLE_RULES':
showError('No progression rules found for this exercise');
break;
default:
showError('Failed to generate progression recommendations');
}
}

Dependencies​

  • Workout History Service: Performance data for analysis
  • Exercise Service: Exercise metadata and characteristics
  • User Management Service: User preferences and goals

Consumers​

  • Coaching Service: Progression-based coaching recommendations
  • Program User Instance Service: Automatic program progression
  • Workout Analytics Service: Progression trend analysis
  • Effective Workout Service: Progression effectiveness evaluation

API Documentation​

For detailed GraphQL schema and usage examples, see:

  • Progression Playbook API documentation: coming soon

Support​

For progression playbook questions:

  1. Review the Progression Playbook API documentation
  2. Test progression queries in GraphQL Playground
  3. Check progression rules and recommendation logic
  4. Contact the AI/ML team for rule engine questions