# Noteivate

[![pipeline status](https://gitlab.ost.ch/fabio.stocker/dsy-challenge-task/badges/main/pipeline.svg)](https://gitlab.ost.ch/fabio.stocker/dsy-challenge-task/-/commits/main)

Noteivate (Note + Motivate) is a simple note-taking app that allows you to create, edit, and delete notes. It is built using Docker, Node.js, Express, and PostgreSQL.

## Table of Contents

- [Installation](#installation)
  - [Prerequisites](#prerequisites)
  - [Clone the repository](#clone-the-repository)
  - [Set up the environment](#set-up-the-environment)
  - [Start the application](#start-the-application)
  - [Access the application](#access-the-application)
- [API Documentation](#api-documentation)
  - [Endpoints](#endpoints)
- [Web Documentation](#web-documentation)
  - [Endpoints](#endpoints-1)
- [Comments](#comments)

## Installation

### Prerequisites

- [Docker](https://www.docker.com/)
- [Docker Compose](https://docs.docker.com/compose/)

### Clone the repository

Clone the repository to your local machine:

```bash
git clone https://gitlab.ost.ch/fabio.stocker/dsy-challenge-task.git
cd dsy-challenge-task
```

### Set up the environment

A Docker volume, various environment variables and SSL certificates are required to run the application. The following sections describe how to set them up.

#### Docker Volume

Create a Docker volume for the database to persist data:

```bash
docker volume create noteivate
```

#### Database

Copy the `.env.example` file to `.env`:

```bash
cd db
cp .env.example .env
```

Make sure to set the `POSTGRES_PASSWORD` environment variable in `.env` to a secure password.

#### API

Copy the `.env.example` file to `.env`:

```bash
cd api
cp .env.example .env
```

Make sure to set the `DB_PASSWORD` environment variable in `.env` to the same password as in `db/.env`.
Optionally, you can also change the `DB_*` environment variables to your liking. Remember to also change the environment variables in `db/.env` accordingly.

#### Web

Copy the `.env.example` file to `.env`:

```bash
cd web
cp .env.example .env
```

You can change the environment variables in `.env` to your liking. However, the defaults should work fine.

#### Generate SSL certificates

Generate SSL certificates for traefik, which is used as a reverse proxy for the web service:

```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout certs/key.pem -out certs/cert.pem
```

### Start the application

Start the application using Docker Compose:

```bash
docker compose up
```

You can also start the application in detached mode by using the `-d` flag.

```bash
docker compose up -d
```

### Access the application

By default, the application is accessible at https://localhost/.
Note that 127.0.0.1 will not work due to traefik's configuration.

## API Documentation

### Endpoints

#### `GET /`

Returns a list of all notes.

##### Query Parameters

None.

##### Request Body

None.

##### Response

- `200 OK`: The notes were successfully returned.
- `500 Internal Server Error`: An error occurred while returning the notes.

###### Response Body

An array of notes:

```json
[
  {
    "id": 1,
    "title": "Note title 1",
    "content": "Note content 1",
    "createdAt": "2021-10-10T00:00:00.000Z",
    "updatedAt": "2021-10-10T00:00:00.000Z"
  },
  {
    "id": 2,
    "title": "Note title 2",
    "content": "Note content 2",
    "createdAt": "2022-10-10T00:00:00.000Z",
    "updatedAt": "2022-10-10T00:00:00.000Z"
  },
  // ...
]
```

#### `GET /:id`

Returns the note with the given ID.

##### Query Parameters

- `id`: The ID of the note to return.

##### Request Body

None.

##### Response

- `200 OK`: The note was successfully returned.
- `400 Bad Request`: The request is invalid.
- `404 Not Found`: The note with the given ID does not exist.
- `500 Internal Server Error`: An error occurred while returning the note.

###### Response Body

The note:

```json
{
  "id": 1,
  "title": "Note title",
  "content": "Note content",
  "createdAt": "2021-10-10T00:00:00.000Z",
  "updatedAt": "2021-10-10T00:00:00.000Z"
}
```

#### `POST /new`

Creates a new note.

##### Query Parameters

None.

##### Request Body

```json
{
  "title": "Note title",
  "content": "Note content"
}
```

##### Response

- `201 Created`: The note was successfully created.
- `400 Bad Request`: The request is invalid.
- `500 Internal Server Error`: An error occurred while creating the note.

###### Response Body

The ID of the created note along with a message:

```json
{
  "id": 1,
  "message": "Note successfully created"
}
```

#### `POST /:id`

Updates an existing note with the given ID.

##### Query Parameters

- `id`: The ID of the note to update.

##### Request Body

```json
{
  "title": "New note title",
  "content": "New note content"
}
```

##### Response

- `200 OK`: The note was successfully updated.
- `400 Bad Request`: The request is invalid.
- `404 Not Found`: The note with the given ID does not exist.
- `500 Internal Server Error`: An error occurred while updating the note.

###### Response Body

The ID of the updated note along with a message:

```json
{
  "id": 1,
  "message": "Note successfully updated"
}
```

#### `DELETE /:id`

Deletes the note with the given ID.

##### Query Parameters

- `id`: The ID of the note to delete.

##### Request Body

None.

##### Response

- `200 OK`: The note was successfully deleted.
- `400 Bad Request`: The request is invalid.
- `404 Not Found`: The note with the given ID does not exist.
- `500 Internal Server Error`: An error occurred while deleting the note.

###### Response Body

The note that was deleted along with a message:

```json
{
  "message": "Note successfully deleted",
  "note": {
    "id": 1,
    "title": "Note title",
    "content": "Note content",
    "createdAt": "2021-10-10T00:00:00.000Z",
    "updatedAt": "2021-10-10T00:00:00.000Z"
  }
}
```

If the note for some reason cannot be fetched, the response body will be:

```json
{
  "message": "Note successfully deleted",
  "note": null
}
```

### Error Responses

#### `400 Bad Request`

The request is invalid.

##### Response Body

```json
{
  "message": "Invalid request"
}
```

#### `404 Not Found`

The note with the given ID does not exist.

##### Response Body

```json
{
  "message": "Note not found"
}
```

#### `500 Internal Server Error`

An error occurred while processing the request.

##### Response Body

```json
{
  "message": "Internal server error"
}
```

## Web Documentation

### Endpoints

#### `GET /`

Redirects to `/notes`.

#### `GET /notes`

Displays a list of all notes.

#### `GET /notes/new`

Displays a form to create a new note.

#### `GET /notes/:id`

Displays the note with the given ID.

#### `GET /notes/:id/edit`

Displays a form to edit the note with the given ID.

#### `POST /notes/new`

Creates a new note.

#### `POST /notes/:id/edit`

Updates the note with the given ID.

#### `POST /notes/:id/delete`

Deletes the note with the given ID.

## Comments

HTTP/3 was tested on the Firefox Nightly browser build as other browsers do not seem to utilize HTTP/3 efficiently.
