Skip to content

Commit

Permalink
Containerize backend app and MySQL database. (#230)
Browse files Browse the repository at this point in the history
* Containerize backend and, integrate with MySQL container using docker-compose.

* Add default password to compose environment

* Update documentation to include Docker

* Update documentation headers and command outline

* Update docker documentation to have bolder commands

* Add warning about Docker container volume

* Modify init.sql to use legacy authentication

* Modify .env.example default values to be consistent

* Assign db.config.js values to be consistent with .env.example

* Add legacy authentication to MySQL

* Update .env dev database name

* Remove mysql_native_password option in init.sql in favor of configuration option.
  • Loading branch information
Justin-Fernbaugh authored May 24, 2024
1 parent 9a470d0 commit 07e1c60
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 37 deletions.
4 changes: 4 additions & 0 deletions server/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
npm-debug.log
Dockerfile
.dockerignore
10 changes: 5 additions & 5 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
DEV_DB_NAME='myclassroom'
DEV_DB_USER='admin'
DEV_DB_PASS='Password_1'
DEV_DB_NAME='myclassroom_development'
DEV_DB_USER='dev_admin'
DEV_DB_PASS='password'

TEST_DB_NAME='myclassroom_test'
TEST_DB_USER='testadmin'
TEST_DB_PASS='Password_2'
TEST_DB_USER='test_admin'
TEST_DB_PASS='password'

PORT='3001'

Expand Down
20 changes: 20 additions & 0 deletions server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Use the official Node.js image as a base image
FROM node:latest

# Set the working directory in the container
WORKDIR /app

# Copy package.json and package-lock.json files to the working directory
COPY package*.json ./

# Install the dependencies
RUN npm install

# Copy the rest of the application code to the working directory but ignore node_modules
COPY . .

# Expose the port the app runs on
EXPOSE 3001

# Command to run the application
CMD ["npm", "run", "start:dev"]
94 changes: 91 additions & 3 deletions server/README.md
Original file line number Diff line number Diff line change
@@ -1,157 +1,238 @@
# My-Classroom-Backend

## Dependencies

- node: 16.13.0
- npm: 9.1.2
- mysql: 8.0.31

## Cloning Repo and Installing Dependencies

Install MySQL

- Refer to the [MySQL Getting Started Guide](https://dev.mysql.com/doc/mysql-getting-started/en/) for installing and troubleshooting MySQL.

Clone the GitHub Repository

```
git clone git@github.com:OSU-MC/MyClassroom.git
```

Navigate to the Server Directory

```
cd MyClassroom/server
```

Install the Application Dependencies

```
npm install
```

## Configuring Local Environment

Rename the .env.example file to setup environment configuration

```
mv .env.example .env
```

The server application can be configured by modifying the `/server/.env` file. The `DEV_DB_...` and `TEST_DB_...` values should match those in the database/user creation commands listed in the setup steps below. Additionally, `CLIENT_URL` should be set to the front end application URL. For basic testing, the default values can be used.

## Create and Migrate the Database

Connect to the MySQL Database using the Root User

```
mysql -u root -p
```

Create the Application Database

```
CREATE DATABASE myclassroom;
```

Create the Administrative Database User

```
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'Password_1';
```

Grant the Administrative User Access to the Application Database

```
GRANT ALL PRIVILEGES ON myclassroom.* TO 'admin'@'localhost';
```

Disconnect from the MySQL Database

```
exit
```

Migrate the Database using Sequelize

```
npx sequelize-cli db:migrate
```

## Setup Backend Testing Environment

Connect to the MySQL Database using the Root User

```
mysql -u root -p
```

Create the Test Application Database

```
CREATE DATABASE myclassroom_test;
```

Create the Testing Administrative Database User

```
CREATE USER 'testadmin'@'localhost' IDENTIFIED BY 'Password_2';
```

Grant the Testing Administrative User Access to the Test Application Database

```
GRANT ALL PRIVILEGES ON myclassroom_test.* TO 'testadmin'@'localhost';
```

Disconnect from the MySQL Database

```
exit
```

Migrate the Test Database using Sequelize

```
npx sequelize-cli db:migrate --env test
```

Seed the Test Database using Sequelize

```
npx sequelize-cli db:seed:all --env test
```

## Resetting/Rolling Back Databases

(Append `npx` commands with `--env test` to run on the test database)

Undo Database Migrations

```
npx sequelize-cli db:migrate:undo:all
```

Undo Test Database Seeding

```
npx sequelize-cli db:seed:undo:all
```

Reset Local Database

```
mysql -u root -p
```

```
DROP DATABASE myclassroom;
```

or

```
DROP DATABASE myclassroom_test;
```

## Starting the Application
## Docker

The backend NodeJS app and MySQL database can be deployed in containers using Docker. The Dockerfile will build the backend NodeJS app as a standalone whilst the compose.yml file will build and run the backend and MySQL containers. If you plan to re-initialize the database from scratch remember to delete the docker volume for it as well.

### Build the backend Dockerfile alone (Optional)

```
docker build -t myclassroom_backend .
docker run -p 3001:3001: myclassroom_backend
```

### Utilizing docker-compose (Preferred)

Build and start then detach with '-d'

```
docker-compose up --build -d
```

After first build we can start and stop using docker-compose

```
docker-compose up -d
docker-compose down
```

Inspecting detached containers

```
docker-compose logs
```

Optionally, the MySQL database can be started and stopped individually after the first build

```
docker container start myclasroom_db
```

## Starting the Application (Conventional NodeJS)

```
npm run start
```

## Testing the Application

Testing the application is easy. The Jest testing framework is used to write tests for the system. A script has been added to the package.json file to run tests locally:

```
npm run test
```

If you run into issues, ensure you have done the following:

1. Created a local test database
2. Properly instantiated all env variables for the test environment

## Application Authentication & Session
The application uses cookie-based authentication once a user session has been created (i.e. a user has logged in). A user's session will have a specific XSRF token value associated with it to protect against XSRF attacks. As such, the value of that token will be sent back as a cookie, and the application expects to recieve with each authenticated request a custom X-XSRF-TOKEN header with that value, along with the traditional authentication cookie _myclassroom_session which the application generated as part of initial session creation.

The application uses cookie-based authentication once a user session has been created (i.e. a user has logged in). A user's session will have a specific XSRF token value associated with it to protect against XSRF attacks. As such, the value of that token will be sent back as a cookie, and the application expects to recieve with each authenticated request a custom X-XSRF-TOKEN header with that value, along with the traditional authentication cookie \_myclassroom_session which the application generated as part of initial session creation.

A user's session is valid for a minimum of 4 hours, and as long as the user is active within 4 hours of last activity, the session can be valid for as long as 24 hours. In other words, users will be asked to login again after 4 hours of inactivity or 24 hours since they last provided their credentials.

## Configuring Services

### Emailer

The application is configured to use Courier notification infastructure to message users. In order to use the application's mailer, create an account at https://www.courier.com/. Follow Courier's setup instructions and prompts.

The process should yield a bearer token in the HTTPS request Courier generates. Copy this token, and paste it in the application environment as `COURIER_AUTH_TOKEN`. Also set `EABLE_EMAIL='true'`. That's it! You should be able to interact with the configured emailer through Courier.

It's worth noting that the application is only configured for email use through Courier, but Courier supports a variety of modern notification methods.

## Roadmap

- Learning Management System (LMS) Integration
- Expanded Question Type Support
- WebSocket Open Polling Connection for Live Updates and Feedback
Expand All @@ -160,14 +241,21 @@ It's worth noting that the application is only configured for email use through
- Request Rate Limiting

## Database Schema
![Schema](https://github.com/OSU-MC/MyClassroom/assets/25465133/d987e780-fd0e-4ea5-bd18-c72de5d8c32c)

![Schema](https://github.com/OSU-MC/MyClassroom/assets/25465133/d987e780-fd0e-4ea5-bd18-c72de5d8c32c)

## Endpoints

[API Endpoints Doc](/API%20Endpoints%20MyClassroom.pdf)

## Getting Involved

Feel free to open an issue for feature requests or bugs. We openly accept pull requests for bug fixes.

## Licensing

GNU General Public License v3.0

```
```
41 changes: 41 additions & 0 deletions server/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
version: "3.8"

services:
backend:
container_name: myclassroom_backend
build:
context: .
dockerfile: Dockerfile
depends_on:
db:
condition: service_healthy
environment:
DEV_DB_HOST: db
DEV_DB_PASS: password
TEST_DB_HOST: db
TEST_DB_PASS: password
entrypoint: ["./entrypoint.sh"]
ports:
- "3001:3001"
expose:
- "3001"

db:
image: mysql:latest
container_name: myclassroom_db
command: ["mysqld", "--mysql-native-password=ON"]
environment:
MYSQL_ROOT_PASSWORD: rootpassword
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -prootpassword"]
interval: 10s
timeout: 5s
retries: 5

volumes:
db_data:
Loading

0 comments on commit 07e1c60

Please # to comment.