Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohamed-Hafez24 committed Feb 27, 2022
0 parents commit 5282a86
Show file tree
Hide file tree
Showing 58 changed files with 3,932 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
spec
27 changes: 27 additions & 0 deletions .eslintrc.json
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
}
}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package-lock.json
node_modules
dist
.env
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ignore artifacts:
dist
node_modules
6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": true,
"singleQuote": true
}
107 changes: 107 additions & 0 deletions README.md
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
```
148 changes: 148 additions & 0 deletions REQUIREMENTS.md
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;

Loading

0 comments on commit 5282a86

Please sign in to comment.