Skip to content

TzeMingHo/E_commerce_app

Repository files navigation

e_commerce_app

// 1. list out the criteria of an e-commerce web-app

  1. A landing page (the shop interface)
  2. products shelf (recommended products)
  3. a filter bar on the side (categories)
  4. product brief info cards (photo, productName, price, add to cart)
  5. product detail page (photo, description, price)
  6. buyer selection control (+ / - for quantities, add to cart)
  7. a cart
  8. a shipping cart list with product details
  9. checkout page
  10. payment page
  11. order page
  12. a user icon
  13. register page
  14. user profile page
  15. user address book
  16. order history
  17. Admin page for editing products
  18. JWT table for login session

// 2. set up necessary files for the web app

  1. Create front-end (views) and back-end folders
  2. npm init at the root of e_commerce_app
  3. create a git repository and git init at the root
  4. create a .gitignore file and a .dockerignore file
  5. create a Dockerfile and a Jenkinsfile for CI/CD
  6. test the pipeline set up

// 3. create a routes folder, a module folder and a controller folder

  1. create a product.js in routes
  2. create a pool.js in module (the pool will have a isJenkins check for docker database and local database)
  3. create a .env and npm install dotenv --save
  4. input the DB variables and dockerized database variables in .env
  5. do a test for the route with a sample

// 4. create a server at the backend 6. create a server.js and require express 7. export the app from server.js to index.js 8. app.listen in index.js 9. create a postgres database with tools like dbdiagram 10. import the queries from diagram (Dbeaver) for local development and testing 11. Insert a testing data

// Goal: Set up a Jenkins container and PostgreSQL database container using docker-compose, // so Jenkins can run CI pipelines with the database and your app

  1. Make sure project structure looks something like this: E_commerce_app/ ├── backend/ │ ├── index.js │ ├── package.json │ ├── package-lock.json │ └── ... (your app code) ├── jenkins/ │ └── Dockerfile ├── docker-compose.yml ├── .dockerignore └── .gitignore

  2. Create Dockerfile for Jenkins (at the root, jenkins/Dockerfile) This custom Jenkins image installs required tools and sets up your app code:

    Get the latest jenkins version

    FROM jenkins/jenkins:lts

    switch to User root

    USER root

    Install Node.js and npm

    RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - &&
    apt-get install -y nodejs &&
    npm install -g npm

    Install required tools

    RUN apt-get update && apt-get install -y
    git
    python3
    python3-pip
    postgresql-client
    lsb-release
    curl

    Install Docker CLI

    RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc https://download.docker.com/linux/debian/gpg &&
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.asc]
    https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list &&
    apt-get update && apt-get install -y docker-ce-cli

    Switch back to Jenkins user

    USER jenkins

    Set working directory

    WORKDIR /app

    Copy package files and install dependencies

    COPY --chown=jenkins:jenkins package*.json ./ RUN npm ci

    Copy the rest of the app code

    COPY --chown=jenkins:jenkins . .

    Default CMD (Jenkins uses its own)

    CMD ["/bin/bash"]

// 5. create a dockerized database for CI/CD

  1. create a docker-compose.yml in the root of project (for getting a postgresql image from docker)
  2. set up the database environments and volumes for persisting data changes in the docker-compose.yml
  3. use a different port from 5432 like 5433 for the dockerized psql image
  4. run the image (docker-compose up -d) and the database will be running in a container
  5. try to connect the database from Dbeaver (input the environment from docker-compose.yml)
  6. try to seed the database with a test with a seed.js
  7. if the database can be seeded, try to connect from the app
  8. connect the database from Jenkins for testing

// 6. Jenkins should have preinstalled elements

  1. node.js, git, python3, python3-pip, postgresql-client, express, jest, supertest, bcrypt (adding those in the dockerfile while creating the jenkins image)

// 7. connect Jenkins to Postgresql's network (database)

  1. docker network ls (checking the names of network)
  2. docker network connect e_commerce_app_postgres-net jenkins-blueocean (connect the database network to the jenkins container)
  3. docker network inspect e_commerce_app_postgres-net (verify the network connection. both jenkins-blueocean and postgres-local should be listed under Containers)
  4. docker exec -it jenkins-blueocean psql -h postgres-local -U [username] -d [database] (test the database connection, enter the env password, if successful, will be logged into Postgresql)

// 8. After connection, add global env variables in Jenkins system, edit the pool for isJenkins, write and update the Jenkinsfile

  1. modify the pool dynamically to switch between local and docker (isJenkins?)
  2. add global env variables in Jenkins system (variable names have to match with the dockerized database env names)
  3. added a host check in server.test.js
  4. if the variables can be accessed in the pipeline, it will print out in 'sh printenv | grep DOCKER_DB_'
  5. add a stage of check DB connection before stage of run tests
  6. when the server test and route tests are passed, move forward to write other routes and tests

// 9. create open api documents (before creating the rest of the routes in the backend)

  1. create api.yaml (in controller)
  2. create swaggerSpec.js (in routes)
  3. install and require "swagger-jsdoc", "swagger-ui-express", "yamljs", ""path", "express" in swaggerSpec.js
  4. create the path and load the api spec from the yaml file (const swaggerPath = path.join(__dirname, '../controller/api.yaml'); const swaggerDefinition = YAML.load(swaggerPath);)
  5. set up doc route (swaggerRouter.use('/', swaggerUi.serve, swaggerUi.setup(swaggerDefinition));)
  6. set up the header and return the spec (swaggerRouter.get('/', (req, res) => { res.setHeader('Content-Type', 'application/json'); res.send(swaggerSpec); });)
  7. export the swaggerRouter
  8. import the swaggerRouter from index.js

// 10. after created the swaggerSpec.js, write the api.yaml

  1. create one and two tags and test them in localhost
  2. add the routes to api.yaml while completing each route

// 11. completing the products route

  1. npm install uuid (for product id) in the test
  2. set the test to do post, get, put, delete a product (will have to add isAdmin check)
  3. use a custom middleware to check if the product exits (by product_id)
  4. if the routes work, update the api.yaml (should only shows get products for security reasons)

// 12. import middlewares in server.js

  1. morgan, bodyParser, errorHandler, cors, helmet, express-session, passport, connect-pg-simple

// 13. complete a departments route

  1. write a route, controller and tests for department
  2. prepare the get department select options in the front end in the future
  3. update the api.yaml with departments component
  4. try to seed the database with departments (revise the test if it is necessary)
  5. think about how to add products_departments when a product is added and ready to match the existing departments (should add the control in the product route? while the department ids and names were listed out in options and parsed in body) Come back to this part when it is combined to front end interface

// 14. complete a materials route

  1. write a route, controller and tests for materials
  2. more or less like the department route and update the api.yaml
  3. have to come back to modify when it is combined to front end interface

// 15. work on the Users route

  1. Think about what should be included in the User interface

  2. register, login, profile, address book, order review

  3. It must have a isAdmin check to get user basic information

  4. Create a Register route in usersController

  5. Register: import a bcrypt for hashing the password when registering a new user (in server side)

  6. write a test for registering a user in local method and test in postman

  7. may not need to update the api.yaml since the user should have created a new account before using the api service

  8. make a test for email has been taken

  9. move on to the login and create a loginController

  10. create a passport config file in Utilities folder

  11. Login: import passport, passport-local.Strategy, passport-google-oauth2.Strategy in the passport config file

  12. in the passportConfig.js, require the pool and bcrypt for checking password, uuid for generating new user_id

  13. serialized and deserialized user in passportConfig.js

  14. import the passport from passportConfig in loginController

  15. create issueJWT.js in utilities folder

  16. create JWTs table in database

  17. update the seed.js and try to re create the database (seed.js and .env have to be on the same root)

  18. work on the issueJWT before returning to loginController

  19. in issueJWT, import jsonwebtoken, fs and pool

  20. get the private key from the file

  21. issue the JWT with created date, expired date, user id and provider in the payload

  22. sign the token with payload by private key, using expired date and algorithm: 'RS256'

  23. save the signed token in the database

  24. return the token in function and module.exports the function

  25. import and use express-session, and connect-pg-simple in server.js (for postgresql database)

  26. create a session-middleware in server.js (create the session table if it is missing)

  27. import pool for the session saving in server.js

  28. debug issuejwt.js if the data format is not relative (the table may not be created yet)

  29. import issuejwt.js in loginController.js

  30. write a local login test and integrate it in the user.test.js

  31. if local login test is passed, it is time to make a google login and how can it be tested (but front end is not ready yet)

  32. make a profile page route and controller for user (it can help check the session and tokens)

  33. make a logout route and controller but it can not be tested until the front end is ready

// It's time to make a front end

// set the folder and files

  1. on the root of the app, npm create vite@latest frontend -- --template react (vite seems faster than react app)
  2. select the framework and variant, cd frontend, npm install, and npm run dev
  3. in the frontend, index/main is the root (createRoot from react-dom/client), app is the container to hold all the pages, and react-dom gathers all the pages in the app
  4. set proxy in package.json (in the frontend if using react-app)
  5. However, Vite uses vite.config.js instead of package.json to save the proxy configuration

// basic set up for the pages and set up the routes

  1. create a pages folder and create HomePage.js
  2. install react-router-dom in the front end folder and import it in app.js
  3. import { BrowserRouter, Routes, Route } from react-router-dom, will be able to render the HomePage in main and enable the doors to different pages

// try to connect the backend to the frontend

  1. create products page
  2. install axios in the frontend root and import it on ProductPage
  3. useState and useEffect are used to store the products
  4. tests if the frontend can display the product information (may have to seed to the database with simple products)
  5. if the products can be displayed, think about the next steps

// Plan about the frontend structure

  1. install and create redux for state management
  2. use slices as controller in components and pages
  3. add bootstrap UI framework

// install and create redux store

  1. npm install @reduxjs/toolkit react-redux in the front end
  2. create store folder inside src in front end
  3. create store.js inside the store folder
  4. import { configureStore } from '@reduxjs/toolkit';
  5. create a store variable from configureStore, which can add reducer in
  6. import productsReducer from './slices/productsSlice' (will be created as below)
  7. export default store

// create slices folder and create productsSlice.js

  1. create slice folder inside src/store
  2. import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; inside the productsSlice.js
  3. create an initialState variable
  4. import axios from 'axios' for fetching data and store data in the state
  5. create a function from createAsyncThunk for fetching data with axios and export it
  6. create productsSlice from createSlice
  7. the productsSlice will have name, initialState, reducers: {extraReducers} (for changing the initialState)
  8. export actions and the reducer at the end of the page

// provide store in the main.js or index.js in the front end

  1. import { Provider } from 'react-redux';
  2. import { store } from './store/store';
  3. wrap the with

// use Redux in ProductsPage

  1. import { useEffect } from "react";
  2. import { useSelector, useDispatch } from "react-redux";
  3. import { fetchProducts } from "../store/slices/productsSlice";
  4. in productsPage function, const dispatch = useDispatch(); const { products, loading, error } = useSelector((state) => state.products);
  5. implement useEffect to fetchProducts

// install and implement react-bootstrap

  1. npm install react-bootstrap bootstrap (in the front end)
  2. in main.jsx, import bootstrap's CSS: import 'bootstrap/dist/css/bootstrap.min.css'; (save to be effective)
  3. in ProductsPage.js, import react-bootstraps components import { Container, Row, Col, Card, Spinner, Alert } from 'react-bootstrap';
  4. update the components

// if the redux and bootstrap works fine, the layout would have been different // review the webpage design. how should the webpage present

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published