Skip to content

HEIG-VD-S3-PW/DAI-LAB-04

Repository files navigation

Front-end example

OKR - An Objective and Key Results Manager API

An intuitive API to help individuals, teams, and organizations set, track, and achieve their objectives and key results efficiently.


Important Note
This repository contains only the backend API for the project. The frontend is not included here.
The image above is just an example of the user interface (frontend) that interacts with this backend API.

Table of Contents

Built With

(back to top)

Getting Started

This program is a simple OKR manager. OKR is a goal-setting framework used by individuals, teams, and organizations to define measurable goals and track their outcomes.

With this platform, you'll be able to create teams, manage its users, create projects, objectives, key results and tasks. You will also be able to set requirements for a task (human, material or even another task), its priority and define the timeframe in which the task must be done.

Enjoy seamless collaboration with role-based access control for users.

Get the source code

First of all, download the source code:

git clone https://github.com/HEIG-VD-S3-PW/DAI-LAB-04
cd DAI-LAB-04

Documentation

You will find all the information you need to use this application in this readme.

The code documentation is written with standard javadoc.

Important

The following instructions are targeted for development environments. On production, you might want to use the following URL: https://api-heig-dai-pw04.duckdns.org/api/openapi.json>

Also, the route's documentation (built with the OpenAPI spec) can be accessed throught the following url: http://localhost:8085. Then, you must specify the following url to fetch the .json file containing the documentation: http://localhost:7000/api/openapi.json

Notice, that these url's can only be accessed after launching the backend as the SWAGGER-UI client. Detailed instructions about how to do this can be found later in this document.

Here are some images of the OpenAPI documentation:

OpenAPI documentation OpenAPI documentation OpenAPI documentation

Requirements

Java 21

  • asdf

    # Install the plugin if needed
    asdf plugin add java
    # Install
    asdf install java latest:temurin-21
  • Mac (homebrew)

    brew tap homebrew/cask-versions
    brew install --cask temurin@21
  • Windows (winget)

    winget install EclipseAdoptium.Temurin.21.JDK

Docker

The application can (and should) be used with docker.

To install and use docker, follow the official documentation

Setup web infrastructure

First, create a virtual machine using your Azure account. To do so, select a virtual machine with the following characteristics from the creation menu:

  • Project details
    • Subscription: Azure for Students
    • Resource group: Create new with the name <YOUR_VM_NAME>
  • Instance details
    • Virtual machine name: <YOUR_VM_NAME>
    • Region: (Europe) West Europe
    • Availability options: No infrastructure redundancy required
    • Security type: Trusted launch virtual machines (the default)
    • Image: Ubuntu Server 24.04 LTS - x64 Gen2 (the default)
    • VM architecture: x64
    • Size: Standard_B1s - you might need to click "See all sizes" to see this option
  • Administrator account
    • Authentication type: SSH public key
    • Username: ubuntu
    • SSH public key source: Use existing public key
    • SSH public key: Paste your public key here - see the note below for more information
  • Inbound port rules
    • Public inbound ports: Allow selected ports
    • Select inbound ports: HTTP (80), HTTPS (443), SSH (22)

The settings above will allow you to create a virtual machine whose open ports are: 80, 443 and 22. Also, SSH connections require key-based authentication.

DNS

Once the VM created, you can grab its IP address and create a DNS entry for that same IP.

We used duckdns.org as our DNS service provider.

All you need to do is to create an account and fill the simple form on the main page with your domain name (in our case it was: api-heig-dai-pw04). Then, update the DNS  entry with the IP address of your VM.

Test the DNS resolution

Test the DNS resolution of the DNS records you added from the virtual machine and from your local machine.

# Test the DNS resolution
nslookup api-heig-dai-pw04.duckdns.org
Server:         10.193.64.16
Address:        10.193.64.16#53

Non-authoritative answer:
Name:   api-heig-dai-pw04.duckdns.org
Address: 135.236.100.168

SSH connection

In order to connect to the VM, simply type the following command:

ssh -i <PATH_TO_PRIVATE_KEY> ubuntu@api-heig-dai-pw04.duckdns.org

As key-based authentication was already setup, it wont ask you for a password.

Deployment

Even though the deployment instructions using docker can be found later in this document, all you need to do is:

  1. Clone or copy (using scp) the source code to the remote server
  2. Go to directory you have just created/copied and create a file named .env with the following content:
# The image version to use for whoami
WHOAMI_IMAGE_VERSION=latest
# The email address for Let's Encrypt
TRAEFIK_ACME_EMAIL=<YOUR_EMAIL>

# The fully qualified domain name to access Traefik
TRAEFIK_FULLY_QUALIFIED_DOMAIN_NAME=dashboard-heig-dai-pw04.duckdns.org

# Enable the Traefik dashboard
TRAEFIK_ENABLE_DASHBOARD=true

# The image version to use for Traefik
TRAEFIK_IMAGE_VERSION=latest

Also, create a file named credentials.txt whose purpose is to store the database credentials.

Then, simply run the command to launch our application as well as all its dependencies:

sudo docker compose --profile prod up --build
Testing the web app

In order to prove that all services (http/s + ssh) are running, we can run the following command:

 sudo nmap api-heig-dai-pw04.duckdns.org
Nmap scan report for api-heig-dai-pw04.duckdns.org (135.236.100.168)
Host is up (0.020s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 5.04 seconds

Then, we can use CURL to make some HTTP requests using both HTTP and HTTPS:

Testing HTTPS redirection

curl -L --show-headers  http://api-heig-dai-pw04.duckdns.org/users

HTTP/1.1 301 Moved Permanently
Location: https://api-heig-dai-pw04.duckdns.org/users
Date: Wed, 15 Jan 2025 08:23:10 GMT
Content-Length: 17

HTTP/2 200
content-type: application/json
date: Wed, 15 Jan 2025 08:23:10 GMT
content-length: 2

[]⏎ 

Testing HTTPS

curl --show-headers  https://api-heig-dai-pw04.duckdns.org/users
curl --show-headers  https://api-heig-dai-pw04.duckdns.org/users
HTTP/2 200
content-type: application/json
date: Wed, 15 Jan 2025 08:22:31 GMT
content-length: 2

[]⏎

Development

Use the maven wrapper to install dependencies, build and package the project.

# install the dependencies
./mvnw clean install
# build
./mvnw package
# run
java -jar target/<filename>.jar --help

Usage

Even though this application can used by simply launching the final .jar file, the recommended way to do so is by using Docker as we use a PostgreSQL database and a SWAGGER-UI client to access the OpenAPI routes documentation.

OKR can be run directly using java or through a docker container.

Building the image

As we do not use the same image on development and production stages (ie. we use a filewatcher to automatically rebuild the webapp on development but we use a traeffik container as a reverse proxy on production), you have to specify the target by using docker compose profiles.

You can build the container by cloning the repository and using:

docker build . -t dai-pw-04:latest --target <TARGET> .

Or with the compose.yml file provided

docker compose --profile <TARGET> build

Where <TARGET> is one of these values:

  • dev
  • prod

The web application will listen by default on 0.0.0.0:7000.

You can change this value by setting the JAVALIN_PORT environment variable to whatever you want. For further information, take a look at the compose.yml file.

Publishing the Docker image

You can publish the image thanks to the following commands:

# Login to GitHub Container Registry
docker login ghcr.io -u <username>

# Tag the image with the correct format
docker tag dai-pw-04 ghcr.io/<username>/dai-pw-04:latest

# Publish the image on GitHub Container Registry
docker push ghcr.io/<username>/dai-pw-04:latest
Running the image

As the image as multiple dependencies depending on the stage target (dev or prod), we first have to launch them.

Start by launching and setting up the database container. But first, let's create a docker credential file so the database password is sent securely to the container without being stored in the image.

echo "your-db-password" | docker secret create db_password -

Then, launch the container:

docker run -d \
  --name db \
  --net traefik_network \
  -p 5432:5432 \
  --shm-size=128mb \
  -e POSTGRES_ROOT_PASSWORD=<ROOT_PW> \
  -e POSTGRES_DATABASE=bdr \
  -e POSTGRES_USER=bdr \
  -e PGUSER=bdr \
  -e POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
  -e POSTGRES_PORT=5600 \
  --health-cmd="pg_isready -d db_prod" \
  --health-interval=30s \
  --health-timeout=60s \
  --health-retries=5 \
  --health-start-period=80s \
  --restart unless-stopped \
  -v $(pwd)/postgres-data:/var/lib/postgresql/data \
  -v $(pwd)/database/db.sql:/docker-entrypoint-initdb.d/create_database.sql \
  postgres

Where, <ROOT_PW> is the password of the root user.

Then, we also need the SWAGGER-UI container so we can consult the route's documentation:

docker run -d \
  --name swagger-ui \
  --net traefik_network \
  -p 8085:8080 \
  swaggerapi/swagger-ui
Development

Backend

docker run -d \
  --name backend-dev \
  --net traefik_network \
  -p 7000:7000 \
  -e DB_NAME=bdr \
  -e DB_USER=bdr \
  -e DB_SSL=false \
  -e DB_PORT=5432 \
  -v $(pwd):/app \
  backend-dev
Production

Before launching the containers, make sure you create the following .env (at the project root) file required to setup traefik:

# The image version to use for whoami
WHOAMI_IMAGE_VERSION=latest
# The email address for Let's Encrypt
TRAEFIK_ACME_EMAIL=<YOUR_EMAIL>

# The fully qualified domain name to access Traefik
TRAEFIK_FULLY_QUALIFIED_DOMAIN_NAME=<YOUR_DOMAIN>

# Enable the Traefik dashboard
TRAEFIK_ENABLE_DASHBOARD=true

# The image version to use for Traefik
TRAEFIK_IMAGE_VERSION=latest

backend

docker run -d \
  --name backend-prod \
  --net traefik_network \
  -p 7000:7000 \
  -e DB_NAME=bdr \
  -e DB_USER=bdr \
  -e DB_SSL=false \
  -e DB_PORT=5432 \
  --label traefik.enable=true \
  --label traefik.http.routers.user-api-backend.rule=Host\(`api-heig-dai-pw04.duckdns.org`\) \
  --label traefik.http.routers.user-api.entrypoints=api \
  --label traefik.http.routers.user-api-backend.tls=true \
  --label traefik.http.routers.user-api-backend.tls.certresolver=letsencrypt \
  --label traefik.http.services.user-api-backend.loadbalancer.server.port=7000 \
  backend-prod

reverse proxy

docker run -d \
  --name traefik \
  --net traefik_network \
  -p 80:80 \
  -p 443:443 \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -v $(pwd)/letsencrypt:/letsencrypt \
  --restart unless-stopped \
  -e TRAEFIK_ACME_EMAIL=your-email@example.com \
  --label traefik.enable=true \
  --label traefik.docker.network=traefik_network \
  --label traefik.http.routers.traefik.entrypoints=https \
  --label traefik.http.routers.traefik.rule=Host\(${TRAEFIK_FULLY_QUALIFIED_DOMAIN_NAME}\) \
  --label traefik.http.routers.traefik.service=api@internal \
  --label traefik.http.middlewares.test-http-cache.plugin.httpCache.maxTtl=600
  --label traefik.http.middlewares.test-http-cache.plugin.httpCache.memory.limit=3Gi
  traefik:${TRAEFIK_IMAGE_VERSION:-latest}

Or, with docker compose:

docker compose --profile dev up

production

docker compose --profile prod up
HTTP Caching

Caching has been setup using the traefik middleware. The current configuration can be found in the compose.yml file under the traefik service.

Currently, the maxTtl has been set to 600 seconds but be carefull, the time after which an HTTP response is no longer cached will be the lowest value between what is configured in maxTtl and the specified expiry time in the HTTP response headers.

We also specified a memory.limit of 3Gi for the cache. Feel free to change the configuration according to your proxy's specified memory limit.

Traefik's dashboard

Traefik's dashboard can be accessed through the following url: https://dashboard-heig-dai-pw04.duckdns.org/

Traefik's dashboard

Examples

Create

curl -i -X POST -H "Content-Type: application/json" -d '{"name": "New Project"}' https://api-heig-dai-pw04.duckdns.org/projects
HTTP/1.1 201 Created
Date: Fri, 17 Jan 2025 11:10:46 GMT
Content-Type: application/json
Last-Modified: 2025-01-17T11:10:46
Content-Length: 30

{"id":23,"name":"New Project"}

List all

curl -i -X GET https://api-heig-dai-pw04.duckdns.org/projects
HTTP/1.1 200 OK
Date: Fri, 17 Jan 2025 11:10:46 GMT
Content-Type: application/json
Content-Length: 32

[{"id":23,"name":"New Project"}]

Show

curl -i -X GET https://api-heig-dai-pw04.duckdns.org/projects/23
HTTP/1.1 200 OK
Date: Fri, 17 Jan 2025 11:10:46 GMT
Content-Type: application/json
Last-Modified: 2025-01-17T11:10:46
Content-Length: 30

{"id":23,"name":"New Project"}

Update

curl -i -X PUT -H "Content-Type: application/json" -d '{"name": "Updated Project"}' https://api-heig-dai-pw04.duckdns.org/projects/23
HTTP/1.1 204 No Content
Date: Fri, 17 Jan 2025 11:10:46 GMT
Content-Type: text/plain
Last-Modified: 2025-01-17T11:10:46

Delete

curl -i -X DELETE https://api-heig-dai-pw04.duckdns.org/projects/23

HTTP/1.1 204 No Content
Date: Fri, 17 Jan 2025 11:10:46 GMT
Content-Type: text/plain

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

(back to top)

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Contacts

(back to top)

About

An intuitive API to help individuals, teams, and organizations set, track, and achieve their objectives and key results efficiently.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages