diff --git a/README.md b/README.md index 2906a297..01653d6f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ # BlueWave Onboarding -BlueWave Onboarding helps app owners build knowledge and user-experience oriented apps. It includes the following features: +BlueWave Onboarding helps app owners build knowledge and user-experience oriented apps. It includes the following features: - Welcome tours - Product hints @@ -21,7 +21,6 @@ This is a work-in-progress application. The source code is available under GNU A ![Main dashboard](https://github.com/bluewave-labs/bluewave-onboarding/blob/master/Dashboard.png) - ## Tech stack - [ReactJs](https://react.dev/) @@ -29,8 +28,25 @@ This is a work-in-progress application. The source code is available under GNU A - [Node.js](https://nodejs.org/en) - [PostgreSQL](https://postgresql.org) +## For Local Use + +Make sure docker and git is installed + +1. Clone the project + +`git clone https://github.com/bluewave-labs/guidefox.git` + +2. Navigate to the project directory + +`cd guidefox` + +3. Run docker + +`docker compose build` + +`docker compose up` -## Installation +## Server Installation 1. Make sure Docker is installed to your machine where the server will run. 2. Make sure git is installed to your machine Git. @@ -48,14 +64,14 @@ cd bluewave-onboarding Open the Nginx configuration file: -``sudo nano /etc/nginx/sites-available/onboarding-demo`` +`sudo nano /etc/nginx/sites-available/onboarding-demo` Add the following configuration. Change YOUR_DOMAIN_NAME with your domain name: ```server { listen 80; server_name YOUR_DOMAIN_NAME; - return 301 https://$host$request_uri; + return 301 https://$host$request_uri; } server { @@ -84,40 +100,121 @@ server { } ``` - 6. Create a symbolic link to enable the configuration: -``sudo ln -s /etc/nginx/sites-available/onboarding-demo /etc/nginx/sites-enabled/`` +`sudo ln -s /etc/nginx/sites-available/onboarding-demo /etc/nginx/sites-enabled/` 7. Install Certbot and its Nginx plugin: -``sudo apt install certbot python3-certbot-nginx`` +`sudo apt install certbot python3-certbot-nginx` 8. Obtain SSL Certificate. Run Certbot to obtain a certificate for your domain: -``sudo certbot --nginx`` +`sudo certbot --nginx` 9. Verify the Nginx configuration: -``sudo nginx -t`` +`sudo nginx -t` 10. Restart Nginx to apply the changes: -``sudo systemctl restart nginx`` +`sudo systemctl restart nginx` 11. Start the project -``cd ~/bluewave-onboarding -docker compose up -d`` +`cd ~/bluewave-onboarding +docker compose up -d` + +## Environment variables + +In order to the project to run safely and correctly, the user should add their own environment variables. They can be added to the .env file in the root directory of the project. The following is the list of environment variables that should be added and its description: + +1. Database credentials + +```env +DEV_DB_USERNAME - Development database username +DEV_DB_PASSWORD - Development database password +DEV_DB_NAME - Development database name +DEV_DB_HOST - Development database host +DEV_DB_PORT - Development database port +TEST_DB_USERNAME - Test database username +TEST_DB_PASSWORD - Test database password +TEST_DB_NAME - Test database name +TEST_DB_HOST - Test database host +TEST_DB_PORT - Test database port +PROD_DB_USERNAME - Production database username +PROD_DB_PASSWORD - Production database password +PROD_DB_NAME - Production database name +PROD_DB_HOST - Production database host +PROD_DB_PORT - Production database port +``` + +2. Email service configuration + For the email service to run correctly, the user should add their own email credentials + +```env +EMAIL_ENABLE - Enable email service (boolean) +EMAIL_HOST - Email host +EMAIL_PORT - Email port +EMAIL - Email +APP_PASSWORD - Email password +``` + +Example configuration: + +```env +EMAIL_ENABLE=true +EMAIL_HOST=smtp.gmail.com +EMAIL_PORT=587 +EMAIL=your-email@example.com +APP_PASSWORD=your-app-specific-password +``` + +Note: When using Gmail, you'll need to enable 2-factor authentication and generate an App Password. + +3. JWT Secret Key + +```env +JWT_SECRET - secret key to sign the JWT token +``` + +- Use a strong, random secret key (minimum 32 characters) + +4. Enable IP check for the API + If the ENABLE_IP_CHECK is set to true, but the ALLOWED_IP_RANGE and ALLOWED_IPS are not set, the API will work for all IP addresses. + +```env +ENABLE_IP_CHECK - Enable IP check for the API (boolean) +ALLOWED_IP_RANGE - Allowed IP range for the API with the format "baseIp/rangeStart-rangeEnd" (e.g. 192.168.1/1-255) separated by comma +ALLOWED_IPS - Allowed IP addresses for the API separated by comma +``` + +Example configuration: + +```env +ENABLE_IP_CHECK=true +ALLOWED_IP_RANGE=192.168.1/1-255,10.0.0/1-100 +ALLOWED_IPS=203.0.113.1,203.0.113.2 +``` + +Note: For security reasons, it's recommended to always set either ALLOWED_IP_RANGE or ALLOWED_IPS when ENABLE_IP_CHECK is true. + +5. In .env.test file, the user should have the following environment variables, so the postgres container can run correctly: + +```env +POSTGRES_USER - Test database username (The same as TEST_DB_USERNAME) +POSTGRES_PASSWORD - Test database password (The same as TEST_DB_PASSWORD) +POSTGRES_DB - Test database name (The same as TEST_DB_NAME) +``` + +For development and testing purposes, the application is ready to go after cloning and dependencies installation. ## Contributing -Here's how you can contribute to the Onboarding product. +Here's how you can contribute to the Onboarding product. - Check [Contributor's guideline](https://github.com/bluewave-labs/bluewave-onboarding/blob/master/CONTRIBUTING.md) - Have a look at our Figma designs [here](https://www.figma.com/design/MLPbP1HM2L9ON6f88pHTee/Onboarding?node-id=0-1&t=iwgz015l5QWbWRqU-1). We encourage you to copy to your own Figma page, then work on it as it is read-only. - Open an issue if you believe you've encountered a bug - Make a pull request to add new features/make quality-of-life improvements/fix bugs. - Make sure your send your PRs to **develop** branch. - - diff --git a/backend/.env b/backend/.env index b1057599..0ef4194b 100644 --- a/backend/.env +++ b/backend/.env @@ -1,24 +1,23 @@ -# Node environment -NODE_ENV=development - -# Development environment +# For development environment, the project is ready to run after cloning and installing the dependencies. +# Development database environment DEV_DB_USERNAME=user123 DEV_DB_PASSWORD=password123 DEV_DB_NAME=onboarding_db DEV_DB_HOST=db DEV_DB_PORT=5432 +# Enable email service EMAIL_ENABLE=false +# Email service configuration, for the email service to run correctly, the user should add their own email credentials +EMAIL_HOST=your_email_host +EMAIL_PORT=your_email_port +EMAIL=your_email +APP_PASSWORD=your_app_password # JWT Secret Key JWT_SECRET="NKrbO2lpCsOpVAlqAPsjZ0tZXzIoKru7gAmYZ7XlHn0=qqwqeq" -TEST_DB_USERNAME=user123 -TEST_DB_PASSWORD=password123 -TEST_DB_NAME=onboarding_db_test -TEST_DB_HOST=localhost -TEST_DB_PORT=5432 - +# Enable IP check for the API ENABLE_IP_CHECK=false # Allowed IP range for the API "baseIp/rangeStart-rangeEnd" (e.g. 192.168.1/1-255) separated by comma ALLOWED_IP_RANGE=11.22.33/10-200, 192.168.65/1-255 diff --git a/backend/.env.production b/backend/.env.production index 7de5ae9b..d5efbf21 100644 --- a/backend/.env.production +++ b/backend/.env.production @@ -1,15 +1,22 @@ -# Production Environment Configuration - -# Database Configuration -PROD_DB_USERNAME=prod_user -PROD_DB_PASSWORD=prod_password -PROD_DB_NAME=prod_db -PROD_DB_HOST=localhost +# Production environment +PROD_DB_USERNAME=user123 +PROD_DB_PASSWORD=password123 +PROD_DB_NAME=onboarding_db +PROD_DB_HOST=db PROD_DB_PORT=5432 +# Enable email service +EMAIL_ENABLE=false +# Email service configuration, for the email service to run correctly, the user should add their own email credentials +EMAIL_HOST=your_email_host +EMAIL_PORT=your_email_port +EMAIL=your_email +APP_PASSWORD=your_app_password + # JWT Secret Key JWT_SECRET=your_prod_jwt_secret_key_here +# Enable IP check for the API ENABLE_IP_CHECK=false # Allowed IP range for the API "baseIp/rangeStart-rangeEnd" (e.g. 192.168.1/1-255) separated by comma ALLOWED_IP_RANGE=11.22.33/10-200 diff --git a/backend/.env.test b/backend/.env.test index 7507a9c6..008330e2 100644 --- a/backend/.env.test +++ b/backend/.env.test @@ -1,19 +1,24 @@ # Test Environment Configuration -# Database Configuration +# Test database environment TEST_DB_USERNAME=user123 TEST_DB_PASSWORD=password123 TEST_DB_NAME=onboarding_db_test TEST_DB_HOST=localhost TEST_DB_PORT=5432 +# Credentials for test postgres database POSTGRES_USER=user123 POSTGRES_PASSWORD=password123 POSTGRES_DB=onboarding_db_test +# Enable email service +EMAIL_ENABLE=false + # JWT Secret Key JWT_SECRET=your_test_jwt_secret_key_here +# Enable IP check for the API ENABLE_IP_CHECK=false # Allowed IP range for the API "baseIp/rangeStart-rangeEnd" (e.g. 192.168.1/1-255) separated by comma ALLOWED_IP_RANGE=11.22.33/10-200, 192.168.65/1-255 diff --git a/backend/config/config.js b/backend/config/config.js index 312759a0..56627b44 100644 --- a/backend/config/config.js +++ b/backend/config/config.js @@ -1,31 +1,60 @@ -require("dotenv").config(); +require('dotenv').config(); +const envSuffix = process.env.NODE_ENV && process.env.NODE_ENV !== 'development' ? `.${process.env.NODE_ENV}` : ''; +const env = `.env${envSuffix}`; + +const dotenv = require('dotenv'); +const result = dotenv.config({ path: `./${env}` }); + +if (result.error) { + console.error(`Failed to load environment file: ${env}`); + process.exit(1); +} + +const { + DEV_DB_HOST, + DEV_DB_NAME, + DEV_DB_PASSWORD, + DEV_DB_PORT, + DEV_DB_USERNAME, + TEST_DB_HOST, + TEST_DB_NAME, + TEST_DB_PASSWORD, + TEST_DB_PORT, + TEST_DB_USERNAME, + PROD_DB_HOST, + PROD_DB_NAME, + PROD_DB_PASSWORD, + PROD_DB_PORT, + PROD_DB_USERNAME, +} = process.env; + module.exports = { - defaultTeamName: "My Organisation", + defaultTeamName: 'My Organisation', development: { - username: process.env.DEV_DB_USERNAME, - password: process.env.DEV_DB_PASSWORD, - database: process.env.DEV_DB_NAME, - host: process.env.DEV_DB_HOST, - dialect: "postgres", - port: process.env.DEV_DB_PORT, + username: DEV_DB_USERNAME, + password: DEV_DB_PASSWORD, + database: DEV_DB_NAME, + host: DEV_DB_HOST, + dialect: 'postgres', + port: DEV_DB_PORT, logging: false, }, test: { - username: process.env.TEST_DB_USERNAME, - password: process.env.TEST_DB_PASSWORD, - database: process.env.TEST_DB_NAME, - host: process.env.TEST_DB_HOST, - dialect: "postgres", - port: process.env.TEST_DB_PORT, + username: TEST_DB_USERNAME, + password: TEST_DB_PASSWORD, + database: TEST_DB_NAME, + host: TEST_DB_HOST, + dialect: 'postgres', + port: TEST_DB_PORT, logging: false, }, production: { - username: process.env.PROD_DB_USERNAME, - password: process.env.PROD_DB_PASSWORD, - database: process.env.PROD_DB_NAME, - host: process.env.PROD_DB_HOST, - dialect: "postgres", - port: process.env.PROD_DB_PORT, + username: PROD_DB_USERNAME, + password: PROD_DB_PASSWORD, + database: PROD_DB_NAME, + host: PROD_DB_HOST, + dialect: 'postgres', + port: PROD_DB_PORT, logging: false, }, }; diff --git a/backend/package.json b/backend/package.json index 6f8106d4..164b2be2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,8 +5,8 @@ "main": "index.js", "scripts": { "start": "node index.js", - "pretest": "NODE_ENV=test docker rm -f test-postgres || true && docker run --name test-postgres --env-file .env.test -p 5432:5432 -d postgres && npx wait-on tcp:5432 && npx sequelize-cli db:create --env test || true && npx sequelize-cli db:migrate --env test", - "posttest": "docker stop test-postgres && docker rm test-postgres", + "pretest": "NODE_ENV=test bash pretest-script.sh", + "posttest": "bash posttest-script.sh", "test": "NODE_ENV=test nyc mocha --extension js,mjs 'src/test/**/*.test.*'", "test:e2e": "npm run pretest && NODE_ENV=test mocha 'src/test/e2e/**/*.test.mjs'", "test:unit": "NODE_ENV=test mocha 'src/test/unit/**/*.test.js' --watch", diff --git a/backend/posttest-script.sh b/backend/posttest-script.sh new file mode 100755 index 00000000..47b6340a --- /dev/null +++ b/backend/posttest-script.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# stop container, if it exists + +if [[ "$(docker ps -a -q -f name=test-postgres)" ]]; then + docker stop test-postgres +fi + +# remove container +if [[ "$(docker ps -a -q -f name=test-postgres)" ]]; then + docker rm -f test-postgres +fi + +# reset NODE_ENV to default +if [[ "$OSTYPE" == "msys" ]]; then + if [ -n "$PSModulePath" ]; then + # PowerShell + echo '$env:NODE_ENV="development"' | powershell -Command - + else + # CMD + cmd.exe /C "set NODE_ENV=development" + fi +else + export NODE_ENV=development +fi \ No newline at end of file diff --git a/backend/pretest-script.sh b/backend/pretest-script.sh new file mode 100755 index 00000000..5f9efe34 --- /dev/null +++ b/backend/pretest-script.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# remove test-postgres container if it exists +if [[ "$(docker ps -a -q -f name=test-postgres)" ]]; then + docker rm -f test-postgres +fi + +# run test-postgres container + +docker run --name test-postgres --env-file ./.env.test -p 5432:5432 -d postgres + +# wait for postgres to start +echo "Waiting for PostgreSQL to be ready..." +for i in {1..10}; do + if docker exec test-postgres pg_isready -U user123 >/dev/null 2>&1; then + break + else + echo "PostgreSQL is not ready. Retrying ($i/10)..." + sleep 2 + fi +done + +# create test database if it doesn't exist +exists=$(docker exec test-postgres psql -U user123 -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='onboarding_db_test'") +if [[ -z "$exists" || "$exists" != *"1"* ]]; then + npx sequelize-cli db:create --env test +fi + +# run migrations +npx sequelize-cli db:migrate --env test