-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5282a86
Showing
58 changed files
with
3,932 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
dist | ||
spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"env": { | ||
"es2021": true, | ||
"node": true | ||
}, | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/eslint-recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"eslint-config-prettier" | ||
], | ||
"parser": "@typescript-eslint/parser", | ||
"parserOptions": { | ||
"ecmaVersion": "latest", | ||
"sourceType": "module", | ||
"project": [ | ||
"./tsconfig.json" | ||
] | ||
}, | ||
"plugins": [ | ||
"@typescript-eslint", | ||
"eslint-plugin-prettier" | ||
], | ||
"rules": { | ||
"prettier/prettier": 2 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package-lock.json | ||
node_modules | ||
dist | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Ignore artifacts: | ||
dist | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"trailingComma": "es5", | ||
"tabWidth": 4, | ||
"semi": true, | ||
"singleQuote": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#### Table of Contents | ||
- [Introduction](#introduction) | ||
- [Technology Stack](#technology-stack) | ||
- [Project Setup and Running](#project-setup-and-running) | ||
- [Testing](#testing) | ||
- [Important Notes](#important-notes) | ||
- [Anatomy of storefront endpoints](REQUIREMENTS.md/#anatomy-of-storefront-endpoints) | ||
- [Products](REQUIREMENTS.md/#products) | ||
- [Users](REQUIREMENTS.md/#users) | ||
- [Orders](REQUIREMENTS.md/#orders) | ||
- [Cart](REQUIREMENTS.md/#cart) | ||
- [Dashboard](REQUIREMENTS.md/#dashboard) | ||
- [Database Schema](REQUIREMENTS.md/#database-schema) | ||
- [Data Shapes](REQUIREMENTS.md/#data-shapes) | ||
## Introduction | ||
This is a simple backend API for an online store to handle products, users, orders. It has different endpoints covering all CRUD operations. | ||
|
||
## Technology Stack | ||
![NPM](https://img.shields.io/badge/NPM-%23000000.svg?style=for-the-badge&logo=npm&logoColor=white) | ||
![TypeScript](https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white) | ||
![NodeJS](https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge&logo=node.js&logoColor=white) | ||
![Express.js](https://img.shields.io/badge/express.js-%23404d59.svg?style=for-the-badge&logo=express&logoColor=%2361DAFB) | ||
![Jasmine](https://img.shields.io/badge/jasmine-%238A4182.svg?style=for-the-badge&logo=jasmine&logoColor=white) | ||
![Postgres](https://img.shields.io/badge/postgres-%23316192.svg?style=for-the-badge&logo=postgresql&logoColor=white) | ||
![JWT](https://img.shields.io/badge/JWT-black?style=for-the-badge&logo=JSON%20web%20tokens) | ||
![ESLint](https://img.shields.io/badge/ESLint-4B3263?style=for-the-badge&logo=eslint&logoColor=white) | ||
|
||
This API built with | ||
- `Node.js`: Back-end JavaScript runtime environment. | ||
- `Express`: Node.js web application framework. | ||
- `Typescript`: Is JavaScript with syntax for types. | ||
- `NPM`: As a package manager. | ||
- `PostgreSQL`: As a Database. | ||
- `db-migrate`: For migrations. | ||
- `jsonwebtoken(JWT)`: For users authorization | ||
- `Jasmine`: For Unit testing. | ||
- `ESLint`: JS linting tool. | ||
- `prettier`: Code formatting tool. | ||
|
||
## Project Setup and Running | ||
By following the instruction below , you will be able to set up and run the project locally on your machine. | ||
|
||
#### 1. Install project dependencies | ||
``` | ||
npm install | ||
``` | ||
#### 2. Database Setup | ||
You have to create two databases one for development and another for testing. | ||
|
||
- open your shell and connect to the default postgres database via psql | ||
``` | ||
psql -U postgres | ||
``` | ||
- create the dev and test database | ||
``` | ||
CREATE DATABASE storefront; | ||
CREATE DATABASE storefront_test; | ||
```` | ||
- create a new user | ||
``` | ||
CREATE USER storefront_user WITH PASSWORD 'pass123'; | ||
``` | ||
- grant all privileges on the storefront and storefront_test databases to the new user | ||
``` | ||
\c storefront | ||
GRANT ALL PRIVILEGES ON DATABASE storefront TO storefront_user; | ||
\c storefront_test | ||
GRANT ALL PRIVILEGES ON DATABASE storefront_test TO storefront_user; | ||
``` | ||
#### 3. Environment Setup | ||
You need to create `.env` file in the root directory and add these environment variables to it. | ||
``` | ||
PORT=3000 | ||
POSTGRES_HOST=127.0.0.1 | ||
POSTGRES_DB=storefront | ||
POSTGRES_TEST_DB=storefront_test | ||
POSTGRES_USER=storefront_user | ||
POSTGRES_PASSWORD=pass123 | ||
ENV=dev | ||
|
||
BCRYPT_PASSWORD=spreak-friend-and-enter | ||
SALT_ROUNDS=10 | ||
TOKEN_SECRET=NEWStoreFrontTKN! | ||
|
||
TEST_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjQ1NDk2OTc0fQ.mE1P84E0XJZytIkjs8e41yNFMbja0hdOPVgmKpxuOYs | ||
``` | ||
#### 4. Run the migration | ||
Use this command to run the migrations, to create the tables in the database. | ||
``` | ||
db-migrate up | ||
``` | ||
#### 5. Running the App | ||
Use this command to run the app in watch mode. | ||
``` | ||
npm run watch | ||
``` | ||
- The app will run on port 3000 | `localhost:3000` | ||
________________________________________________________________________________________________________________________________ | ||
### Testing | ||
Use this command to run the unit tests with jasmin. | ||
``` | ||
npm run test | ||
``` | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
#### Table of Contents | ||
- [Introduction](README.md/#introduction) | ||
- [Technology Stack](README.md/#technology-stack) | ||
- [Project Setup and Running](README.md/#project-setup-and-running) | ||
- [Testing](README.md/#testing) | ||
- [Important Notes](#important-notes) | ||
- [Anatomy of storefront endpoints](#anatomy-of-storefront-endpoints) | ||
- [Products](#products) | ||
- [Users](#users) | ||
- [Orders](#orders) | ||
- [Cart](#cart) | ||
- [Dashboard](#dashboard) | ||
- [Database Schema](#database-schema) | ||
- [Data Shapes](#data-shapes) | ||
---------------------------------------------------------- | ||
#### Important Notes | ||
##### 1. You need to set Authorization Variable with the HTTP header As below: | ||
```Authorization```: ```bearer <token>``` | ||
##### 2. You can use any API testing tool like `Postman` to test the endpoints. | ||
```You will find postman collection file in the project repository, it has all endpoints setup for quick testing``` (__preferred to use it__) | ||
##### 3. To test the project without any Access Denied messages, create an admin user as he has all the privileges, so set the `user_role:'admin'` | ||
------------------------------------------------------------- | ||
## Anatomy of Storefront Endpoints | ||
|
||
<h4>Products</h4> | ||
-> product = { name: string, price: number, describtion: string, category:string } <br> | ||
-> [{product}] : list of product objects <br> <br> | ||
|
||
| Method | URL | Description | Access | Request Header | Request Body | Response Body | | ||
| -------- | ---------------------------------------------| --------------------------------| ------- | -------------- | ------------- | --------------- | | ||
| `GET` | `/store/products` | Retrieve all products. | Anyone | | | [{id+product}] | | ||
| `GET` | `/store/products?category=[CategoryName]` | Retrieve products by category. | Anyone | | | [{id+product}] | | ||
| `GET` | `/store/products/:productId` | Get product details by id. | Anyone | | | {id+product} | | ||
| `POST` | `/store/products` | Create new product. | Admin | Authorization | {product} | {id+product} | | ||
| `PUT` | `/store/products/:productId` | Update product by product id | Admin | Authorization | {product} | {id+product} | | ||
| `DELETE` | `/store/products/:productId` | Delete product by product id | Admin | Authorization | | {id+product} | | ||
________________________________________________________________________________________________________________________________ | ||
|
||
<h4>Users</h4> | ||
-> user = { first_name: string, last_name: string, email: string, password: string, user_role: string } <br> | ||
-> [{user}] : List of user objects <br> | ||
-> login-data = {email: string, password: string } <br> <br> | ||
|
||
| Method | URL | Description | Access | Request Header | Request Body | Response Body | | ||
| -------- | --------------------------| --------------------------------------------| ------------------- | -------------- | ------------- | -------------- | | ||
| `POST` | `/store/users` | Create a new user. | Anyone | | {user} | JWT Token | | ||
| `POST` | `/store/users/login` | Use to login a user by email and password. | Anyone | | {login-data} | JWT Token | | ||
| `PUT` | `/store/users/:userId` | Update user data by id. | login-User / Admin | Authorization | {user} | JWT Token | | ||
| `GET` | `/store/users/:userId` | Retrieve user data by id. | login-User / Admin | Authorization | | {id+user} | | ||
| `GET` | `/store/users` | Retrieve all users. | Admin | Authorization | | [{id+user}] | | ||
| `DELETE` | `/store/users/:userId` | Delete a user by id. | Admin | Authorization | | {id+user} | | ||
________________________________________________________________________________________________________________________________ | ||
|
||
<h4>Orders</h4> | ||
-> order = { status:string, user_id: string} <br> | ||
-> [{order}] : List of order objects <br><br> | ||
|
||
| Method | URL | Description | Access | Request Header | Request Body | Response Body | | ||
| -------- | -----------------------------------------| -------------------------------------| ------------------- | -------------- | ------------- | -------------- | | ||
| `POST` | `/store/orders/user/:userId` | Create new order | login-User / Admin | Authorization | {order} | {order} | | ||
| `GET` | `/store/orders/user/:userId` | Get user orders by user id | login-User / Admin | Authorization | | [{order}] | | ||
| `GET` | `/store/orders/:ordertId/user/:userId` | Get specific order for specific user | login-User / Admin | Authorization | | {order} | | ||
| `GET` | `/store/orders/current/user/:userId` | Retrieve user current order. | login-User / Admin | Authorization | | {order} | | ||
| `GET` | `/store/orders/active/user/:userId` | Retrieve user active order. | login-User / Admin | Authorization | | {order} | | ||
| `GET` | `/store/orders/processed/user/:userId` | Retrieve user processed orders. | login-User / Admin | Authorization | | [{order}] | | ||
| `GET` | `/store/orders/completed/user/:userId` | Retrieve user completed orders. | login-User / Admin | Authorization | | [{order}] | | ||
| `GET` | `/store/orders` | Retrieve all orders. | Admin | Authorization | | [{order}] | | ||
| `PUT` | `/store/orders/:orderId` | Delete one orders by id. | Admin | Authorization | {order} | {order}} | | ||
| `DELETE` | `/store/orders/:orderId` | Delete one orders by id. | Admin | Authorization | | {order} | | ||
________________________________________________________________________________________________________________________________ | ||
|
||
<h4>Cart</h4> | ||
-> cart = { productId: string, quantity: string } <br> | ||
-> CartReturn = { id: number, quantity: number, order_id: string, product_id: string } <br> <br> | ||
|
||
| Method | URL | Description | Access | Request Header | Request Body | Response Body | | ||
| -------- | -------------------------------------------| -----------------------------| -------------------| -------------- | ------------ | -------------- | | ||
| `POST` | `/store/cart/user/:userId/order/products` | Add product to the user cart | login-User / Admin | Authorization | {cart} | {CartReturn} | | ||
________________________________________________________________________________________________________________________________ | ||
|
||
<h4>Dashboard</h4> | ||
-> PopularProducts = { name: string, total_quantity:number, number_of_orders: number } <br> | ||
-> UsersWithOrders = { firstName: string, lastName: string, orders_mount :number } <br> | ||
-> ProductsInOrders = { name: string, price: number, category: string, total_quantity:number, order_id: string } <br> <br> | ||
|
||
| Method | URL | Description | Access | Request Header | Request Body | Response Body | | ||
| -------- | ---------------------------------------------| -------------------------------------| -------| -------------- | -------------| -------------- | | ||
| `GET` | `/store/dashboard/five-top-popular-products` | Retrieve top 5 popular products. | Admin | Authorization | | {PopularProducts} | | ||
| `GET` | `/store/dashboard/products-in-orders` | Retrieve products included in orders.| Admin | Authorization | | {UsersWithOrders} | | ||
| `GET` | `/store/dashboard/users-with-orders` | Retrieve users that made orders. | Admin | Authorization | | {ProductsInOrders}| | ||
|
||
________________________________________________________________________________________________________________________________ | ||
|
||
## Database Schema | ||
|
||
``` | ||
| Table Name | Columns Name | Data Type | Comments | | ||
| ------------------ | ------------------ | -------------- | -------------------------------- | | ||
| `products` | `id` | `SERIAL` | [PRIMARY KEY] | | ||
| | `name` | `VARCHAR(100)` | | | ||
| | `price` | `integer` | | | ||
| | `description` | `text` | | | ||
| | `category` | `VARCHAR(64)` | | | ||
| ------------------ | ------------------- | -------------- | ------------------------------- | | ||
| `users` | `id` | `SERIAL` | [PRIMARY KEY] | | ||
| | `first_name` | `VARCHAR(100)` | | | ||
| | `last_name` | `VARCHAR(100)` | | | ||
| | `email` | `VARCHAR` | | | ||
| | `password_digest` | `VARCHAR` | | | ||
| | `user_role` | `VARCHAR` | | | ||
| ------------------ | ------------------- | -------------- | -------------------------------- | | ||
| `orders` | `id` | `SERIAL` | [PRIMARY KEY] | | ||
| | `status` | `VARCHAR(15)` | | | ||
| | `user_id` | `bigint` | [foreign key to users table] | | ||
| ------------------ | ------------------- | -------------- | --------------------------------- | | ||
| `order_products` | `id` | `SERIAL` | [PRIMARY KEY] | | ||
| | `quantity` | `integer` | | | ||
| | `order_id` | `bigint` | [foreign key to orders table] | | ||
| | `product_id` | `bigint` | [foreign key to products table] | | ||
``` | ||
|
||
________________________________________________________________________________________________________________________________ | ||
|
||
## Data Shapes | ||
#### Product | ||
id: number; | ||
name: string; | ||
price: number; | ||
description: string; | ||
category: string; | ||
|
||
#### User | ||
id: number; | ||
first_name: string; | ||
last_name: string; | ||
email: string; | ||
password: string; | ||
user_role: string; | ||
|
||
#### Orders | ||
id: number; | ||
status: string; | ||
user_id: string; | ||
quantity: number; | ||
product_id: string; | ||
|
Oops, something went wrong.