2025-03-17
This document defines the core entities for the fitness tracking application, their relationships, and persistence considerations. These models support the requirements defined in the epics and user personas.
Entity Relationship Diagram
The User Profile stores information about the application user.
data class UserProfile(
val userId: String, // Unique identifier
var displayName: String, // User's name displayed in the app
var height: Measurement? = null, // Optional height
var weight: Measurement? = null, // Optional current weight
var fitnessLevel: FitnessLevel = FitnessLevel.BEGINNER,
var weightUnit: WeightUnit = WeightUnit.KILOGRAMS,
var distanceUnit: DistanceUnit = DistanceUnit.KILOMETERS,
var availableEquipment: List<Equipment> = emptyList(),
var equipmentProfiles: List<EquipmentProfile> = emptyList(),
var dateCreated: Instant,
var lastUpdated: Instant
)
enum class FitnessLevel {
BEGINNER,
INTERMEDIATE,
ADVANCED,
ELITE
}
enum class WeightUnit {
KILOGRAMS,
POUNDS
}
enum class DistanceUnit {
KILOMETERS,
MILES
}
data class EquipmentProfile(
val id: String,
var name: String,
var equipment: List<Equipment>
)Persistence Considerations: - Store in Room database with single row for current user - Sensitive fields (weight, height) should be optional and have privacy controls - Equipment profiles need one-to-many relationship with main profile
Exercise defines a specific physical activity that can be performed during workouts.
data class Exercise(
val id: String, // Unique identifier
var name: String, // Exercise name
var description: String, // Detailed description
var primaryMuscles: List<MuscleGroup>, // Primary muscles targeted
var secondaryMuscles: List<MuscleGroup>, // Secondary muscles targeted
var equipment: List<Equipment>, // Equipment required
var difficulty: ExerciseDifficulty, // Difficulty level
var exerciseType: ExerciseType, // Type of exercise
var instructions: List<String>, // Step-by-step instructions
var demonstrationImageUrls: List<String>, // URLs to demonstration images
var demonstrationVideoUrl: String? = null, // URL to demonstration video
var isCustom: Boolean, // Whether this is a custom user exercise
var tags: List<String>, // Additional tags for filtering
var isBodyweightExercise: Boolean, // Whether the exercise uses bodyweight
var parentExerciseId: String? = null, // For exercise variants
var created: Instant,
var lastUpdated: Instant
)
enum class ExerciseType {
STRENGTH,
CARDIO,
FLEXIBILITY,
BALANCE,
PLYOMETRIC,
COMPOUND,
ISOLATION
}
enum class ExerciseDifficulty {
BEGINNER,
INTERMEDIATE,
ADVANCED
}
enum class MuscleGroup {
CHEST,
BACK,
SHOULDERS,
BICEPS,
TRICEPS,
FOREARMS,
QUADRICEPS,
HAMSTRINGS,
GLUTES,
CALVES,
CORE,
ABDOMINALS,
OBLIQUES,
LOWER_BACK,
FULL_BODY,
CARDIO_SYSTEM
}
enum class Equipment {
NONE,
BARBELL,
DUMBBELL,
KETTLEBELL,
RESISTANCE_BAND,
CABLE_MACHINE,
SMITH_MACHINE,
SQUAT_RACK,
BENCH,
PULL_UP_BAR,
DIP_STATION,
LEG_PRESS_MACHINE,
CARDIO_MACHINE,
MEDICINE_BALL,
STABILITY_BALL,
FOAM_ROLLER,
TRX,
WEIGHT_PLATE
}Persistence Considerations: - Core exercises stored in app assets as JSON for initial population - Custom exercises stored in Room database - Exercise metadata (images, videos) should support offline caching - Support efficient filtering and searches by muscle group, equipment, etc.
WorkoutProgram represents a collection of workouts structured into a complete training program.
data class WorkoutProgram(
val id: String, // Unique identifier
var name: String, // Program name
var description: String, // Program description
var difficulty: ProgramDifficulty, // Program difficulty
var category: ProgramCategory, // Program category/type
var estimatedDurationWeeks: Int, // Estimated duration in weeks
var workoutsPerWeek: Int, // Expected workouts per week
var schedule: List<WorkoutSchedule>, // Scheduled workouts
var isCustom: Boolean, // Whether this is a custom user program
var created: Instant,
var lastUpdated: Instant,
var creatorId: String? = null, // ID of creator (null for system programs)
var tags: List<String> = emptyList() // Tags for filtering programs
)
data class WorkoutSchedule(
val workoutId: String, // Reference to a Workout
val weekNumber: Int, // Week in the program (1-based)
val dayOfWeek: Int, // Day of week (1 = Monday, 7 = Sunday)
val isDeloadWeek: Boolean = false // Whether this is a deload week
)
enum class ProgramDifficulty {
BEGINNER,
INTERMEDIATE,
ADVANCED
}
enum class ProgramCategory {
STRENGTH,
HYPERTROPHY,
ENDURANCE,
WEIGHT_LOSS,
GENERAL_FITNESS,
POWERLIFTING,
BODYBUILDING,
CROSSFIT,
SPORT_SPECIFIC,
REHABILITATION
}Persistence Considerations: - Base programs stored in app assets as JSON - Custom and modified programs stored in Room database - Support for sharing programs between users (export/import)
Workout represents a single training session with a specific set of exercises.
data class Workout(
val id: String, // Unique identifier
var name: String, // Workout name
var description: String? = null, // Workout description
var exerciseGroups: List<ExerciseGroup>, // Grouped exercises
var estimatedDurationMinutes: Int, // Estimated duration
var targetMuscleGroups: List<MuscleGroup>, // Primary muscles targeted
var difficulty: ProgramDifficulty, // Workout difficulty
var isCustom: Boolean, // Whether this is a custom workout
var parentProgramId: String? = null, // Program this workout belongs to (optional)
var created: Instant,
var lastUpdated: Instant,
var notes: String? = null // Additional notes
)
data class ExerciseGroup(
val id: String,
var name: String? = null, // Optional group name (e.g., "Superset 1")
var exercises: List<WorkoutExercise>, // Exercises in this group
var type: ExerciseGroupType // Type of grouping
)
enum class ExerciseGroupType {
REGULAR, // Sequential exercises
SUPERSET, // Alternating exercises with minimal rest
CIRCUIT, // Multiple exercises performed in sequence with minimal rest
PYRAMID // Progressive increase/decrease in weight or reps
}
data class WorkoutExercise(
val id: String,
val exerciseId: String, // Reference to an Exercise
var order: Int, // Order in the workout
var sets: List<ExerciseSet>, // Sets configuration
var restTimeBetweenSets: Duration = Duration.ofSeconds(90),
var restTimeAfterExercise: Duration = Duration.ofSeconds(120),
var notes: String? = null // Exercise-specific notes
)
data class ExerciseSet(
val id: String,
var setType: SetType, // Type of set
var targetReps: Int? = null, // Target repetitions (null for time-based)
var targetDuration: Duration? = null, // Target duration (null for rep-based)
var targetWeight: Double? = null, // Target weight (null for bodyweight)
var dropSets: List<DropSet>? = null // For drop sets
)
enum class SetType {
NORMAL,
WARM_UP,
DROP_SET,
FAILURE,
AMRAP // As Many Reps As Possible
}
data class DropSet(
val weight: Double,
val targetReps: Int
)Persistence Considerations: - Workouts can exist independently or as part of a program - Efficient retrieval of workouts for current day/week - Support embedded transaction to maintain workout structure integrity
WorkoutSession represents a specific instance of a performed workout with recorded performance.
data class WorkoutSession(
val id: String, // Unique identifier
val workoutId: String, // Reference to Workout template
val userId: String, // User who performed the workout
val programId: String? = null, // Program this session is part of (optional)
var startTime: Instant, // When the session started
var endTime: Instant? = null, // When the session ended (null if ongoing)
var state: WorkoutState = WorkoutState.IN_PROGRESS,
var exerciseRecords: List<ExerciseRecord>, // Exercises performed
var totalVolume: Double? = null, // Total weight lifted
var notes: String? = null // Session notes
)
enum class WorkoutState {
IN_PROGRESS,
COMPLETED,
PAUSED,
ABANDONED
}
data class ExerciseRecord(
val id: String,
val exerciseId: String, // Reference to Exercise
val workoutExerciseId: String, // Reference to WorkoutExercise
var order: Int, // Actual order performed (may differ from plan)
var startTime: Instant, // When this exercise started
var endTime: Instant? = null, // When this exercise ended
var setRecords: List<SetRecord>, // Sets performed
var notes: String? = null // Notes during this exercise
)
data class SetRecord(
val id: String,
val setType: SetType, // Type of set performed
var repsCompleted: Int? = null, // Actual reps completed
var weightUsed: Double? = null, // Actual weight used
var durationCompleted: Duration? = null, // Actual duration
var difficultyRating: Int? = null, // Perceived difficulty (1-10)
var completionTime: Instant, // When this set was logged
var isPersonalRecord: Boolean = false, // Whether this is a PR
var notes: String? = null // Set-specific notes
)Persistence Considerations: - Room database transaction for saving complete sessions - Support for restoring abandoned/crashed sessions - Efficient query by date range, program, and exercise
Goal represents a training objective the user wants to achieve.
data class Goal(
val id: String, // Unique identifier
val userId: String, // User who set the goal
var name: String, // Goal name
var description: String? = null, // Goal description
var type: GoalType, // Type of goal
var targetValue: Double, // Target numeric value
var currentValue: Double, // Current progress
var startDate: Instant, // When the goal started
var targetDate: Instant? = null, // Deadline (optional)
var status: GoalStatus = GoalStatus.IN_PROGRESS,
var exerciseId: String? = null, // For exercise-specific goals
var programId: String? = null, // For program-specific goals
var created: Instant,
var lastUpdated: Instant
)
enum class GoalType {
WEIGHT_LIFTED, // Target weight for an exercise
FREQUENCY, // Number of workouts
VOLUME, // Total volume lifted
BODY_MEASUREMENT, // Body measurement target
CONSECUTIVE_DAYS, // Workout streak
PROGRAM_COMPLETION // Complete specific program
}
enum class GoalStatus {
IN_PROGRESS,
COMPLETED,
FAILED,
ABANDONED
}Persistence Considerations: - Room database with user-to-goals relationship - Support for automatic progress updates when related activities are recorded - Notification triggers for approaching deadlines and milestones
Achievement represents badges and milestones the user has earned.
data class Achievement(
val id: String, // Unique identifier
val userId: String, // User who earned the achievement
val achievementDefinitionId: String, // Reference to achievement definition
var earnedDate: Instant, // When the achievement was earned
var currentProgress: Double? = null, // Progress toward next level (if applicable)
var level: Int = 1 // Achievement level (for tiered achievements)
)
data class AchievementDefinition(
val id: String, // Unique identifier
var name: String, // Achievement name
var description: String, // Achievement description
var category: AchievementCategory, // Achievement category
var iconUrl: String, // URL to achievement icon
var thresholds: List<Double>, // Thresholds for different levels
var isHidden: Boolean = false // Whether this is a secret achievement
)
enum class AchievementCategory {
CONSISTENCY,
STRENGTH,
VOLUME,
VARIETY,
MILESTONE,
SPECIAL
}Persistence Considerations: - Achievement definitions stored in app assets - Earned achievements stored in Room database - Support for progress tracking and notifications
The key relationships between entities are:
The application will use a multi-tiered persistence strategy:
The application will follow an offline-first approach:
To ensure data integrity, the following validation rules will be implemented:
Database migrations will follow these principles:
To protect user data:
The data model will leverage Kotlin features for type safety:
E. Bruno - Data Models