diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a91d2178beea5110f4a15b367e52ea545fa866f3..a5322dd13132c688dbdecb1f9aee199d359de840 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,12 +1,55 @@
 variables:
-    BIN_FOLDER: /binary
-    BIN_NAME: dojo
-    VERSION_FILE: $BIN_FOLDER/VERSION
-    CLI_PROJECT_FOLDER: NodeApp
     GIT_SUBMODULE_STRATEGY: recursive
     GIT_SUBMODULE_FORCE_HTTPS: "true"
     SECURE_FILES_DOWNLOAD_PATH: './'
 
+    BIN_NAME: dojo
+
+    MACOS_PKG_EXTENSION: '.pkg'
+    MACOS_PKG_BIN_NAME: "${BIN_NAME}${MACOS_PKG_EXTENSION}"
+
+    ARTIFACTS_FOLDER: /artifacts
+
+    BIN_FOLDER_MACOS: $ARTIFACTS_FOLDER/macOS
+    BIN_FOLDER_LINUX: $ARTIFACTS_FOLDER/Linux
+    BIN_FOLDER_WINDOWS: $ARTIFACTS_FOLDER/Windows
+
+    BIN_FOLDER_MACOS_ARM64: $BIN_FOLDER_MACOS/arm64
+    BIN_FOLDER_MACOS_X64: $BIN_FOLDER_MACOS/x64
+
+    BIN_FILE_MACOS_ARM64: $BIN_FOLDER_MACOS_ARM64/$BIN_NAME
+    BIN_FILE_MACOS_X64: $BIN_FOLDER_MACOS_X64/$BIN_NAME
+    BIN_PKG_FILE_MACOS_ARM64: $BIN_FOLDER_MACOS_ARM64/$MACOS_PKG_BIN_NAME
+    BIN_PKG_FILE_MACOS_X64: $BIN_FOLDER_MACOS_X64/$MACOS_PKG_BIN_NAME
+    BIN_FILE_LINUX_ARM64: $BIN_FOLDER_LINUX/arm64/$BIN_NAME
+    BIN_FILE_LINUX_X64: $BIN_FOLDER_LINUX/x64/$BIN_NAME
+    BIN_FILE_WINDOWS_ARM64: $BIN_FOLDER_WINDOWS/arm64/$BIN_NAME.exe
+    BIN_FILE_WINDOWS_X64: $BIN_FOLDER_WINDOWS/x64/$BIN_NAME.exe
+
+    VERSION_FILE: $ARTIFACTS_FOLDER/VERSION
+    VERSION_DEV_SUFFIX: '-dev'
+
+    PROJECT_FOLDER: NodeApp
+
+    PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${BIN_NAME}"
+
+
+.get_version:
+    script:
+        - IS_DEV=$([[ $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ]] && echo false || echo true)
+        - VERSION=$(jq -r .version $PROJECT_FOLDER/package.json)$([[ $IS_DEV == true ]] && echo $VERSION_DEV_SUFFIX || echo '')
+
+.get_packages_url:
+    script:
+        - PACKAGE_URL_MACOS_ARM64_BIN="${PACKAGE_REGISTRY_URL}_macOS-arm64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_MACOS_X64_BIN="${PACKAGE_REGISTRY_URL}_macOS-x64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_MACOS_ARM64_PKG="${PACKAGE_REGISTRY_URL}_macOS-pkg-arm64/${VERSION}/${MACOS_PKG_BIN_NAME}"
+        - PACKAGE_URL_MACOS_X64_PKG="${PACKAGE_REGISTRY_URL}_macOS-pkg-x64/${VERSION}/${MACOS_PKG_BIN_NAME}"
+        - PACKAGE_URL_LINUX_ARM64_BIN="${PACKAGE_REGISTRY_URL}_Linux-arm64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_LINUX_X64_BIN="${PACKAGE_REGISTRY_URL}_Linux-x64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_WINDOWS_ARM64_BIN="${PACKAGE_REGISTRY_URL}_Windows-arm64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_WINDOWS_X64_BIN="${PACKAGE_REGISTRY_URL}_Windows-x64/${VERSION}/${BIN_NAME}"
+
 .build_cli:
     script:
         - cd NodeApp
@@ -17,86 +60,232 @@ variables:
         - npm install
         - npm run build
         # Build binaries
-        - npx pkg . -t node18-macos-arm64 --output $BIN_FOLDER/macOS/arm64/$BIN_NAME --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-macos-x64 --output $BIN_FOLDER/macOS/x64/$BIN_NAME --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-linuxstatic-arm64 --output $BIN_FOLDER/linux/arm64/$BIN_NAME --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-linuxstatic-x64 --output $BIN_FOLDER/linux/x64/$BIN_NAME --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-win-arm64 --output $BIN_FOLDER/Windows/arm64/$BIN_NAME --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-win-x64 --output $BIN_FOLDER/Windows/x64/$BIN_NAME --no-bytecode --public-packages "*" --public
-
-.macos-sign_and_pkg:
+        ## macOS
+        - npx pkg . -t node18-macos-arm64 --output $BIN_FILE_MACOS_ARM64 --no-bytecode --public-packages "*" --public
+        - npx pkg . -t node18-macos-x64 --output $BIN_FILE_MACOS_X64 --no-bytecode --public-packages "*" --public
+        ## Linux
+        - npx pkg . -t node18-linuxstatic-arm64 --output $BIN_FILE_LINUX_ARM64 --no-bytecode --public-packages "*" --public
+        - npx pkg . -t node18-linuxstatic-x64 --output $BIN_FILE_LINUX_X64 --no-bytecode --public-packages "*" --public
+        ## Windows
+        - npx pkg . -t node18-win-arm64 --output $BIN_FILE_WINDOWS_ARM64 --no-bytecode --public-packages "*" --public
+        - npx pkg . -t node18-win-x64 --output $BIN_FILE_WINDOWS_X64 --no-bytecode --public-packages "*" --public
+
+.sign_macos:
     script:
         # Sign excecutable
         - codesign --force --options=runtime --entitlements ../../../Resources/macApp/Signing/entitlements.plist --sign $SIGN_DEV_ID_APP --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp ${BIN_NAME}
         # Package and notarize the app
         - xcrun notarytool store-credentials --apple-id $SIGN_APPLE_ID --team-id $SIGN_TEAM_ID --password $SIGN_APP_PASSWORD --keychain $SIGN_LOGIN_KEYCHAIN_PATH $SIGN_KEYCHAIN_PROFILE
         - ditto ${BIN_NAME} ${BIN_NAME}_pkg/usr/local/bin/
-        - productbuild --identifier $SIGN_IDENTIFIER --version $VERSION --sign $SIGN_DEV_ID_INST --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp --root ${BIN_NAME}_pkg / ${BIN_NAME}.pkg
+        - productbuild --identifier $SIGN_IDENTIFIER --version $VERSION --sign $SIGN_DEV_ID_INST --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp --root ${BIN_NAME}_pkg / ${MACOS_PKG_BIN_NAME}
         - xcrun notarytool submit ${BIN_NAME}.pkg --keychain $SIGN_LOGIN_KEYCHAIN_PATH --keychain-profile $SIGN_KEYCHAIN_PROFILE --wait
         - xcrun stapler staple ${BIN_NAME}.pkg
         #Clean folder
         - rm -Rf ${BIN_NAME}_pkg
 
+.clean_release:
+    script:
+        # Delete release if it already exists
+        - 'curl --request DELETE --header "JOB-TOKEN: $CI_JOB_TOKEN" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases/${VERSION}"'
+
+.clean_packages:
+    script:
+        # Get all packages of the project
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages" > gitlabPackages.json'
+        # Filter and select packages to delete (based on version)
+        - packagesToDelete=`jq -r '.[] | select(.version=="'${VERSION}'") | ._links.delete_api_path' gitlabPackages.json`
+        # Delete packages by calling Gitlab API
+        - >
+            for deletePath in $packagesToDelete; do
+              echo "Deleting package at path : ${deletePath}"
+              curl --request DELETE --header "JOB-TOKEN: $CI_JOB_TOKEN" "${deletePath}"
+            done
+
+
 stages:
     - build
     - sign
+    - clean-same-release
+    - clean-dev-release
+    - upload
+    - release
 
-default:
-    image: node:latest
-    cache:
-        paths:
-            - $CLI_PROJECT_FOLDER/node_modules/
-    before_script:
-        - mkdir -p $BIN_FOLDER
-        - apt update
-        - apt install -y jq
-        - >
-            VERSION=$(jq -r .version $CLI_PROJECT_FOLDER/package.json)
 
-test:build:
+build:test:
     stage: build
     tags:
         - build
+    image: node:latest
     script:
+        - apt update
+        - apt install -y jq
+        - !reference [.get_version, script]
         - !reference [.build_cli, script]
     rules:
         - if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_COMMIT_BRANCH !~ /^v[0-9]+(\.[0-9]+)*$/'
 
-version:build:
+build:version:
     stage: build
     tags:
         - build
+    image: node:latest
     script:
+        - apt update
+        - apt install -y jq
+        - !reference [.get_version, script]
+        - mkdir -p $ARTIFACTS_FOLDER
         - echo $VERSION > $VERSION_FILE
         - !reference [.build_cli, script]
     artifacts:
         untracked: true
         paths:
-            - $BIN_FOLDER/*
+            - $ARTIFACTS_FOLDER/*
         expire_in: 1 hour
     rules:
         - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
 
-sign_macos:
+sign:macos:
     stage: sign
-    needs: ["version:build"]
-    inherit:
-        default: false
     tags:
         - macos_signing
     dependencies:
-        - version:build
+        - build:version
     script:
         - VERSION=$(cat $VERSION_FILE)
         - security unlock-keychain -p $SIGN_KEYCHAIN_PASSWORD $SIGN_LOGIN_KEYCHAIN_PATH
-        - cd $BIN_FOLDER/macOS/arm64
-        - !reference [.macos-sign_and_pkg, script]
-        - cd $BIN_FOLDER/macOS/x64
-        - !reference [.macos-sign_and_pkg, script]
+        - cd $BIN_FOLDER_MACOS_ARM64
+        - !reference [.sign_macos, script]
+        - cd $BIN_FOLDER_MACOS_X64
+        - !reference [.sign_macos, script]
     artifacts:
         paths:
-            - $BIN_FOLDER/*
-        expire_in: 1 week
+            - $ARTIFACTS_FOLDER/*
+        expire_in: 1 day
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
+
+clean:release:
+    stage: clean-same-release
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [.get_version, script]
+        - !reference [.clean_release, script]
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
+
+clean:packages:
+    stage: clean-same-release
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [.get_version, script]
+        - !reference [.clean_packages, script]
     rules:
         - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
 
+clean-dev:release:
+    stage: clean-dev-release
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [.get_version, script]
+        - VERSION="${VERSION}${VERSION_DEV_SUFFIX}"
+        - !reference [.clean_release, script]
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+
+clean-dev:packages:
+    stage: clean-dev-release
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [.get_version, script]
+        - VERSION="${VERSION}${VERSION_DEV_SUFFIX}"
+        - !reference [.clean_packages, script]
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+
+upload:packages:
+    stage: upload
+    tags:
+        - gitlab_package
+    dependencies:
+        - sign:macos
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [.get_version, script]
+        - !reference [.get_packages_url, script]
+        #macOS
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_MACOS_ARM64} "${PACKAGE_URL_MACOS_ARM64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_MACOS_X64} "${PACKAGE_URL_MACOS_X64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_MACOS_ARM64} "${PACKAGE_URL_MACOS_ARM64_PKG}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_MACOS_X64} "${PACKAGE_URL_MACOS_X64_PKG}";'
+        #Linux
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_LINUX_ARM64} "${PACKAGE_URL_LINUX_ARM64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_LINUX_X64} "${PACKAGE_URL_LINUX_X64_BIN}";'
+        #Windows
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_WINDOWS_ARM64} "${PACKAGE_URL_WINDOWS_ARM64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_WINDOWS_X64} "${PACKAGE_URL_WINDOWS_X64_BIN}";'
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
+
+release_job:
+    stage: release
+    tags:
+        - release
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [.get_version, script]
+        - !reference [.get_packages_url, script]
+        - echo 'Running release_job'
+        - CHANGELOG_LINE_START=`awk '/##\ [0-9]+\.[0-9]+\.[0-9]+/{print NR; exit;}' CHANGELOG.md`
+        - CHANGELOG_LINE_END=`awk '/##\ [0-9]+\.[0-9]+\.[0-9]+/{ count++; if(count>1) {print NR; exit;}}' CHANGELOG.md`
+        - DESCRIPTION=`awk 'NR > '$CHANGELOG_LINE_START' && NR < '$CHANGELOG_LINE_END'' CHANGELOG.md`
+        - >
+            RELEASE_DATA=$(jq --null-input --arg version "$VERSION" --arg description "# Changelog (version $VERSION) $DESCRIPTION" --arg tag_name "$VERSION" --arg ref "$CI_COMMIT_SHORT_SHA" '{
+                "name": $version,
+                "description": $description,
+                "tag_name": $tag_name,
+                "ref": $ref,
+                "assets": {
+                    "links": [
+                        {
+                          "name": "Windows (ARM64) binary",
+                          "url": "'${PACKAGE_URL_WINDOWS_ARM64_BIN}'",
+                        },{
+                            "name": "Windows (x64) binary",
+                            "url": "'${PACKAGE_URL_WINDOWS_X64_BIN}'",
+                        },{
+                            "name": "Linux (ARM64) binary",
+                            "url": "'${PACKAGE_URL_LINUX_ARM64_BIN}'",
+                        },{
+                            "name": "Linux (x64) binary",
+                            "url": "'${PACKAGE_URL_LINUX_X64_BIN}'",
+                        },{
+                            "name": "macOS (Intel) binary",
+                            "url": "'${PACKAGE_URL_MACOS_X64_BIN}'",
+                        },{
+                          "name": "macOS (Apple Silicon) binary",
+                          "url": "'${PACKAGE_URL_MACOS_ARM64_BIN}'",
+                        },{
+                            "name": "macOS (Intel) package",
+                            "url": "'${PACKAGE_URL_MACOS_X64_PKG}'",
+                        },{
+                          "name": "macOS (Apple Silicon) package",
+                          "url": "'${PACKAGE_URL_MACOS_ARM64_PKG}'",
+                        }
+                    ]                       
+                }
+            }')
+        - >
+            curl --data "${RELEASE_DATA}" \
+              --header "Content-Type: application/json" \
+              --header "JOB-TOKEN: $CI_JOB_TOKEN" \
+              --request POST "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases"
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bfc317d5fdbc189a2ab49a986655639d1d3c2537..619aa96399baa4168efc9ee2bc236f249f2664d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,29 @@
 # Changelog
 
+<!--
+### ✨ Feature
+### 🤏 Minor change
+### 🎨 Interface
+### 🐛 Bugfix
+### 🔒 Security
+### 🚀‍️ CI / CD
+### 🔨 Internal / Developers
+### 📚 Documentation
+
+**💥 Breaking:**
+**⚠️ Deprecation:**
+-->
+
 ## 2.0.0 (?)
 
-### Feature
+### ✨ Feature
 - Added license: AGPLv3
 
-### Interface
-- 🔴 Breaking: Renamed `enonce` to `assignment`
-- 🔴 Breaking: Renamed `exercice` to `exercise`
+### 🎨 Interface
+- **💥 Breaking:** Renamed `enonce` to `assignment`
+- **💥 Breaking:** Renamed `exercice` to `exercise`
 
-### Internal / Developers
+### 🔨 Internal / Developers
 - Auto release by pipeline
   - For vX.Y.Z branch create release and tag with `-dev` suffix
   - For main branch create definitive release and remove `-dev` releases
@@ -17,17 +31,5 @@
 
 ## 1.0.1 (2023-08-12)
 
-### Feature
-- Initial release of the project
-
-<!--
-### Feature
-### Minor change
-### Interface
-### Bugfix
-### Internal / Developers
-### Documentation
-
-🔴 Breaking: 
-⚠️ Deprecation: ️
--->
\ No newline at end of file
+### ✨ Feature
+- 🎉 Initial release of the project
\ No newline at end of file