Skip to content

A web app for creating interval timers. Made with NodeJS, Express, Sequelize & PostgreSQL

Notifications You must be signed in to change notification settings

saulthebear/intrvl

Repository files navigation

INTRVL. ⏱

Intrvl is a web app that allows users to create custom interval timers.

Timers consist of named sections, and users can skip to the next / previous sections. Text-to-Speech is also used to give the user the option of having an announcement spoken when the timer starts and ends, as well as announcing the name of each section as it starts. Users can also choose to make a timer public, so that it can be used by others, and users can make lists of their favorite timers (their own or other users' public timers) so they can get to them quickly.

⏱ Try it out!

Table of contents

Screenshots

  • Timer Page
    • Timer Screenshot
  • Profile Page
    • Profile Page Screenshot
  • Public Timers Page - Mobile Layout
    • Mobile Layout Screenshot - Public Timers Page

Overview

The challenge

Project requirements:

  • A full-stack application
  • Have complete restful routes for at least one model (GET, POST, PUT, DELETE)
  • Utilize an ORM to create and interact with the database

Personal Goals:

  • Minimum Viable Product (MVP)
    • Allow users to sign up / login
    • Allow users to create / edit / delete timers
    • Allow users to view all their timers and use each
    • Use a Text-to-Speech API to announce when a timer is starting and ending
  • Stretch Goals:
    • Allow timers to be repeated
    • Allow timers to have 'sections'
      • Allow sections to be rearranged
      • Allow sections to be repeated
    • Allow users to add tags (categories) to timers
    • Allow user to set some timers as public, and others as private
    • Allow users to have timer section names be announced when that section starts
    • Styling
      • Use TailwindCSS
      • Responsive design
      • Dark mode
    • Allow users to duplicate an existing timer to use it as a template

Links

Details

Built with

  • Backend: NodeJS, PostgreSQL, Sequelize, EJS
  • Frontend: TailwindCSS, Flowbite, JavaScript
  • Web Speech API

  • The timer functionality was built with JavaScript, and relies on a fixed time-step engine, built for my previous project Bodhi's Dreamworld.
  • Text-to-Speech relies on the native web speech synthesis API: SpeechSynthesis
  • The app interacts with the PostgreSQL database through the Sequelize ORM
  • Views are built with the Embedded JavaScript (EJS) templating language, while styling was done with TailwindCSS (a utility-first CSS framework) and Flowbite (an open-source library of components built with TailwindCSS). Ionicons (open-source icons library) was used to add SVG icons. Typed.js was used for a text animation on the home page
  • Winston and Chalk were used for logging. Winston allowed the creation of different logging outputs, depending on environment logging level. For example, errors are logged in a separate file, so they can be easily found, and in development all levels of logging are output to the console.
  • connect-flash was used to show flash messages to users upon redirect, to let them know if an action succeeded or to inform them why an action had failed.

Installation Instructions

  • To run this app, clone it (or fork and clone) and follow these steps:
    • Install dependencies using npm
    • Create a .env file and add an encryption key
    • Create the database
    • Start the app in development mode, by running npm run start:dev
npm i

echo "ENC_KEY=[Random Key]" >> .env

sequelize db:create

npm run start:dev

Entity Relationship Diagram (ERD)

ERD

Routes

HTTP Verb URL Pattern Action Description
GET / Index Describe app, show nav links
GET /login New Show login form
POST /login Create Log user in, by setting a cookie
GET /logout Destroy Log user out, by deleting a cookie
POST /favorites/:timerId Create Add timer to favorites
DELETE /favorites/:timerId Destroy Remove timer from favorites
GET /users/new New Show form to sign up
POST /users Create Create a new user
GET /users/:id Show Show user profile and their timers
GET /users/:id/edit Edit Show form to update user profile
PUT /users/:id Update Update profile / credentials
DELETE /users/:id Destroy Delete user's account
GET /users/:id/favorites Index Show users favorites
GET /timers Index Show all public timers
GET /timers/:id Show Show a specific timer
GET /timers/new New Show form to create a new timer
POST /timers Create Create a new timer
GET /timers/:id/edit Edit Show form to edit a timer
PUT /timers/:id Update Update a timer
DELETE /timers/:id Destroy Delete a timer
POST /timers/:timerId/sections Create Create a new timer section
PUT /timers/:timerId/sections/:sectionId Update Update a section
DELETE /timers/:timerId/sections/:sectionId Destroy Delete a timer section
POST /timers/:timerId/tag/:tagId Create Associate a tag with a timer
DELETE /timers/:timerId/tag/:tagId Destroy Remove association between a tag and a timer
GET /tags/new New Show form to create a tag
POST /tags Create Create a new tag
GET /tags/:id Index Show all timers associated with a tag
GET /tags/:id/edit Edit Show form to edit a tag
PUT /tags/:id Update Update a tag
DELETE /tags/:id Destroy Delete a tag

What I learned

  • This project allowed me to strengthen my skills in planning and designing an Entity Relationship Diagram, and then implementing that design
  • I also learned how to use the SpeechSynthesis API. I had originally planned to use an external TTS engine, such as the Google Cloud Text-to-Speech API, however the complexity of needing to generate the speech on the backend, store MP3 files, and then send those to the client, seemed unnecessary given the widespread browser support for speech synthesis. In the future, I plan to continue building on this project by allowing the user to select the type of voice they would like to use, as well as the pitch, tone, and speed.
  • This project allowed me to continue practicing my skills in creating interactive elements in JavaScript and HTML. Building the timer component and allowing users to skip forward / backwards through timer sections was a fun challenge.
  • I learned how to use throttling for better performance. In the view showing the timer, there is a function that fires on window resize events, to ensure the timer sections are displayed at the correct width; to ensure this function isn't called too many times as the user is resizing their window, throttling is used so that it runs at most every 500ms.
  • I learned how to use Chai and Mocha for testing, along with supertest and FakerJs. I have tests for the user model, for example, which ensure the methods for hashing and verifying passwords are working correctly. I had originally planned on using a Test Driven Development approach for this project, however, considering that this is a monolithic full-stack application and the routes directly send HTML to the client (rather than JSON), the complexity of learning to test views (essentially performing integration testing, rather than unit testing) in the tight time frame of this project was too much. In the end, I only wrote tests for a few models.
  • On the design front, I learned about Neubrutalism and tried to use this style for the app.

Resources referenced

Author

About

A web app for creating interval timers. Made with NodeJS, Express, Sequelize & PostgreSQL

Topics

Resources

Stars

Watchers

Forks