75. Design Gym Fitness Center Management and Slot Booking System

Design Gym Fitness Center Management and Slot Booking System
You are building GetInShape, an in-memory backend for a fitness booking platform. GetInShape partners with multiple gym centers in cities. Each center has daily operating windows (timings) and supports a configurable list of workout types (for example: Weights, Cardio, Yoga, Swimming). Center admins define workout slots for the current day, and customers can view availability, book sessions, and cancel bookings.

Your system should support the following.

  • Functionality to onboard centers with details like centerName, center timings, and workout variations.
  • Each center can have N possible workout variations - Weights, Cardio, Yoga, Swimming etc. There could be newer workouts added in the future.
  • Functionality to define workout slots.
  • Each center will define a workout slot during center timings. These slots would be defined by a center admin.
  • Current scope is that at one point of time for a center, there would be just one workout.
  • The number of seats in each workout slot for a given center is fixed.
  • Current scope is that an admin would define these workout slots on a daily basis for the same day and only once. Update is out of scope.

End-User / Customer Operations

  • Optional - Register onto the platform. In the current scope we don’t have to worry about authentication.
  • View the workout slots availability/unavailability for the day - filter by workout type (sorted by start time in ASC order).
  • View the workout slots availability/unavailability for the day - filter by workout type and center name (sorted by seats available in ASC order).
  • Book a workout slot for a user if seats are available at that time.
  • Cancel the booked workout slot.
  • Optional - Notify me feature: If a user is interested in some particular slot of a center and seats are unavailable, he can choose to be part of the interest list for that slot. Once any other user cancels that particular slot the interested users can be notified. Notification will be pushed to all the interested users. You can use logs to model the notification.

1) Onboard a Center

void onboardCenter(String centerName, List<String> centerTimings, List<String> workoutTypes)
  • centerName is unique for a center (acts as identifier).
  • centerTimings contains time ranges for the day; each element is a string like "6-9" or "18-21". Time is an integer for the current scope (single day).
  • workoutTypes contains allowed workouts for the center, e.g. "Weights", "Cardio", "Yoga", "Swimming".
  • Adding newer workouts in the future should be supported by allowing new strings in workoutTypes.

2) Admin Defines a Workout Slot

boolean addWorkoutSlot(String centerName, String workoutType, int startTime, int endTime, int totalSeats)
  • startTime and endTime are integers for a day-only scope, e.g. 6 to 7.
  • startTime < endTime and totalSeats > 0.
  • The slot must lie fully inside at least one of the center timing ranges defined during onboarding.
  • The workoutType must be one of the allowed types for that center.
  • At any point in time for a center, there is just one workout: slots must not overlap in time for the same center.
  • Update is out of scope: once a slot is created, it cannot be modified (you may reject duplicate/overlapping re-definitions).
  • Return true if the slot is created; otherwise return false (invalid center, invalid time, invalid workout type, overlaps, etc.).

3) View Workout Availability (Sorted by Start Time)

List<String> viewWorkoutAvailabilityByStartTime(String workoutType, String centerName)
  • Returns slot availability for the day filtered by workoutType.
  • If centerName is empty or "*", include all centers; otherwise restrict to that center.
  • Sort the results by slot startTime and then lexicographically in ascending order.
  • Return each slot as a single string: "centerName|workoutType|startTime|endTime|seatsAvailable"

4) View Workout Availability (Sorted by Seats Available)

List<String> viewWorkoutAvailabilityBySeatsAvailable(String workoutType, String centerName)
  • Returns slot availability for the day filtered by workoutType and centerName.
  • centerName must be provided (cannot be empty or "*").
  • Sort the results by seatsAvailable and then lexicographicaly in ascending order.
  • Return each slot as a single string: "centerName|workoutType|startTime|endTime|seatsAvailable"
  • Book a slot
    String bookSession(String userId, String centerName, String workoutType, int startTime, int endTime)
    • Books exactly one seat for the identified slot: (centerName, workoutType, startTime, endTime).
    • Return values:
      • "BOOKED" on success
      • "NO_SEATS" if slot exists but has 0 seats available
      • "SLOT_NOT_FOUND" if the slot does not exist
      • "ALREADY_BOOKED" if the same user already booked the same slot
  • Cancel a booking
    String cancelSession(String userId, String centerName, String workoutType, int startTime, int endTime)
    • Cancels the user’s booking for the identified slot and restores exactly one seat.
    • Return values:
      • "CANCELLED" on success
      • "BOOKING_NOT_FOUND" if user has no booking for that slot
      • "SLOT_NOT_FOUND" if the slot does not exist
    • If notify-me is enabled, after cancellation notifyInterestedUsers() will return notification logs for interested users.
  • Notify-me / Interest list
    String addToInterestList(String userId, String centerName, String workoutType, int startTime, int endTime)
    • Adds the user to the interest list for the identified slot when the slot is currently full.
    • Return values:
      • "INTEREST_ADDED" if user was added
      • "ALREADY_INTERESTED" if user is already in the list
      • "SEATS_AVAILABLE" if slot currently has seats (so interest is not needed)
      • "SLOT_NOT_FOUND" if the slot does not exist
  • Notification dispatch
    List<String> notifyInterestedUsers(String centerName, String workoutType, int startTime, int endTime)
    • Called after a successful cancellation when a seat becomes available.
    • Returns log lines like: "NOTIFY|<userId>|<centerName>|<workoutType>|<startTime>-<endTime>".

Constraints

  • Time is an integer for a single day only (e.g. 6 means 6 AM, 18 means 6 PM).
  • centerTimings.size() >= 1 and each timing string is a range "start-end" with start < end.
  • workoutTypes.size() >= 1.
  • totalSeats > 0.
  • No external databases allowed; use only in-memory data structures.
  • All operations are for one day only, but design should be extensible to multiple days with minimal changes.
  • Identifiers are unique and lowercase (you may treat centerName and userId as unique identifiers).

Functional Notes

  • Admin can define slots only for the same day; updates to already-created slots are out of scope.
  • A center cannot create a workout slot outside its onboarded timings.
  • A center cannot create a workout slot for a workout type not onboarded for that center.
  • Within a center, workout slots must not overlap in time (one workout at one point of time).
  • For notifications, you can model notification as logs printed when cancellation happens.

Examples

Example 1: Center Onboarding + Slot Definition

onboardCenter(centerName = "connaught_place", centerTimings = List.of("6-9", "18-21"), workoutTypes = List.of("weights", "cardio", "yoga", "swimming"))
onboardCenter(centerName = "bandra_west", centerTimings = List.of("7-10", "19-22"), workoutTypes = List.of("weights", "cardio", "yoga"))

addWorkoutSlot(centerName = "connaught_place", workoutType = "weights", startTime = 6, endTime = 7, totalSeats = 100)true
addWorkoutSlot(centerName = "connaught_place", workoutType = "cardio", startTime = 7, endTime = 8, totalSeats = 150)true
addWorkoutSlot(centerName = "connaught_place", workoutType = "yoga", startTime = 8, endTime = 9, totalSeats = 200)true

addWorkoutSlot(centerName = "bandra_west", workoutType = "weights", startTime = 18, endTime = 19, totalSeats = 100)false
Reason: 18-19 is outside bandra_west timings (allowed: 7-10 and 19-22).

addWorkoutSlot(centerName = "bandra_west", workoutType = "swimming", startTime = 19, endTime = 20, totalSeats = 100)false
Reason: "swimming" is not an allowed workout type for bandra_west.

addWorkoutSlot(centerName = "bandra_west", workoutType = "cardio", startTime = 19, endTime = 20, totalSeats = 20)true
addWorkoutSlot(centerName = "bandra_west", workoutType = "weights", startTime = 20, endTime = 21, totalSeats = 100)true
addWorkoutSlot(centerName = "bandra_west", workoutType = "weights", startTime = 21, endTime = 22, totalSeats = 100)true

Example 2: View Availability (Sorted by Start Time)

viewWorkoutAvailabilityByStartTime(workoutType = "weights", centerName = "*")
Output:
  • "connaught_place|weights|6|7|100"
  • "bandra_west|weights|20|21|100"
  • "bandra_west|weights|21|22|100"
Reason: Filter by "weights", include all centers, sorted by startTime ASC.

Example 3: Book Session + Verify Updated Seats + Prevent Double Booking

bookSession(userId = "vaibhav", centerName = "connaught_place", workoutType = "weights", startTime = 6, endTime = 7)"BOOKED"
Reason: Slot exists and has seats; one seat is consumed.

viewWorkoutAvailabilityByStartTime(workoutType = "weights", centerName = "*")
Output:
  • "connaught_place|weights|6|7|99"
  • "bandra_west|weights|20|21|100"
  • "bandra_west|weights|21|22|100"
Reason: connaught_place 6-7 seat count decreased from 100 to 99.

bookSession(userId = "vaibhav", centerName = "connaught_place", workoutType = "weights", startTime = 6, endTime = 7)"ALREADY_BOOKED"
Reason: Same user cannot book the same slot twice.

Example 4: View Availability (Sorted by Seats Available)

viewWorkoutAvailabilityBySeatsAvailable(workoutType = "weights", centerName = "bandra_west")
Output:
  • "bandra_west|weights|20|21|100"
  • "bandra_west|weights|21|22|100"
Reason: Filter by workoutType + centerName; both have equal seats, so we order in lexicographically ascending order.

Example 5: Cancel Restores Seat + Notify-Me Flow

(Setup a small seat slot to demonstrate full capacity)
addWorkoutSlot(centerName = "connaught_place", workoutType = "yoga", startTime = 18, endTime = 19, totalSeats = 1)true

bookSession(userId = "arjun", centerName = "connaught_place", workoutType = "yoga", startTime = 18, endTime = 19)"BOOKED"
bookSession(userId = "rohit", centerName = "connaught_place", workoutType = "yoga", startTime = 18, endTime = 19)"NO_SEATS"
Reason: Only 1 seat exists; after arjun books, the slot becomes full.

addToInterestList(userId = "rohit", centerName = "connaught_place", workoutType = "yoga", startTime = 18, endTime = 19)"INTEREST_ADDED"
Reason: Slot is full, so user can join interest list.

cancelSession(userId = "arjun", centerName = "connaught_place", workoutType = "yoga", startTime = 18, endTime = 19)"CANCELLED"
Reason: Booking removed; one seat becomes available. System should notify interested users (via logs).

notifyInterestedUsers(centerName = "connaught_place", workoutType = "yoga", startTime = 18, endTime = 19)
Output:
  • "NOTIFY|rohit|connaught_place|yoga|18-19"
Reason: rohit was in the interest list for that slot, so he gets notified when a seat frees up.

viewWorkoutAvailabilityByStartTime(workoutType = "yoga", centerName = "connaught_place")
Output:
  • "connaught_place|yoga|8|9|200"
  • "connaught_place|yoga|18|19|1"
Reason: Both yoga slots are listed for connaught_place, sorted by startTime.




Please use Laptop/Desktop or any other large screen to add/edit code.