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');
}
}
Related Servicesβ
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:
- Review the Progression Playbook API documentation
- Test progression queries in GraphQL Playground
- Check progression rules and recommendation logic
- Contact the AI/ML team for rule engine questions