High-Level Design
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
Components involved
- Mobile app
- Desktop browser app
- API gateway
- Our services can handle a maximum of 100 requests per second. We will enforce this using a sliding window mechanism that allows only 100 per second
- User management service
- Workout management service
- Reports management service
- Exercise management service
- Cache
- Database - 2 nodes ( sharding on the basis of userid )
Flows involved
- Add a user
- User signs up using mobile app ( sign up process is same for web browser also )
- We will use google oauth to simplify login and signup
- Once user signs up using google, we get a google_id from google's API. We use the google_id as the external_provider_id and this is stored in our database
- We get a code and our backend will exchange the code for token with Google's token endpoint
- We create a session token and this is passed around for any API that needs authentication
- The user is then showed a page with a form to fill in some basic details such as name, age, sex, date of birth, height, weight and username.
- We perform a validation if the username is already taken using a bloom filter or alternatively if we use a database like cassandra, it would use the same bloom filter internally to compare and set.
- This information is saved in our database
{
name: varadharajan,
age: 40,
sex: male,
date_of_birth: 07-05-1980,
height : 160,
height_units: cm
weight : 80
weight_units : kilograms,
extenal_provider_id : google_id,
userName: bigdaddyv
}
- Login as existing user
- User logs in using mobile app / web browser
- Login redirects to google authentication
- Once successfully authenticated, we get the google_id
- We look up based on the external_provider_id and see if user already exists, then we load his home page , else we redirect to create new user page
- Log a workout
- User adds a workout using the add workout button
- We start a new workout with a timer running that will be used to indicate the total time spent in that workout
- The workout page provides option to add new exercises
- We make call to the cache to fetch all the latest exercises ( paged way ). if cache miss occurs, we retrieve from the DB and update cache.
- User can add exercise and then we provide the option to add a set and the no. of reps for that set along with the weight if applicable. User can add how many ever sets he wants for that exercise
- Once user adds a new exercise, it means he is done with the previous exercise, we now call the update workout with the latest data and update the current workout. We don't do it for every set to prevent an overload and also we don't wait for the user to finish the entire workout so that in case the app is closed or crashes due to whatever reason, we will still retain the workout till the last completed exercise.
{
user_name: bigdaddyv,
date: 2024-09-04 13:42:22 +0530,
exercises :
[
{
exercise : "Hammer curl",
sets:
[
{
weight: 10,
reps: 12
},
{
weight: 10,
reps: 12
}
]
},
{
.
.
.
}
]
}
- Report
- Get workouts between a date range
- Reports are available from both web and app version
- The call comes from the UI to the API gateway, which then directs it to the Reports service. \
- Reports service will first try to load from the cache. The cache key would be a combination of the user_id and the date of the workout. this cache will be valid for one day since it's very likely that the next day the user might ask for a different day's report.
- In case of cache miss, Reports service then loads the data from the database. ( the database is sharded based on the userids. We will distribute the user id to the nodes using consistent hashing ). We also update the cache
- Reports are sent back to the UI for the user to verify
- Get vitals between date range
- This service is used by the user to understand how his vitals like Body fat percentage or weight have progressed over time.
- These vital readings are stored in the database. sharded based on the user id
- We try to retrieve from cache first. Here the cache key will be based on the date and the user id. Cache will be invalidated after a period of 10 days.
- If cache miss occurs, we will retrieve from DB and update cache and send the results to the user.
Offline flow
- When the user is offline, we continue to update the data on the device. The idempotency key is a combination of the user id and the start time of the workout. This will ensure that we update the right record once we are back online. Since we trigger the sync ourselves, we can ensure that there are no duplicate records being sent