d66 habit tracker

web development

2020

Tools: React, Typescropt, Express, MongoDB

Disclaimer: this is a Bootcamp project.

d66 is a web app that allows users to track their changing habits journey, while providing useful encouragement (or shaming) tips to help them along the way.

I built d66 as a final project for a Full Stack development Bootcamp I took in late 2020 as a way to stretch my Back End muscles. I wasn’t feeling very challenged by the projects I was working on full time back then, and I felt the need of adding some new tricks into my tech stack.

d66 mobile view

d66 is built on a React + Typescript front end, leveraging the MaterialUI library for speed. I also used the React Date picker library since date input was a crucial part of the app but I didn’t have the time to build a custom component for that. I wanted to focus on building the API and taking the time to understand the data structure to make the app work correctly.

The application back end uses an Express server to interact with a MongoDB database. By leveraging Mongoose I could communicate with the database and perform data modelling in a JavaScript-oriented logic that felt more natural. I came up with a simple structure with Goals, Entries and Users collections, represented in this early sketch:

database collections sketch

I implemented node-jsonwebtoken to store and retrieve a logged-in state. I exposed it in a middleware function called verifyToken that is called before entering each route:

 //tokenService.js
 const verifyTokenService = (token) => {
  let user

  jwt.verify(token, KEY, (err, decodedToken) => {
    if (err) {
      throw err
    }

    user = decodedToken
  })

  return user
}
// router
const router = express.Router()
router.use(verifyToken)
d66 desktop timeline view

I also used the bcrypt.js library to salt passwords and store them securely in the database. Here’s the implementation as a pre-save hook on the Users collection:

// Pre Save Hooks
UserSchema.pre('save', async function (next) {
  const user = this
  try {
    if (user.isModified('password') || user.isNew) {
      user.password = await bcrypt.hash(user.password, 12)
    }
    next()
  } catch (err) {
    // ...
  }
})

I deployed the whole application using Heroku. You can run the app live here and see the source code here.