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
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.
First of all, download the source code:
git clone https://github.com/HEIG-VD-S3-PW/DAI-LAB-04
cd DAI-LAB-04You 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:
-
# 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
The application can (and should) be used with docker.
To install and use docker, follow the official documentation
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
- Virtual machine name:
- 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.
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 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.orgServer: 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
In order to connect to the VM, simply type the following command:
ssh -i <PATH_TO_PRIVATE_KEY> ubuntu@api-heig-dai-pw04.duckdns.orgAs key-based authentication was already setup, it wont ask you for a password.
Even though the deployment instructions using docker can be found later in this document, all you need to do is:
- Clone or copy (using scp) the source code to the remote server
- 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=latestAlso, 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 --buildIn order to prove that all services (http/s + ssh) are running, we can run the following command:
sudo nmap api-heig-dai-pw04.duckdns.orgNmap 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
[]⏎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 --helpEven 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.
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> buildWhere <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.
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:latestAs 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 \
postgresWhere, <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-uiBackend
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-devBefore 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=latestbackend
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-prodreverse 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 upproduction
docker compose --profile prod upCaching 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 can be accessed through the following url: https://dashboard-heig-dai-pw04.duckdns.org/
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"}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"}]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"}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:46curl -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/plainContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.



