- read

Portfolio Sharing— Expense Tracker

Yu-Ming, CHANG (he/him) 2

I am proudly excited, and scared at the same time, to share with you my first full-stack project in my portfolio.

  • Proudly excited because today is the day that I finally generate enough confidence to believe myself qualified as a web developer
  • Scared because when looking at this project, I could discover so many opportunities to improve it
  • Also, there are certainly knowledge that I’m not aware of but would like to pick up. So maybe you could share your thoughts with me in the comment, and be my sunshine of the day!

Expense Tracker & GitHub Repo

I have been tracking all my expenses for about 3 years. It is a piece of cake for me to imagine what a user might want for such a tool; hence, expense tracker seems like a good starting point.

A screenshot of login page
A screenshot of records page


  1. The user interface is still in traditional Chinese. It will be translated into English by end of June, 2022
  2. This project is active, meaning it is highly likely to change as time goes by
  3. Heroku link stays active as long as it is in my portfolio. If you find it no longer accessible, it means I replace it with other project. For a more up-to-date projects, please visit my portfolio

Technology Used & Developing Process

The tech structure of this project is rather simple:

  • First, Express is used to quickly create server and set up routes
  • Second, Mongoose is used to set up Schema and interact with MongoDB Atlas
  • Third, Handlebars is used to enable server side rendering, Bootstrap is used to make the interface prettier, and Handlebars helper function is used to improve user experience (we’re all busy, so don’t make me type a thing)
  • Then, Passport is included to create user system; bcrypt is in place to secure private data
  • Then, connect-flash is imported to display alert message according to different user behavior
  • Then, seeder is created to feed database with testing files
  • Lastly, reusable function is refactored to increase readability

Reflection by Self Interviewing

What technology do I feel the most familiar with?

I am getting more and more comfortable setting up web server using Express framework. I could imagine vividly how a request travels from client to server, getting through middleware in exact order I write, and then send response back to client.

By seeing this request-response process, it makes more sense to me why a middleware is placed at a certain place, and how handlebars could read some properties even when I am not sending any context object when rendering. (hint: handlebars is reading response to render) The latter could help me design a better view template.

And what about the least?

At first, I thought connect-flash was working in a mysterious way. I was not sure how flash message could be passed through different modules. I was clouded by the method flash().

I later learned that the key is actually the request object in front of flash(). Express middleware is just a function adding side effects to request/response object. By seeing this truth, it helps me understand request/response cycle better.

(Here is my post explaining Express middleware in one minute, in case you’re interested in it)

What are the obstacles in the way? How do I overcome them?

I’ll just name a few obstacles:

  • to format a date type from Mongo Document into YYYY-MM-DD so that the data could be rendered as expected in home page, and as default value when editing a record.
    I read MongoDB and Mongoose documentation and learned about aggregation(). However, it is a bit different from a typical mongoose Model.find() or Model.create. If I want to use aggregation I need to rewrite current promised-based chaining into async/await to get its returned result. I figured it is too much an effort to refactor so just write a simple helper function to return desired date string.
  • I’d like all the information pre-filled in the form when edit existing document. The pain point is select and option. One of the option needs to be dynamically selected based on its input.
    I looked into Handlebars documentation and found out that we could combine {{#if}} with custom helpers to create more complex condition in view template. It works like a charm.
  • There is a simple client JavaScript served via express.static(). I tried several times but client did not receive any script from server to execute.
    Well, it was a beginner’s mistake. I forgot to add <script> in the html file. I just suddenly recall this after several failed attempts.

For all those obstacles, which one do I enjoy the most?

aggregation makes me really excited about how the data could be cooked at database before returning; however, it isn’t used in this project.

Therefore, I would say the most enjoyable one is Handlebars Custom Helpers. Because it extends my capability to render with greater flexibility. I feel leveling up.

Any other takeaway?

I found using render directly in a route will not change display URL, but leaves user in the original route. It might cause some unwanted confusion.

For example, GET /users/register will render a register form. When submit that form, it makes more logical sense to define the route to be POST /users . However, we always want to perform some kind of form data validation at server side, when there is something wrong, we would redirect user back to register form with their previous input as default value. If we design the route to be POST /users/register then we could render register page directly in POST route, and pass user input to it very easy.

If we design it as POST /users , then if we render register page directly, user URL stays in /users instead of /users/register. The major downside of using POST /users is that we need figure out another way to pass user input to GET /users/register.

Not a big deal, use POST /users/register just saves some development pain without giving up much route readability.

Next Step

Here are what I planned to refine this project:

  1. make different views, by month and by category, and use aggregate to make the calculation happened at database
  2. implement forgot password and change password
  3. refactor current code
  4. make a button to switch content display language