-
Clone the repo
git clone git@github.com:civilcoder55/note-taking-app.git
or
git clone https://github.com/civilcoder55/note-taking-app.git
-
Change directory
cd note-taking-app
-
update the env file with proper Leave it if you want, default values should work
cp .env.example .env
-
ensure run.sh is executable
chmod +x run.sh
-
Build images and run containers
docker-compose up -d
-
Create and Sync database (already run with container up)
docker exec -it note-taking-node npm run db:sync
-
Access API at
http://localhost:3000/v1/docs
-
Access docker logs
docker logs -f note-taking-node
-
To run test
docker exec -it note-taking-node npm run test
-
Clone the repo
git clone git@github.com:civilcoder55/note-taking-app.git
or
git clone https://github.com/civilcoder55/note-taking-app.git
-
Make sure you have MySQL database and Redis server installed
-
Change directory
cd note-taking-app
-
Update the env file with proper variables
cp .env.example .env
-
Install npm dependencies
npm install
-
create and Sync database
npm run db:sync
-
To run tests
npm run test
-
To run app
npm start
-
Access API at
http://localhost:3000/v1/docs
- You can access swagger API docs at http://localhost:3000/v1/docs
- or you can use the Postman collection which includes all the different response examples
- Click on the image to download the collection
- used Sequlize orm with MySQL database.
- defined two models for Note and User.
- used sync to migrate and update the status of database tables and schema, I could used migration files as best practice to keep the state of the database changes but for simplicity I went for the sync command
- i could use models associations and query notes on user instance but i keep it simple by query notes with user_id
- users table with id as primary key and a unique index on emails
- notes table with id primary key and user_id as foreign key and unique composite index on (user_id, title)
- implemented the following
Method | URL | Description |
---|---|---|
GET |
/v1/auth/me |
Retrieve logged in user data. |
POST |
/v1/auth/login |
Login with email and password. |
POST |
/v1/auth/register |
Register as new user. |
Method | URL | Description |
---|---|---|
GET |
/v1/notes |
Retrieve all user notes. |
GET |
/v1/notes/:id |
Retrieve user note by id. |
POST |
/v1/notes |
Create a new note. |
PATCH |
/v1/notes/:id |
Update a note. |
DELETE |
/v1/notes/:id |
Delete a note. |
-
used Redis to cache most accessed notes
-
used read through strategy
In a real-world scenario, I will handle cache in more smart ways, like adding expiring time or setting max memory for say 100 mb and set evection policy allkeys_lru to delete lease recently used notes
- used JWT simple tokens with an expiration time, to handle authentication in a stateless manner
In a real-world scenario, I will go for short_life access tokens and long_life refresh tokens, for example, using passport lib, it's more secure and standarized
- For logout, I didn't implement it as it is not part of the assessment scope
In real world scenario I will handle it by invoking the token either by keeping its state in the database and checking for existence on validate or remove it on logout If I need to keep it stateless and don't keep track of tokens, all I need to do is store only blacklisted tokens, When validating check if not blacklisted and when logout add a token to the blacklist store (redis for example)
- Used Joi lib to define validation schemas
- Defined a validator middleware to validate schemas against request body, params, and queries
- I create a Dockerfile for the application's main image, it is a node image with installed npm dependencies and application data
- used Redis' latest official image
- used MySQL's latest official image
- Create a docker-compose file for the stack to run 1 container of each image, two named volumes for datastores data, one bridge network for all stack
- created bash script to wait for mysql server ready then sync database and run nodejs server
- I used Jest to write unit and integration tests
-
you can see coverage report at coverage/index.html after running
npm run coverage
or
docker exec -it note-taking-node npm run coverage
- I used GitHub actions to write a simple ci pipeline to ensure code linting and pass tests
- I didn't write a cd pipeline, I couldn't find the proper environment or server to deploy (free Heroku Dynos are gone 😭)
-
singleton pattern
-
Node modules by default implement a singleton pattern, it caches the module on the first import/require then uses the same instance on every upcoming import/require https://nodejs.org/api/modules.html#caching
-
So we don't actually need to apply this pattern for say logger but let's rebuild it to implement the actual pattern I rebuilt it (but not used) in src/config/singletonLogger.js and covered both singleton and commonJs modules with two test cases
-
-
Factory method pattern https://github.com/civilcoder55/note-taking-app/commit/f7e7a833fb0510d6077392a63850ab863a61bc7d
- I didn't find a need to do the factory method but I made some edits to make a proof of concept of the pattern
- First, i added two new columns to the notes table to distinguish between work and personal notes
- then added data object classes for each work and personal that both inherit from note to extend shared behavior
- then added note factory to return the correct dto based on the type
- then consumed this factory in the note create and update service to return correct data based on note type before persisting it on the database
- Node (v20.5)
- Express (4.17)
- MySQL (8.0)
- Redis (7.0)
- Read and analyze task doc
- boilerplate and init new express app and setup initial configs
- dockerize application stack
- setup mysql database
- create database models and sync them
- add logger
- create users register/login API endpoints
- Create user notes API endpoints
- add caching for notes endpoint
- Add swagger and postman documentation
- Write unit and integration tests using jest
- add a singleton design pattern
- add factory design pattern
- optimize and refactor the code
- create CI pipeline using GitHub actions
- finalize readme file