Skip to main content

User Management Service

The User Management Service handles user profiles, preferences, and account management for the OpenLift platform, providing comprehensive user data management beyond authentication.

Overview​

The User Management Service is responsible for:

  • User profile management and customization
  • Personal preferences and settings
  • Unit system preferences (metric/imperial)
  • Profile information updates and validation
  • User account data retrieval and management

Key Features​

πŸ‘€ Profile Management​

  • Personal Information: Name, bio, fitness goals, experience level
  • Customizable Profiles: Avatar, display preferences, public visibility settings
  • Account Settings: Email preferences, notification settings, privacy controls

βš–οΈ Unit Preferences​

  • Flexible Unit Systems: Support for metric, imperial, and mixed unit preferences
  • Exercise-Specific Units: Different units for weight, distance, and measurements
  • Automatic Conversion: Seamless unit conversion across the platform

πŸ”§ User Preferences​

  • Workout Preferences: Default rest times, preferred workout types, equipment access
  • Display Settings: Theme preferences, dashboard customization, data visualization
  • Notification Settings: Push notifications, email preferences, reminder settings

Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client App β”‚ β”‚ User Mgmt Svc β”‚ β”‚ Database β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β€’ Profile Forms │───▢│ β€’ Data Valid. │───▢│ β€’ User Profiles β”‚
β”‚ β€’ Settings UI │◄───│ β€’ Preferences │◄───│ β€’ Preferences β”‚
β”‚ β€’ Unit Display β”‚ β”‚ β€’ Unit Mgmt β”‚ β”‚ β€’ Settings β”‚
β”‚ β€’ Customization β”‚ β”‚ β€’ Profile Mgmt β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Service Responsibilities​

βœ… User Management Service Handles​

  • User profile information (name, bio, fitness goals)
  • Personal preferences and settings
  • Unit system management and conversion
  • Profile visibility and privacy settings
  • Account information updates and validation
  • User preference synchronization across devices

❌ User Management Service Does NOT Handle​

  • Authentication and login (handled by Authentication Service)
  • Password management and security
  • Workout data and exercise history
  • Program enrollment and tracking
  • Analytics and performance metrics

Key Data Models​

User Profile​

interface UserProfile {
id: string;
email: string;
username: string;
displayName?: string;
bio?: string;
avatarUrl?: string;

// Fitness information
fitnessLevel: 'beginner' | 'intermediate' | 'advanced';
fitnessGoals: string[];
dateOfBirth?: Date;
height?: number;
weight?: number;

// System preferences
unitPreferences: UnitPreferences;
notificationSettings: NotificationSettings;
privacySettings: PrivacySettings;

createdAt: Date;
updatedAt: Date;
}

Unit Preferences​

interface UnitPreferences {
weightUnit: 'kg' | 'lbs';
distanceUnit: 'km' | 'miles';
heightUnit: 'cm' | 'inches';
temperatureUnit: 'celsius' | 'fahrenheit';

// Mixed unit system support
useMetricForWeight: boolean;
useImperialForDistance: boolean;
}

Key Operations​

Get User Profile​

query GetUserProfile {
userProfile {
id
email
username
displayName
bio
avatarUrl
fitnessLevel
fitnessGoals
unitPreferences {
weightUnit
distanceUnit
heightUnit
}
notificationSettings {
pushNotifications
emailNotifications
workoutReminders
}
}
}

Update Profile​

mutation UpdateUserProfile($input: UpdateUserProfileInput!) {
updateUserProfile(input: $input) {
id
displayName
bio
fitnessLevel
fitnessGoals
unitPreferences {
weightUnit
distanceUnit
}
}
}

Update Unit Preferences​

mutation UpdateUnitPreferences($input: UnitPreferencesInput!) {
updateUnitPreferences(input: $input) {
weightUnit
distanceUnit
heightUnit
temperatureUnit
}
}

Integration Patterns​

Flutter Profile Management​

class UserProfileService {
final GraphQLClient _client;

// Get complete user profile
Future<UserProfile> getUserProfile() async {
const query = '''
query GetUserProfile {
userProfile {
id
email
username
displayName
bio
fitnessLevel
unitPreferences {
weightUnit
distanceUnit
heightUnit
}
}
}
''';

final result = await _client.query(QueryOptions(document: gql(query)));
return UserProfile.fromJson(result.data!['userProfile']);
}

// Update user preferences
Future<UserProfile> updateProfile(UpdateUserProfileInput input) async {
const mutation = '''
mutation UpdateUserProfile(\$input: UpdateUserProfileInput!) {
updateUserProfile(input: \$input) {
id
displayName
bio
fitnessLevel
fitnessGoals
}
}
''';

final result = await _client.mutate(MutationOptions(
document: gql(mutation),
variables: {'input': input.toJson()},
));

return UserProfile.fromJson(result.data!['updateUserProfile']);
}
}

Unit Conversion Integration​

class UnitConversionService {
final UserProfileService _userService;

// Convert weight based on user preference
Future<String> formatWeight(double weight) async {
final profile = await _userService.getUserProfile();

switch (profile.unitPreferences.weightUnit) {
case 'kg':
return '${weight.toStringAsFixed(1)} kg';
case 'lbs':
final lbs = weight * 2.20462;
return '${lbs.toStringAsFixed(1)} lbs';
default:
return '${weight.toStringAsFixed(1)} kg';
}
}

// Convert distance based on user preference
Future<String> formatDistance(double distance) async {
final profile = await _userService.getUserProfile();

switch (profile.unitPreferences.distanceUnit) {
case 'km':
return '${distance.toStringAsFixed(2)} km';
case 'miles':
final miles = distance * 0.621371;
return '${miles.toStringAsFixed(2)} mi';
default:
return '${distance.toStringAsFixed(2)} km';
}
}
}

User Preference Categories​

Fitness Preferences​

interface FitnessPreferences {
fitnessLevel: 'beginner' | 'intermediate' | 'advanced';
fitnessGoals: ('weight_loss' | 'muscle_gain' | 'strength' | 'endurance')[];
preferredWorkoutTypes: string[];
availableEquipment: string[];
workoutDaysPerWeek: number;
sessionDurationPreference: number; // minutes
}

Display Preferences​

interface DisplayPreferences {
theme: 'light' | 'dark' | 'auto';
language: string;
timezone: string;
dateFormat: 'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD';
firstDayOfWeek: 'monday' | 'sunday';
}

Privacy Settings​

interface PrivacySettings {
profileVisibility: 'public' | 'friends' | 'private';
shareWorkoutData: boolean;
shareProgressPhotos: boolean;
allowFriendRequests: boolean;
showOnlineStatus: boolean;
}

Event System​

User Management Events​

interface UserManagementEvents {
'user.profile_updated': {
userId: string;
changedFields: string[];
};
'user.preferences_changed': {
userId: string;
preferenceType: string;
};
'user.units_changed': {
userId: string;
oldUnits: UnitPreferences;
newUnits: UnitPreferences;
};
}

Data Validation​

Profile Validation​

class UserProfileValidator {
validateDisplayName(name: string): ValidationResult {
if (name.length < 2) return { valid: false, error: 'Too short' };
if (name.length > 50) return { valid: false, error: 'Too long' };
if (!/^[a-zA-Z0-9\s_-]+$/.test(name)) {
return { valid: false, error: 'Invalid characters' };
}
return { valid: true };
}

validateBio(bio: string): ValidationResult {
if (bio.length > 500) return { valid: false, error: 'Bio too long' };
return { valid: true };
}

validateFitnessGoals(goals: string[]): ValidationResult {
if (goals.length === 0) return { valid: false, error: 'At least one goal required' };
if (goals.length > 5) return { valid: false, error: 'Too many goals' };
return { valid: true };
}
}

Integration with Other Services​

Workout Services Integration​

// Services that depend on user preferences
class WorkoutHistoryService {
async formatWorkoutData(workout: WorkoutData, userId: string) {
const userPrefs = await this.userService.getUnitPreferences(userId);

// Convert weights based on user preference
workout.exercises = workout.exercises.map(exercise => ({
...exercise,
sets: exercise.sets.map(set => ({
...set,
weight: this.convertWeight(set.weight, userPrefs.weightUnit)
}))
}));

return workout;
}
}

Error Handling​

Profile Update Errors​

try {
await userService.updateProfile(profileData);
} on GraphQLError catch (e) {
switch (e.extensions?['code']) {
case 'INVALID_DISPLAY_NAME':
showError('Display name contains invalid characters');
break;
case 'BIO_TOO_LONG':
showError('Bio must be less than 500 characters');
break;
case 'INVALID_FITNESS_LEVEL':
showError('Please select a valid fitness level');
break;
case 'UNAUTHORIZED':
showError('You can only update your own profile');
break;
default:
showError('Failed to update profile');
}
}

Performance Considerations​

Caching Strategy​

  • Profile Caching: Cache user profiles locally for offline access
  • Preference Caching: Cache unit preferences for immediate conversion
  • Selective Updates: Only sync changed fields to reduce bandwidth

Optimization Patterns​

class CachedUserProfileService {
UserProfile? _cachedProfile;
DateTime? _lastFetch;

Future<UserProfile> getUserProfile({bool forceRefresh = false}) async {
if (!forceRefresh &&
_cachedProfile != null &&
_lastFetch != null &&
DateTime.now().difference(_lastFetch!).inMinutes < 15) {
return _cachedProfile!;
}

_cachedProfile = await _fetchUserProfile();
_lastFetch = DateTime.now();
return _cachedProfile!;
}
}

Testing Strategy​

Unit Tests​

  • Profile validation logic
  • Unit conversion accuracy
  • Preference update handling
  • Data serialization/deserialization

Integration Tests​

  • Profile CRUD operations
  • Unit preference synchronization
  • Cross-service data consistency
  • Event emission verification

Security Considerations​

Data Privacy​

  • Personal Information Protection: Sensitive data encrypted at rest
  • Profile Visibility Controls: Granular privacy settings
  • Data Access Logging: Track profile data access for security

Validation & Sanitization​

class ProfileSanitizer {
sanitizeDisplayName(name: string): string {
return name
.trim()
.replace(/[<>]/g, '') // Remove HTML tags
.substring(0, 50); // Enforce length limit
}

sanitizeBio(bio: string): string {
return bio
.trim()
.replace(/<[^>]*>/g, '') // Strip HTML
.substring(0, 500); // Enforce length limit
}
}

Dependencies​

  • Authentication Service: User identity verification
  • Database: Profile and preference storage

Consumers​

  • Workout History Service: Unit preferences for data display
  • Program Services: Fitness level and goals for recommendations
  • Analytics Services: User preferences for personalized insights
  • Coaching Service: Profile data for personalized coaching

API Documentation​

For detailed GraphQL schema and usage examples, see:

  • User Management API documentation: coming soon

Support​

For user management questions:

  1. Review the User Management API documentation
  2. Test profile operations in GraphQL Playground
  3. Check unit conversion logic and preferences
  4. Contact the development team for preference system questions