To simplify, let's say the users can enter the name of the physical activity they did. They can also set goal and update manually their progress in this goal. Let's not include any payment.
Main objects:
Access patterns:
Considering mutability, goals and physical activities can be modified / deleted.
We can target around 2 million daily active users.
Probably more reads than writes (maybe ratio 100:1)
Probably at most 10 writes per user per day (updates to goals / physical activities / progress). Update progress endpoint is probably the most called endpoint
20 million writes / day => 200 writes / second which is completely ok with a sql db
For the storage, only textual data so maybe 1kb on average per write. => 20 GB /day => 1TB / year (it may be overestimated).
For now let's focus on the creation and not consider the mutability
createActivity():
POST /activity
body: {name, timeslot}
res=> activity_id
listActivities():
GET /activity?limit={limit}&offset={offset}
createGoal():
POST /goal
body: {name, freq}
res=> goal_id
listGoals():
GET /goal?limit={limit}&offset={offset}
createProgress():
POST /progress/{goal_id}
body: {current_progress}
res=> progress_id
If we consider mutability, we must add endpoints to update/delete. But it follows basically the same idea
We do want consistency so we will use a SQL database. Because users can only access their data, it makes sense to shard by user id / geographical region (people usually don't move too much) , which would still allow to scale.
For the design itself,
3 services: goal tracking service, progress service, activity service.
Client is directed to an API gateway that redirects to the correct service. For most read workloads, we can have a cache. By default cache could have read data for the current day.
On write, we could write to cache and to a queue. Then a worker should take data from the queue and update the db to avoid overloading it during peak activity. Or we could do a write through cache if we really need strong consistency
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?