How I competed at Imperial's hackathon by creating a fitness app
I'm Jaafar, an EIE student at Imperial College and SWE at Terra. Earlier this month, I participated in ICHack 22, one of the largest UK hackathons hosted, by Imperial students! Over a weekend, participants had to build something... cool.
Submissions ranged from web-based products to hardware or VR applications! These would then be qualified for and judged in one of the various prize categories (educational product, entertainment product, etc...).
We had to build something within a few hours, so my friend and I went with the Entrepreneurial category and focused on a health and fitness product.
The Idea: Hubby
My friend has an Apple Watch, and I have a Fitbit. We can track workouts and calories, set goals, and even get nudges to complete our daily targets. However, each device's data and insights are isolated in their own ecosystem, which makes it hard for us to compare our activities or track challenges together.
Thus, we started building Hubby.
Hubby is the hub for workout buddies. Bearing in mind we were targeting the Entrepreneurial category prize, we planned for Hubby's concept to have two main components:
- From a UX perspective, we focused on a gamification approach to build the user base. As a user, you can connect your fitness wearable, set fitness score targets, and compete with your friends in various score-driven challenges to earn vouchers and discounts.
- From a business perspective, vouchers and discounts would be sponsored by growing or existing fitness and health businesses e.g, a Huel protein shake or a PureGym day pass. These businesses would benefit from the access to a fitness-driven (and hence suitable) user base.
With a plan in place, we got started with hacking!
Building Hubby
To build Hubby, fitness data needed to be pulled and normalised from the different providers before we could even start building the user experience. Thus we decided to use Terra to save us time and focus more on the end-user actual features we had planned. Our system implementation started looking something like below, where Terra would provide us with the fitness data, and we would use it in Hubby to compute scores and present vouchers:
I want to show you in the next few paragraphs how we executed the plan and the different steps we took as devs to build Hubby. I will not go through the full implementation details as we had multiple iterations, but I will still show how got started and achieved a presentable MVP within 20 minutes! This will include a few dev steps for those interested in replicating Hubby's MVP.
MVP Implementation
We decided to start off with the backend, and went on using NodeJS. The backend had to handle users connecting their wearables, as well as pulling data from the different wearable providers.
We started with setting up an express server and creating the various endpoint in our index.js
entry file:
mkdir server && cd server npm install express body-parser dotenv
For a quick test, we ran the server with node index.js
, and a GET request on localhost:3000
returned "Hello from Hubby" successfully!
Connecting Wearables
To connect fitness wearables to Hubby, we decided to use Terra, as the full connection workflow was handled through their API. After signing up on Terra's dashboard and getting our API KEY and DEV ID credentials, we added those to the backend's .env
file and loaded them to the process environment using dotenv
:
With the credentials in place, we could now use Terra to connect the wearables to our backend. Terra's API comes with an NPM package terra-api
. After installing it, we initialised a connection instance:
npm install terra-api
To add a wearable, we had to use the API's widget session endpoint, which would automatically manage connecting user wearables. We added this endpoint to our backend with a list of providers we wanted to support:
We tested it with a curl localhost:3000/session
:
jaafarrammal@Sableur-Terra-Mac ~/D/D/T/server (master)> curl http://localhost:3000/session https://widget.tryterra.co/session/ff781505-87a6-465b-b7fe-55f71d611270
When we visit the URL provided by the API, we're able to select a provider and go through a connection flow!
BOOM! We had a connection flow to add wearables.
Pulling Fitness Data
The connection through the API would return us a unique user ID for that connection. With this user ID, we added an endpoint on the backend to pull fitness data using the API:
The fitnessSummary
and fitnessScore
functions are our custom implementations of computing a user fitness score or fitness summary. We decided to go with a simple summation, although a more scientific equations could have been formulated using additional metrics like sleep, activity intervals, or heart rate variability:
And voilà! We now had a backend which could connect user wearables and return fitness scores and summaries!
Frontend: Connecting User Wearable
For the frontend, we decided to use ReactJS. We started by setting up with:
npx create-react-app terra-hubby --template typescript
We also added bootstrap to our public/index.html
:
For the connection flow, we decided to simply cache the user IDs in a cookie instead of creating a full database (since it's a hackathon, and we needed to get things done quick). The Terra API to connect a wearable had an option to return the user ID in the session URL after the connection was completed. Our frontend flow became the following:
- Check if there is a user ID in the cookie
- If yes, simply pull the fitness summary and score from the backend
- If not, request and connection session from the backend, redirect the frontend to this session to connect a wearable, and write the user ID to a cookie when the connection is completed.
Our code on the frontend now looked something like this in App.tsx
:
It seems a lot, but here is what's happening in the App function:
- Within
useEffect
we check if the URL is coming from a successful connection session redirect. If so, it will contain a user ID that we can save in a cookie - We then attempt to load a user ID from the cookie
- If there isn't a user in the cookie, we request a connection session and redirect the user to that session. When they complete the login, they are redirect to
localhost:3000?user_id=....
which allows the code to fetch that user ID! - If there is a user in the cookie, we set it in the app state so we can pull data from the backend
Obviously, a more robust user auth handling could be added on the frontend side, but since it's a hackathon... nobody cares about error handling :)
Testing again! We visit localhost:3000
, and as expected we get redirected to the connection session, and once we finish connection, we could see the user ID on the screen!
Displaying User Data
With the user ID in hand, we could query the backend for the fitness data and display it.
In our App.tsx
, we created:
- A card function to display the data
- A handler to query the server for the fitness data
This ended up being out card function
Which gets us a card looking like this:
We then added the handler to query the data:
Finally, we added a card for each metric:
And here was the final result! Upon landing on the page, the user was redirect to connect their wearable. After connecting, they could see a fitness summary and their fitness score!
Hackathon outcome
After getting this simple flow working, we started added the other components (a nicer UI, a scores screen, a voucher screen, etc...). At the end, our app looked something like this:
Our final submission is also available to check on Devpost, with the following demo video!
Although we did not end up winning the Entrepreneurial category prize (ouch :/), the learning experience itself was personally worth it, alongside the mini-events at the hackathon such as midnight pizza, or 3 AM karaoke! And, of course, a no-sleep weekend followed by 14 hours of sleep the next day :)