From a4ddf570c9e1fc41be356a60d81563abaeb91563 Mon Sep 17 00:00:00 2001
From: Volker Schukai <volker.schukai@schukai.com>
Date: Sat, 28 Sep 2024 18:36:01 +0200
Subject: [PATCH] fix: move from devenv to nix flake

---
 .envrc                                |   5 +-
 .gitlab-ci.yml                        |  60 +--
 Taskfile.yml                          |  64 ---
 devenv.lock                           | 190 -------
 devenv.nix                            | 715 --------------------------
 devenv.yaml                           |   7 -
 flake.lock                            | 181 +++++++
 flake.nix                             | 158 ++++++
 go.mod                                |   2 +-
 nix/config/common-packages.nix        |  73 +++
 nix/config/defaults.nix               |   2 +
 nix/config/release.nix                |  15 +
 nix/config/release.nix.template       |  15 +
 nix/packages/manual.nix               |  18 +
 nix/scripts/bash-fkt.nix              |  43 ++
 nix/scripts/build-cover-report.nix    |  60 +++
 nix/scripts/build-manual.nix          |  17 +
 nix/scripts/clean-up.nix              |  13 +
 nix/scripts/go-task.nix               | 121 +++++
 nix/scripts/release.nix               |  75 +++
 nix/scripts/run-ci-tests.nix          |  29 ++
 nix/scripts/run-extended-tests.nix    |  52 ++
 nix/scripts/run-tests.nix             |  72 +++
 nix/scripts/update-changelog.nix      |  76 +++
 nix/scripts/update-inputs.nix         |  44 ++
 nix/scripts/update-manual-summary.nix |  91 ++++
 nix/scripts/update-project.nix        |  85 +++
 27 files changed, 1265 insertions(+), 1018 deletions(-)
 delete mode 100644 Taskfile.yml
 delete mode 100644 devenv.lock
 delete mode 100644 devenv.nix
 delete mode 100644 devenv.yaml
 create mode 100644 flake.lock
 create mode 100644 flake.nix
 create mode 100644 nix/config/common-packages.nix
 create mode 100644 nix/config/defaults.nix
 create mode 100644 nix/config/release.nix
 create mode 100644 nix/config/release.nix.template
 create mode 100644 nix/packages/manual.nix
 create mode 100644 nix/scripts/bash-fkt.nix
 create mode 100644 nix/scripts/build-cover-report.nix
 create mode 100644 nix/scripts/build-manual.nix
 create mode 100644 nix/scripts/clean-up.nix
 create mode 100644 nix/scripts/go-task.nix
 create mode 100644 nix/scripts/release.nix
 create mode 100644 nix/scripts/run-ci-tests.nix
 create mode 100644 nix/scripts/run-extended-tests.nix
 create mode 100644 nix/scripts/run-tests.nix
 create mode 100644 nix/scripts/update-changelog.nix
 create mode 100644 nix/scripts/update-inputs.nix
 create mode 100644 nix/scripts/update-manual-summary.nix
 create mode 100644 nix/scripts/update-project.nix

diff --git a/.envrc b/.envrc
index 6de8a8a..0da5bcc 100644
--- a/.envrc
+++ b/.envrc
@@ -1,3 +1,2 @@
-source_url "https://raw.githubusercontent.com/cachix/devenv/d1f7b48e35e6dee421cfd0f51481d17f77586997/direnvrc" "sha256-YBzqskFZxmNb3kYVoKD9ZixoPXJh1C9ZvTLGFRkauZ0="
-
-use devenv
\ No newline at end of file
+watch_file ./flake.nix ./nix/scripts/*.nix ./nix/config/*.nix ./nix/packages/*.nix 
+use flake
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1bc73eb..78b9b3f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,59 +1,43 @@
-
-# THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
-# DO NOT EDIT THIS FILE MANUALLY
-# INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix
-# AND OPEN A SHELL WITH THE COMMAND devenv shell
-#
-
-image: docker-registry.schukai.com:443/nixos-ci-devenv:latest
-
 variables:
-  # The repo name as used in
-  # https://github.com/nix-community/NUR/blob/master/repos.json
-  NIXOS_VERSION: "23.05"
   NIXPKGS_ALLOW_UNFREE: "1"
   NIXPKGS_ALLOW_INSECURE: "1"
   GIT_DEPTH: 10
+  GIT_SUBMODULE_STRATEGY: normal
+  GIT_SUBMODULE_DEPTH: 1
+
 
 stages:
   - test
-  - deploy 
+  - release
 
 before_script:
-  - echo > .env-gitlab-ci
-  - variables=("HOME=$HOME" "CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME" "CI_REPOSITORY_URL=$CI_REPOSITORY_URL" "GITLAB_TOKEN=$GITLAB_TOKEN" "CI_JOB_TOKEN=$CI_JOB_TOKEN" "GITLAB_USER_EMAIL=$GITLAB_USER_EMAIL" "GITLAB_USER_NAME=\"$GITLAB_USER_NAME\"" "CI_REGISTRY_USER=$CI_REGISTRY_USER" "CI_PROJECT_ID=$CI_PROJECT_ID" "CI_PROJECT_DIR=$CI_PROJECT_DIR" "CI_API_V4_URL=$CI_API_V4_URL" "CI_PROJECT_NAME=$CI_PROJECT_NAME" "CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA"); for var in "${variables[@]}"; do echo "$var" >> .env-gitlab-ci; done
-  - cat .env-gitlab-ci
+  - git config --global user.email "${GITLAB_USER_EMAIL}"
+  - git config --global user.name "${GITLAB_USER_NAME:-"Gitlab CI"}"
+  - git config --global credential.helper '!f() { echo "username=gitlab-ci-token"; echo "password=${CI_JOB_TOKEN}"; }; f'
+  - git config --global pull.rebase true
+  - git config --global http.sslVerify "false"
+
 
 after_script:
-  - if [ -f .env-gitlab-ci ]; then rm .env-gitlab-ci; fi
+  - nix develop .#gitlab --command clean-up
 
-test:
+tests:
   stage: test
   tags:
-    - nixos
+    - nixos-gen3
   script:
-    - devenv shell test-lib
-
-  cache:
-    - key: nixos
-      paths:
-        - /nix/store
-  
+    - nix develop .#gitlab --command run-ci-tests
   artifacts:
     paths:
-      - dist
+      - last-phpunit-result.xml
 
-deploy:
-  stage: deploy
+release:
+  stage: release
   tags:
-    - nixos
+    - nixos-gen3
   script:
-    - devenv shell -c deploy-lib
-
+    - nix develop .#gitlab --command release
   when: on_success
-
-  cache:
-    - key: nixos
-      paths:
-        - /nix/store
-
+  rules:
+    - if: $CI_COMMIT_BRANCH == "master"
+  
\ No newline at end of file
diff --git a/Taskfile.yml b/Taskfile.yml
deleted file mode 100644
index b48a18a..0000000
--- a/Taskfile.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-
-# THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
-# DO NOT EDIT THIS FILE MANUALLY
-# INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix 
-# AND OPEN A SHELL WITH THE COMMAND devenv shell
-#
-# Information about the task runner can be found here:
-# https://taskfile.dev
-
-version: '3'
-
-tasks:
-  default: 
-    cmds:
-      - task --list
-    silent: true
-    
-  test:
-    desc: Execute unit tests in Go.
-    env:
-      TEST_BY_TASK: true
-    cmds:
-      - echo "Execute unit tests in Go."
-      - gosec .
-      - go test -tags=runOnTask -cover -v ./...
-      - go test -tags=runOnTask -bench -v ./...
-      - go test -tags=runOnTask -race -v ./...
-
-  test-fuzz:
-    desc: Conduct fuzzing tests.#
-    env:
-      TEST_BY_TASK: true
-    cmds:  
-      - echo "Conduct fuzzing tests."
-      - go test -tags=runOnTask -v -fuzztime=30s -fuzz=Fuzz ./...
-
-  add-licenses:
-    desc: Attach license headers to Go files.
-    cmds:
-      - echo "Attach license headers to Go files."
-      - go install github.com/google/addlicense@latest
-      - addlicense -c "schukai GmbH" -s -l "AGPL-3.0" ./*.go
-    silent: true
-    
-  check-licenses:
-    desc: Check license headers of Go files.
-    silent: true
-    cmds:
-      - go-licenses save "$(get-go-default-packages)"  --ignore "gitlab.schukai.com"  --force --save_path ${DEVENV_ROOT}/licenses/
-
-  check:
-    desc: Confirm repository status.
-    cmds:
-      - git diff-index --quiet HEAD || (echo "There are uncommitted changes after running make. Please commit or stash them before running make."; exit 1)
-    silent: true
-
-  commit:
-    desc: Commit changes to the repository.
-    aliases:
-      - c
-      - ci
-      - git-commit
-    cmds:
-      - do-git-commit
diff --git a/devenv.lock b/devenv.lock
deleted file mode 100644
index 37e09b7..0000000
--- a/devenv.lock
+++ /dev/null
@@ -1,190 +0,0 @@
-{
-  "nodes": {
-    "devenv": {
-      "locked": {
-        "dir": "src/modules",
-        "lastModified": 1698243190,
-        "narHash": "sha256-n+SbyNQRhUcaZoU00d+7wi17HJpw/kAUrXOL4zRcqE8=",
-        "owner": "cachix",
-        "repo": "devenv",
-        "rev": "86f476f7edb86159fd20764489ab4e4df6edb4b6",
-        "type": "github"
-      },
-      "original": {
-        "dir": "src/modules",
-        "owner": "cachix",
-        "repo": "devenv",
-        "type": "github"
-      }
-    },
-    "flake-compat": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1673956053,
-        "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "type": "github"
-      }
-    },
-    "flake-utils": {
-      "inputs": {
-        "systems": "systems"
-      },
-      "locked": {
-        "lastModified": 1685518550,
-        "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "gitignore": {
-      "inputs": {
-        "nixpkgs": [
-          "pre-commit-hooks",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1660459072,
-        "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
-        "owner": "hercules-ci",
-        "repo": "gitignore.nix",
-        "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
-        "type": "github"
-      },
-      "original": {
-        "owner": "hercules-ci",
-        "repo": "gitignore.nix",
-        "type": "github"
-      }
-    },
-    "nixpkgs": {
-      "locked": {
-        "lastModified": 1702346276,
-        "narHash": "sha256-eAQgwIWApFQ40ipeOjVSoK4TEHVd6nbSd9fApiHIw5A=",
-        "owner": "nixos",
-        "repo": "nixpkgs",
-        "rev": "cf28ee258fd5f9a52de6b9865cdb93a1f96d09b7",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nixos",
-        "ref": "nixos-23.11",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs-stable": {
-      "locked": {
-        "lastModified": 1685801374,
-        "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "c37ca420157f4abc31e26f436c1145f8951ff373",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-23.05",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_2": {
-      "locked": {
-        "lastModified": 1698288402,
-        "narHash": "sha256-jIIjApPdm+4yt8PglX8pUOexAdEiAax/DXW3S/Mb21E=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "60b9db998f71ea49e1a9c41824d09aa274be1344",
-        "type": "github"
-      },
-      "original": {
-        "id": "nixpkgs",
-        "ref": "nixos-23.05",
-        "type": "indirect"
-      }
-    },
-    "pre-commit-hooks": {
-      "inputs": {
-        "flake-compat": "flake-compat",
-        "flake-utils": "flake-utils",
-        "gitignore": "gitignore",
-        "nixpkgs": [
-          "nixpkgs"
-        ],
-        "nixpkgs-stable": "nixpkgs-stable"
-      },
-      "locked": {
-        "lastModified": 1698227354,
-        "narHash": "sha256-Fi5H9jbaQLmLw9qBi/mkR33CoFjNbobo5xWdX4tKz1Q=",
-        "owner": "cachix",
-        "repo": "pre-commit-hooks.nix",
-        "rev": "bd38df3d508dfcdff52cd243d297f218ed2257bf",
-        "type": "github"
-      },
-      "original": {
-        "owner": "cachix",
-        "repo": "pre-commit-hooks.nix",
-        "type": "github"
-      }
-    },
-    "root": {
-      "inputs": {
-        "devenv": "devenv",
-        "nixpkgs": "nixpkgs",
-        "pre-commit-hooks": "pre-commit-hooks",
-        "version": "version"
-      }
-    },
-    "systems": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
-    "version": {
-      "inputs": {
-        "nixpkgs": "nixpkgs_2"
-      },
-      "locked": {
-        "lastModified": 1690668568,
-        "narHash": "sha256-jzixQKFFW4oxO0S4GYqbkFCXzhBd6com6Z9+MtVKakU=",
-        "ref": "refs/heads/master",
-        "rev": "3838f03165b726e47d586c04a1821749375e1001",
-        "revCount": 37,
-        "type": "git",
-        "url": "https://gitlab.schukai.com/oss/utilities/version.git"
-      },
-      "original": {
-        "type": "git",
-        "url": "https://gitlab.schukai.com/oss/utilities/version.git"
-      }
-    }
-  },
-  "root": "root",
-  "version": 7
-}
diff --git a/devenv.nix b/devenv.nix
deleted file mode 100644
index a32c8d7..0000000
--- a/devenv.nix
+++ /dev/null
@@ -1,715 +0,0 @@
-{ pkgs ? import <nixpkgs> {}, inputs, phps, lib, config, modulesPath, ... }:
-
-{
-  # https://devenv.sh/packages/
-  packages = with pkgs; [
-    inputs.version.defaultPackage."${builtins.currentSystem}"
-    appimage-run
-    blackbox
-    blackbox-terminal
-    coreutils-full
-    dbeaver
-    dbeaver
-    delve
-    dialog
-    drill
-    eza
-    fd
-    fd
-    feh
-    gcc12
-    gdlv
-    git
-    glab
-    gnugrep
-    gnumake
-    gnused
-    go-licenses
-    gosec
-    go-task
-    gum
-    httpie
-    hurl
-    jq
-    libffi
-    logrotate
-    meld
-    memcached
-    netcat
-    nixfmt
-    nodePackages.mermaid-cli
-    openssh
-    procps
-    ranger
-    unixtools.xxd
-    unzip
-    util-linux
-    wget
-    zlib
-  ];
-
-  # https://devenv.sh/languages/
-  # languages.nix.enable = true;
-  languages = { go = { enable = true; }; };
-
-  difftastic.enable = true;
-  
-  scripts.get-go-default-packages.exec = ''
-    #!${pkgs.bash}/bin/bash
-    echo $(awk -F ' ' '/^module / { print $2 }' go.mod)
-  '';
-
-  # This script is executed when the app is built
-  # You can use it to build the app  
-  scripts.test-lib.exec = ''
-    #!${pkgs.bash}/bin/bash
-    #set -euo pipefail
-    set -x
-    
-    PATH="''${PATH}":${pkgs.coreutils}/bin
-    PATH="''${PATH}":${pkgs.findutils}/bin
-    PATH="''${PATH}":${pkgs.jq}/bin/
-    PATH="''${PATH}":${pkgs.rsync}/bin/
-    PATH="''${PATH}":${pkgs.bash}/bin/
-    PATH="''${PATH}":${pkgs.curl}/bin/
-    PATH="''${PATH}":${pkgs.moreutils}/bin/
-    PATH="''${PATH}":${pkgs.gnutar}/bin
-    PATH="''${PATH}":${pkgs.gzip}/bin/
-    PATH="''${PATH}":${pkgs.procps}/bin/
-    PATH="''${PATH}":${pkgs.eza}/bin/
-    PATH="''${PATH}":${pkgs.git}/bin/
-    PATH="''${PATH}":${pkgs.gnugrep}/bin/
-    PATH="''${PATH}":${
-      inputs.version.defaultPackage."${builtins.currentSystem}"
-    }/bin/
-
-    export PATH
-
-    task test
-
-  '';
-
-  # This scritp is used to deploy the app to the gitlab registry
-  # It is used by the gitlab-ci.yml file
-  # The environment variables are set in the gitlab project settings
-  scripts.deploy-lib.exec = ''
-    #!${pkgs.bash}/bin/bash
-
-    PATH="''${PATH}":${pkgs.coreutils}/bin
-    PATH="''${PATH}":${pkgs.jq}/bin/
-    PATH="''${PATH}":${pkgs.curl}/bin/
-    PATH="''${PATH}":${pkgs.moreutils}/bin/
-    PATH="''${PATH}":${pkgs.gnutar}/bin
-    PATH="''${PATH}":${pkgs.gzip}/bin/
-    PATH="''${PATH}":${pkgs.eza}/bin/
-    PATH="''${PATH}":${pkgs.git}/bin/
-    PATH="''${PATH}":${
-      inputs.version.defaultPackage."${builtins.currentSystem}"
-    }/bin/
-
-    export PATH
-
-    if [[ -f .env-gitlab-ci ]]; then
-        source .env-gitlab-ci
-        rm .env-gitlab-ci
-    fi
-
-    set -x
-    ## if $HOME not set, set it to current directory
-    if [[ -z "''${HOME}" ]]; then
-        HOME=$(pwd)
-    fi
-
-    export HOME
-
-    git config user.email "''${GITLAB_USER_EMAIL}"
-    git config user.name "''${GITLAB_USER_NAME:-"Gitlab CI"}"
-    git config pull.rebase true
-    git config http.sslVerify "false"
-    git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@}
-
-    git fetch --all --tags --unshallow
-    git reset --hard origin/master
-    git checkout $CI_COMMIT_REF_NAME
-    git pull origin $CI_COMMIT_REF_NAME
-
-    if [ ! -z "''${CI_PROJECT_DIR}" ]; then
-        echo "CI_PROJECT_DIR is set, using it as project root."
-        project_root=$(realpath "''${CI_PROJECT_DIR}")/
-    elif [ ! -z "''${DEVENV_ROOT}" ]; then
-        echo "DEVENV_ROOT is set, using it as project root."
-        project_root=$(realpath "''${DEVENV_ROOT}")/
-    else
-        echo "Error: DEVENV_ROOT or CI_PROJECT_DIR environment variables are not set."
-        exit 1  
-    fi
-
-    if [ ! -d "''${project_root}" ]; then
-        echo "Error: Project root directory does not seem to be valid."
-        echo "Check the DEVENV_ROOT or CI_PROJECT_DIR environment variables."
-        exit 1
-    fi
-
-    if [ -z "'CI_JOB_TOKEN" ]; then
-        echo "Error: CI_JOB_TOKEN variable is not set."
-        exit 1
-    fi
-
-    git --no-pager log --decorate=short --pretty=oneline
-    gitVersion=v$(version predict)
-    git tag -a $gitVersion -m"chore: bump version" 
-    git --no-pager log --decorate=short --pretty=oneline
-    git push -o ci.skip origin ''${CI_COMMIT_REF_NAME} --tags
-
-    echo "done"
-
-  '';
-
-  enterShell = ''
-       
-cat <<'EOF' > CONTRIBUTING.md
-# Contributing to schukai GmbH Projects
-
-## Code of Conduct
-
-Be a human, not an asshole. Common sense and basic human decency apply.
-
-## Getting Started
-
-### Setting up the Project
-
-1. Fork the project on GitLab.
-2. Clone your fork locally. Replace `[your-username]` with your GitLab username and `[project-name]` with the actual project name:
-    ```bash
-    git clone $(git config --get remote.origin.url)
-    ```
-3. Add the upstream repository. Replace `[original-username]` and `[project-name]` with the original repository's username and project name:
-    ```bash
-    git remote add upstream https://gitlab.schukai.com/[original-username]/[project-name].git
-    ```
-
-### Making Changes
-
-1. Create a new branch:
-    ```bash
-    git checkout -b new-feature-branch
-    ```
-2. Make your changes.
-3. Commit your changes:
-    ```bash
-    git commit -m "Description of change"
-    ```
-
-### Submitting a Merge Request
-
-1. Push your changes to your fork:
-    ```bash
-    git push origin new-feature-branch
-    ```
-2. Navigate to the original project repository on `gitlab.schukai.com`.
-3. Open a Merge Request and provide a clear description of the changes.
-
-## Coding Guidelines
-
-- Follow the coding style used in the project.
-- Write unit tests for new features.
-- Ensure that all tests pass before submitting a Merge Request.
-
-## Reporting Issues
-
-If you find an issue, please create a new issue on `gitlab.schukai.com`.
-
-## Additional Resources
-
-- [GitLab Flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html)
-- [GitLab Merge Request Guidelines](https://docs.gitlab.com/ee/user/project/merge_requests/)
-
-Thank you for your contribution! 
-    
-EOF
-    
-cat <<'EOF' > LICENSE
-Copyright (C) 2023 schukai GmbH 
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published
-by the Free Software Foundation, either version 3 of the License.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <https://www.gnu.org/licenses/>.  
-    
-EOF
- 
-cat <<'EOF' > Taskfile.yml
-
-# THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
-# DO NOT EDIT THIS FILE MANUALLY
-# INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix 
-# AND OPEN A SHELL WITH THE COMMAND devenv shell
-#
-# Information about the task runner can be found here:
-# https://taskfile.dev
-
-version: '3'
-
-tasks:
-  default: 
-    cmds:
-      - task --list
-    silent: true
-    
-  test:
-    desc: Execute unit tests in Go.
-    env:
-      TEST_BY_TASK: true
-    cmds:
-      - echo "Execute unit tests in Go."
-      - gosec .
-      - go test -tags=runOnTask -cover -v ./...
-      - go test -tags=runOnTask -bench -v ./...
-      - go test -tags=runOnTask -race -v ./...
-
-  test-fuzz:
-    desc: Conduct fuzzing tests.#
-    env:
-      TEST_BY_TASK: true
-    cmds:  
-      - echo "Conduct fuzzing tests."
-      - go test -tags=runOnTask -v -fuzztime=30s -fuzz=Fuzz ./...
-
-  add-licenses:
-    desc: Attach license headers to Go files.
-    cmds:
-      - echo "Attach license headers to Go files."
-      - go install github.com/google/addlicense@latest
-      - addlicense -c "schukai GmbH" -s -l "AGPL-3.0" ./*.go
-    silent: true
-    
-  check-licenses:
-    desc: Check license headers of Go files.
-    silent: true
-    cmds:
-      - go-licenses save "$(get-go-default-packages)"  --ignore "gitlab.schukai.com"  --force --save_path ''${DEVENV_ROOT}/licenses/
-
-  check:
-    desc: Confirm repository status.
-    cmds:
-      - git diff-index --quiet HEAD || (echo "There are uncommitted changes after running make. Please commit or stash them before running make."; exit 1)
-    silent: true
-
-  commit:
-    desc: Commit changes to the repository.
-    aliases:
-      - c
-      - ci
-      - git-commit
-    cmds:
-      - do-git-commit
-EOF
-
-cat <<'EOF' > .gitlab-ci.yml
-
-# THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
-# DO NOT EDIT THIS FILE MANUALLY
-# INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix
-# AND OPEN A SHELL WITH THE COMMAND devenv shell
-#
-
-image: docker-registry.schukai.com:443/nixos-ci-devenv:latest
-
-variables:
-  # The repo name as used in
-  # https://github.com/nix-community/NUR/blob/master/repos.json
-  NIXOS_VERSION: "23.05"
-  NIXPKGS_ALLOW_UNFREE: "1"
-  NIXPKGS_ALLOW_INSECURE: "1"
-  GIT_DEPTH: 10
-
-stages:
-  - test
-  - deploy 
-
-before_script:
-  - echo > .env-gitlab-ci
-  - variables=("HOME=$HOME" "CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME" "CI_REPOSITORY_URL=$CI_REPOSITORY_URL" "GITLAB_TOKEN=$GITLAB_TOKEN" "CI_JOB_TOKEN=$CI_JOB_TOKEN" "GITLAB_USER_EMAIL=$GITLAB_USER_EMAIL" "GITLAB_USER_NAME=\"$GITLAB_USER_NAME\"" "CI_REGISTRY_USER=$CI_REGISTRY_USER" "CI_PROJECT_ID=$CI_PROJECT_ID" "CI_PROJECT_DIR=$CI_PROJECT_DIR" "CI_API_V4_URL=$CI_API_V4_URL" "CI_PROJECT_NAME=$CI_PROJECT_NAME" "CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA"); for var in "''${variables[@]}"; do echo "$var" >> .env-gitlab-ci; done
-  - cat .env-gitlab-ci
-
-after_script:
-  - if [ -f .env-gitlab-ci ]; then rm .env-gitlab-ci; fi
-
-test:
-  stage: test
-  tags:
-    - nixos
-  script:
-    - devenv shell test-lib
-
-  cache:
-    - key: nixos
-      paths:
-        - /nix/store
-  
-  artifacts:
-    paths:
-      - dist
-
-deploy:
-  stage: deploy
-  tags:
-    - nixos
-  script:
-    - devenv shell -c deploy-lib
-
-  when: on_success
-
-  cache:
-    - key: nixos
-      paths:
-        - /nix/store
-
-EOF
-        
-  '';
-
-  scripts.do-git-commit.exec = ''
-    #!/usr/bin/env bash
-
-    # Define colors if the terminal supports it
-    if [ -t 1 ]; then
-      RED='\033[0;31m'
-      GREEN='\033[0;32m'
-      RESET='\033[0m'
-      BOLD='\033[1m'
-    else
-      RED=""
-      GREEN=""
-      RESET=""
-    fi
-
-    step=1
-
-    reset
-    clear
-
-    # create random log file
-    LOGFILE="$(mktemp)"
-    if [ $? -ne 0 ]; then
-      echo -e "''${RED}✖ Could not create temporary log file. Exiting.''${RESET}"
-      exit 1
-    fi
-
-    log_and_display() {
-      echo -e "''${GREEN}==> $step. $1''${RESET}" | tee -a $LOGFILE
-      step=$((step + 1))
-    }
-
-    log_error_and_display() {
-      echo -e "''${RED}==> $step. $1''${RESET}" | tee -a $LOGFILE
-    }
-
-    printLogfileAndExit() {
-      exit_code=$1
-      echo -e "\n\n========================================\n\n\n"
-
-      echo -e "\n\n''${BOLD}Git and GitLab Automation Script''${RESET}\n\nI have performed the following actions:\n\n"
-      cat "$LOGFILE"
-
-      # Optional: Remove log file
-      rm -f "$LOGFILE"
-
-      if [ $exit_code -eq 0 ]; then
-        echo -e "\n''${GREEN}✔''${RESET} All actions were successful" | tee -a $LOGFILE
-      elif [ $exit_code -eq -1 ]; then
-        echo -e "\n''${RED}✖''${RESET} The script was manually cancelled" | tee -a $LOGFILE
-        exit_code=0
-      else
-        echo -e "\n''${RED}✖''${RESET} Some actions failed" | tee -a $LOGFILE
-      fi
-
-      exit $exit_code
-    }
-
-    print_headline() {
-      local title=$1
-      local underline=$(printf '─%.0s' $(seq 1 ''${#title}))
-      echo -e "\n\n''${BOLD}''${title}\n''${underline}''${RESET}\n"
-    }
-
-    do_cancel() {
-      echo -e "''${RED}==> ✖ Cancelled.''${RESET}" | tee -a $LOGFILE
-      printLogfileAndExit -1
-    }
-
-    # Function for unified logging and display
-    log_action() {
-      if [ $? -eq 0 ]; then
-        echo -e "    ''${GREEN}✔''${RESET} $1: Successful" | tee -a $LOGFILE
-      else
-        echo -e "    ''${RED}✖''${RESET} $1: Failed" | tee -a $LOGFILE
-        printLogfileAndExit 1
-      fi
-    }
-
-    print_what_to_do() {
-      echo -e "\n\nWhat do you want to do?\n"
-    }
-
-    git_status=$(git status --porcelain)
-    if [[ -z "$git_status" ]]; then
-      log_error_and_display "No changes to commit. Exiting."
-      printLogfileAndExit 0
-    fi
-
-    print_headline "Choose commit type"
-    selection=$(gum choose "feat: (new feature for the user, not a new feature for build script)" "fix: (bug fix for the user, not a fix to a build script)" "chore: (updating grunt tasks etc.; no production code change)" "docs: (changes to the documentation)" "style: (formatting, missing semi colons, etc; no production code change)" "refactor: (refactoring production code, eg. renaming a variable)" "test: (adding missing tests, refactoring tests; no production code change)" "Cancel")
-
-    commit_type=$(echo "$selection" | awk -F':' '{print $1}')
-
-    if [[ "$commit_type" == "Cancel" ]]; then
-      do_cancel
-    fi
-
-    log_and_display "You chose the commit type: $commit_type"
-
-    # NEXT STEP ISSUE HANDLING ############################################################################################################
-    #log_and_display "Issue handling"
-
-    gitlabIssues=()
-    while IFS= read -r line; do
-      if [[ $line =~ ^# ]]; then
-        id=$(echo "$line" | awk '{print substr($1, 2)}')
-        title=$(echo "$line" | awk -F'about' '{print $1}' | awk '{$1=$2=""; print substr($0, 3)}')
-        gitlabIssues+=("$id > $title")
-      fi
-    done < <(gum spin --spinner dot --show-output --title "Ask gitlab ..." -- glab issue list --output-format=details)
-
-    ## if issues are available, ask if user wants to use an existing issue or create a new one
-    createOption="Create new issue"
-    existingOption="Use existing issue"
-    cancelOption="Cancel"
-
-    print_headline "Choose issue handling"
-    if [ ''${#gitlabIssues[@]} -eq 0 ]; then
-      log_and_display "There are no issues available."
-
-      print_what_to_do
-      choice=$(gum choose "$createOption" "$cancelOption")
-
-    else
-      log_and_display "There are ''${#gitlabIssues[@]} issues available."
-      print_what_to_do
-      choice=$(gum choose "$createOption" "$existingOption" "$cancelOption")
-    fi
-
-    if [[ "$choice" == "$cancelOption" ]]; then
-      do_cancel
-    fi
-
-    ## array of issue ids
-    work_on_issue_ids=()
-
-    issue_text=""
-
-    if [[ "$choice" == "$createOption" ]]; then
-      print_headline "Create new issue"
-      issue_text=$(gum input --placeholder "Enter issue title")
-      echo -e "Enter issue description. ''${RED}End with Ctrl+D''${RESET}\n"
-      issue_description=$(gum write --placeholder "Enter issue description. End with Ctrl+D")
-      
-      if [[ -z "$issue_text" ]]; then
-        log_error_and_display "Issue title is empty. Exiting."
-        printLogfileAndExit 1
-      fi
-
-      log_and_display "You entered the issue title: $issue_text"
-      log_and_display "You entered the issue description: $issue_description"
-      echo -e "\n"
-
-      gum confirm "Do you want to create this issue?"
-      # gum confirm exits with status 0 if confirmed and status 1 if cancelled.
-      if [ $? -eq 1 ]; then
-        do_cancel
-      fi
-
-      issue_output=$(glab issue create -t"$issue_text" --no-editor --description "$issue_description")
-      issue_id=$(echo "$issue_output" | grep -oP '(?<=/issues/)\d+')
-
-      work_on_issue_ids+=("$issue_id")
-
-      log_action "glab issue with id $issue_id created"
-
-    else
-
-      print_headline "Use existing issue"
-      echo -e "Select issue with arrow keys and press tab or space to select. Press enter to confirm.\n"
-      issue_ids=$(gum choose --no-limit "''${gitlabIssues[@]}")
-
-      # assign issue_ids to work_on_issue_ids. iterate over lines and take integer from beginning of line
-      while IFS= read -r line; do
-        work_on_issue_ids+=($(echo "$line" | grep -oP '^\d+'))
-      done <<<"$issue_ids"
-
-    fi
-
-    if [ ''${#work_on_issue_ids[@]} -eq 0 ]; then
-      log_and_display "No issue selected. Exiting."
-      printLogfileAndExit 0
-    fi 
-
-    # NEXT STEP COMMIT MESSAGE ############################################################################################################
-    # print work_on_issue_ids
-    work_on_issue_ids_string=""
-    for i in "''${work_on_issue_ids[@]}"; do
-      work_on_issue_ids_string+="#$i "
-    done
-
-    log_and_display "You chose to work on the following issues: ''${work_on_issue_ids_string}"
-
-
-    print_headline "Check for changes to commit"
-
-    # ' ' = unmodified
-    # M = modified
-    # T = file type changed (regular file, symbolic link or submodule)
-    # A = added
-    # D = deleted
-    # R = renamed
-    # C = copied (if config option status.renames is set to "copies")
-    # U = updated but unmerged
-    # https://man.freebsd.org/cgi/man.cgi?query=git-status&sektion=1&manpath=freebsd-release-ports
-
-    count_all_changes=$(echo "$git_status" | wc -l)
-    count_staged_changes=$(echo "$git_status" | grep -c '^M')
-    count_new_staged_files=$(echo "$git_status" | grep -c '^A')
-    count_staged_changes=$((count_staged_changes + count_new_staged_files))
-
-
-
-    git_options_all="All $count_all_changes changes"
-    git_options_staged="Only the $count_staged_changes staged changes"
-    git_options_select_files="Select files"
-    git_options_cancel="Cancel"
-
-    git_options_array=()
-    if [[ $count_all_changes -gt 0 ]]; then
-      git_options_array+=("$git_options_all")
-    fi
-
-    if [[ $count_staged_changes -gt 0 ]]; then
-      git_options_array+=("$git_options_staged")
-    fi
-
-    git_options_array+=( "$git_options_select_files" )
-    git_options_array+=( "$git_options_cancel" )
-
-
-    selection=$(gum choose "''${git_options_array[@]}")
-    if [[ "$selection" == "$git_options_cancel" ]]; then
-      do_cancel
-    fi
-
-    if [[ "$selection" == "$git_options_all" ]]; then
-      git add -A
-      echo "1"
-    elif [[ "$selection" == "$git_options_select_files" ]]; then
-
-      files=()
-      while IFS= read -r line; do
-        files+=("$line")
-      done <<<"$git_status"
-        
-      selected_files=$(gum choose --no-limit "''${files[@]}")
-      
-      # no files selected
-      if [[ -z "$selected_files" ]]; then
-        log_and_display "No files selected. Exiting."
-        printLogfileAndExit 0
-      fi
-
-      # add selected files
-      while IFS= read -r line; do
-        ## git proclimne could have letter, ? or ! at the beginning of the line
-        file=$(echo "$line" | awk '{print $2}')
-        if [[ -z "$file" || ! -f "$file" ]]; then
-          log_and_display "No file found in line: $line"
-          continue
-        fi
-        
-        git add "$file"
-      done <<<"$selected_files"
-      
-    fi
-
-    ## count staged changes again and print
-    count_staged_changes=$(echo "$git_status" | grep -c '^M')
-    count_new_staged_files=$(echo "$git_status" | grep -c '^A')
-    count_staged_changes=$((count_staged_changes + count_new_staged_files))
-
-    log_and_display "You have $count_staged_changes staged changes to commit."
-
-    # NEXT STEP COMMIT MESSAGE ############################################################################################################
-
-    print_headline "Enter commit message"
-    commit_message=$(gum input --placeholder "Enter commit message" --value "$commit_type: $issue_text $work_on_issue_ids_string")
-
-    if [[ -z "$commit_message" ]]; then
-      log_error_and_display "Commit message is empty. Exiting."
-      printLogfileAndExit 1
-    fi
-
-    log_and_display "You entered the commit message: $commit_message"
-
-    gum confirm "Do you want to commit with this message?"
-    if [ $? -eq 1 ]; then
-      do_cancel
-    fi
-
-    # NEXT STEP COMMIT ####################################################################################################################
-    print_headline "Committing changes"
-
-    if ! git commit -m "$commit_message" ; then
-      log_error_and_display "Commit failed. Exiting."
-      printLogfileAndExit 1
-    fi
-
-    log_and_display "Commit successful."
-
-    # NEXT STEP PUSH ######################################################################################################################
-
-    print_headline "Pushing changes"
-
-    if ! git push ; then
-      log_error_and_display "Push failed. Exiting."
-      printLogfileAndExit 1
-    fi
-
-    log_and_display "Push successful."
-
-    # Close issue ######################################################################################################################
-
-    print_headline "Closing issues"
-
-    for issue_id in "''${work_on_issue_ids[@]}"; do
-      
-      gum confirm "Do you want to close issue #$issue_id?"
-      if [ $? -eq 1 ]; then
-        continue
-      fi
-      
-      if ! glab issue close "$issue_id" ; then
-        log_error_and_display "Closing issue $issue_id failed. Exiting."
-      else
-        log_and_display "Closing issue $issue_id successful."  
-      fi
-    done
-
-    printLogfileAndExit 0
-  '';
-
-
-}
diff --git a/devenv.yaml b/devenv.yaml
deleted file mode 100644
index 1fd1de9..0000000
--- a/devenv.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-inputs:
-  nixpkgs:
-    url: github:nixos/nixpkgs/nixos-23.11
-
-  version:
-    url: git+https://gitlab.schukai.com/oss/utilities/version.git
-    flake: true
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..fd83cb2
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,181 @@
+{
+  "nodes": {
+    "commonFlake": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      },
+      "locked": {
+        "dir": "common",
+        "lastModified": 1718788884,
+        "narHash": "sha256-PefMbkGNMK9TN1qcNL9OkFVTNdv6wo6XoaS8eTdsY04=",
+        "ref": "refs/heads/master",
+        "rev": "abda2dc723e13dfc835535593321c514666e679e",
+        "revCount": 39,
+        "type": "git",
+        "url": "https://gitlab.schukai.com/schukai/entwicklung/nix-flakes.git?dir=common"
+      },
+      "original": {
+        "dir": "common",
+        "type": "git",
+        "url": "https://gitlab.schukai.com/schukai/entwicklung/nix-flakes.git?dir=common"
+      }
+    },
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1726560853,
+        "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
+        "type": "github"
+      },
+      "original": {
+        "id": "flake-utils",
+        "type": "indirect"
+      }
+    },
+    "flakeUtils": {
+      "inputs": {
+        "systems": "systems_2"
+      },
+      "locked": {
+        "lastModified": 1726560853,
+        "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1714971268,
+        "narHash": "sha256-IKwMSwHj9+ec660l+I4tki/1NRoeGpyA2GdtdYpAgEw=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "27c13997bf450a01219899f5a83bd6ffbfc70d3c",
+        "type": "github"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "ref": "nixos-23.11",
+        "type": "indirect"
+      }
+    },
+    "nixpkgsUnstable": {
+      "locked": {
+        "lastModified": 1727348695,
+        "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_2": {
+      "locked": {
+        "lastModified": 1727397532,
+        "narHash": "sha256-pojbL/qteElw/nIXlN8kmHn/w6PQbEHr7Iz+WOXs0EM=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "f65141456289e81ea0d5a05af8898333cab5c53d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixos-24.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_3": {
+      "locked": {
+        "lastModified": 1704145853,
+        "narHash": "sha256-G/1AMt9ibpeMlcxvD1vNaC8imGaK+g7zZ99e29BLgWw=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2d2ea8eab9e400618748ab1a6a108255233b602c",
+        "type": "github"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "ref": "nixos-23.11",
+        "type": "indirect"
+      }
+    },
+    "root": {
+      "inputs": {
+        "commonFlake": "commonFlake",
+        "flake-utils": "flake-utils",
+        "flakeUtils": "flakeUtils",
+        "nixpkgs": "nixpkgs_2",
+        "nixpkgsUnstable": "nixpkgsUnstable",
+        "versionFlake": "versionFlake"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "systems_2": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "versionFlake": {
+      "inputs": {
+        "nixpkgs": "nixpkgs_3"
+      },
+      "locked": {
+        "lastModified": 1716914109,
+        "narHash": "sha256-JY0PLGWzYRDQ9daKLGOBWHHuYun9nSpH9J3aSk8iDmQ=",
+        "ref": "refs/heads/master",
+        "rev": "fe8dd932d6c414a93b4a69c470792b2db038e0fb",
+        "revCount": 129,
+        "type": "git",
+        "url": "https://gitlab.schukai.com/oss/utilities/version.git"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://gitlab.schukai.com/oss/utilities/version.git"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..39757fe
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,158 @@
+{
+  description = "HTTP-Negotiate is a library that provides a simple way to negotiate HTTP requests.";
+
+  inputs = {
+    nixpkgs = {url = "github:nixos/nixpkgs/nixos-24.05";};
+    nixpkgsUnstable = {url = "github:nixos/nixpkgs/nixos-unstable";};
+    flakeUtils = {url = "github:numtide/flake-utils";};
+
+    commonFlake = {
+      url = "git+https://gitlab.schukai.com/schukai/entwicklung/nix-flakes.git?dir=common";
+      flake = true;
+    };
+
+    versionFlake = {
+      url = "git+https://gitlab.schukai.com/oss/utilities/version.git";
+      flake = true;
+    };
+  };
+
+  outputs = {
+    self,
+    nixpkgs,
+    nixpkgsUnstable,
+    flake-utils,
+    versionFlake,
+    commonFlake,
+    ...
+  } @ inputs:
+    flake-utils.lib.eachDefaultSystem (system: let
+      inherit (nixpkgs.lib) optional;
+
+      commonPck = commonFlake.packages.${system}.common;
+      versionPck = versionFlake.packages.${system}.version;
+
+      pkgs' = import nixpkgs {
+        inherit system;
+        overlays = [
+          (final: prev: {
+            common = commonPck;
+          })
+
+          (final: prev: {
+            version = versionPck;
+          })
+
+          (final: prev: {
+            dolt =
+              (import nixpkgsUnstable {
+                inherit system;
+              })
+              .dolt;
+          })
+        ];
+      };
+    in {
+      packages = rec {
+        manual = pkgs'.callPackage ./nix/packages/manual.nix {inherit self pkgs';};
+      };
+
+      devShells = {
+        default = let
+          commonPck = commonFlake.packages.${system}.common;
+          commonScript = commonPck + "/bin/common";
+
+          versionPck = versionFlake.packages.${system}.version;
+          versionBin = versionPck + "/bin/version";
+
+          scriptGoTask = import ./nix/scripts/go-task.nix {inherit self pkgs' system;};
+
+          commonPackages = import ./nix/config/common-packages.nix {inherit pkgs';};
+
+          extendedPackages = [
+            scriptGoTask
+          ];
+
+          scriptPackages = [
+            versionPck
+          ];
+
+          shellPackages =
+            commonPackages
+            ++ extendedPackages
+            ++ scriptPackages;
+        in
+          pkgs'.mkShell {
+            nativeBuildInputs = shellPackages;
+
+            shellHook = ''
+              source ${commonScript}
+
+              if [ -n "$CI_JOB_TOKEN" ]; then
+                  echo_fail "You are in a CI environment, this shell is not intended for CI, but for local development"
+                  exit 1
+              fi
+
+              echo_header "Configuration Lib development shell"
+              readonly worktree=$(get_working_dir)
+              echo_hint "Working directory: ''${worktree}"
+              currentVersion=$(${versionBin} print -g)
+              if [ -z "''${currentVersion}" ]; then
+                  echo_fail "No version found, check your git tags"
+              else
+                  echo_hint "Current version: ''${currentVersion}"
+              fi
+
+              currentGitBranch=$(git rev-parse --abbrev-ref HEAD)
+              echo_hint "Current branch: ''${currentGitBranch}"
+              echo_hint "You can run the task command to see the available tasks"
+
+              echo_section "Happy hacking!"
+            '';
+          };
+
+        gitlab = let
+          commonPck = commonFlake.packages.${system}.common;
+          commonScript = commonPck + "/bin/common";
+
+          versionPck = versionFlake.packages.${system}.version;
+
+          scriptCleanUp = pkgs'.callPackage ./nix/scripts/clean-up.nix {inherit pkgs';};
+          scriptRunCITests = pkgs'.callPackage ./nix/scripts/run-ci-tests.nix {inherit pkgs';};
+          scriptRelease = pkgs'.callPackage ./nix/scripts/release.nix {inherit pkgs';};
+
+          commonPackages = import ./nix/config/common-packages.nix {inherit pkgs';};
+
+          extendedPackages = [
+            scriptCleanUp
+            scriptRunCITests
+            scriptRelease
+          ];
+
+          scriptPackages = [
+            versionPck
+          ];
+
+          shellPackages =
+            commonPackages
+            ++ extendedPackages
+            ++ scriptPackages;
+        in
+          pkgs'.mkShell {
+            nativeBuildInputs = shellPackages;
+
+            shellHook = ''
+              source ${commonScript}
+
+              if [ -z "$CI_JOB_TOKEN" ]; then
+                 echo_fail "You are not in a CI environment, this shell is intended for CI, but for local development"
+                 exit 1
+              fi
+
+              cd ''${CI_PROJECT_DIR} || exit 1
+
+            '';
+          };
+      };
+    });
+}
diff --git a/go.mod b/go.mod
index e5663f2..6d2bf25 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
 module gitlab.schukai.com/oss/libraries/go/network/http-negotiation
 
-go 1.19
+go 1.22
diff --git a/nix/config/common-packages.nix b/nix/config/common-packages.nix
new file mode 100644
index 0000000..572a06e
--- /dev/null
+++ b/nix/config/common-packages.nix
@@ -0,0 +1,73 @@
+{pkgs'}:
+with pkgs'; let
+  php = pkgs.php83.buildEnv {
+    extensions = {
+      enabled,
+      all,
+    }:
+      enabled ++ (with all; [memcached xdebug]);
+  };
+in [
+  alejandra
+  blackbox
+  coreutils-full
+  curl
+  d2
+  dbeaver-bin
+  delve
+  dialog
+  dive
+  drill
+  eza
+  fd
+  feh
+  gcc12
+  gdlv
+  git
+  gitty
+  glab
+  gnugrep
+  gnumake
+  gnused
+  go
+  go-licenses
+  go-migrate
+  golangci-lint
+  google-fonts
+  gosec
+  graphviz
+  grpc
+  gum
+  httpie
+  hurl
+  jq
+  libffi
+  logrotate
+  mdbook
+  mdbook-admonish
+  mdbook-cmdrun
+  mdbook-d2
+  mdbook-emojicodes
+  mdbook-graphviz
+  mdbook-linkcheck
+  mdbook-mermaid
+  mdbook-pdf
+  mdbook-plantuml
+  meld
+  memcached
+  netcat
+  nghttp2
+  nodePackages.mermaid-cli
+  openssh
+  pandoc-katex
+  plantuml
+  procps
+  ranger
+  roboto
+  unixtools.xxd
+  unzip
+  util-linux
+  vhs
+  wget
+  zlib
+]
diff --git a/nix/config/defaults.nix b/nix/config/defaults.nix
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/nix/config/defaults.nix
@@ -0,0 +1,2 @@
+{
+}
diff --git a/nix/config/release.nix b/nix/config/release.nix
new file mode 100644
index 0000000..2639ebb
--- /dev/null
+++ b/nix/config/release.nix
@@ -0,0 +1,15 @@
+{
+  # this file is generated by nix/scripts/init-project.nix
+  # please don't edit it manually
+
+  version = "1.22.1";
+  commit = "36d6f93a8f2801323ab8a4e24826e542bfe22c5c";
+  projectURL = "https://gitlab.schukai.com/oss/configuration";
+  name = "negotiation";
+  mnemonic = "negotiation";
+
+  projectID = "512";
+
+  # this file is generated by nix/scripts/init-project.nix
+  # please don't edit it manually
+}
\ No newline at end of file
diff --git a/nix/config/release.nix.template b/nix/config/release.nix.template
new file mode 100644
index 0000000..e06c6df
--- /dev/null
+++ b/nix/config/release.nix.template
@@ -0,0 +1,15 @@
+{
+  # this file is generated by nix/scripts/init-project.nix
+  # please don't edit it manually
+
+  version = "$VERSION";
+  commit = "$COMMIT";
+  projectURL = "https://gitlab.schukai.com/oss/libraries/go/network/http-negotiation";
+  name = "Negotiation";
+  mnemonic = "negotiation";
+
+  projectID = "412";
+
+  # this file is generated by nix/scripts/init-project.nix
+  # please don't edit it manually
+}
\ No newline at end of file
diff --git a/nix/packages/manual.nix b/nix/packages/manual.nix
new file mode 100644
index 0000000..24efdc4
--- /dev/null
+++ b/nix/packages/manual.nix
@@ -0,0 +1,18 @@
+{
+  pkgs',
+  system,
+  self,
+  ...
+}: let
+  releaseInfo = import ../config/release.nix;
+in
+  derivation {
+    name = "manual";
+    version = releaseInfo.version;
+    builder = "${pkgs'.bash}/bin/bash";
+    args = let
+      script = pkgs'.callPackage ../scripts/build-manual.nix {inherit pkgs' system;};
+    in ["${script}/bin/build-manual"];
+    buildInputs = with pkgs'; [];
+    system = system;
+  }
diff --git a/nix/scripts/bash-fkt.nix b/nix/scripts/bash-fkt.nix
new file mode 100644
index 0000000..2a9d444
--- /dev/null
+++ b/nix/scripts/bash-fkt.nix
@@ -0,0 +1,43 @@
+{pkgs', ...}: ''
+
+  convert_multiline_for_nix() {
+   printf "%s" "
+   }$1" | ${pkgs'.gnused}/bin/sed 's/\\/\\\\/g; s/"/\\"/g; s/$/\\n/g' | tr -d '\n'
+  }
+
+  download_test_images() {
+
+      echo_step "Downloading docker images"
+
+      if ! ${pkgs'.docker}/bin/docker images | grep atmoz/sftp | grep alpine
+      then
+          echo_step "Downloading atmoz/sftp:alpine"
+          if ! ${pkgs'.docker}/bin/docker pull atmoz/sftp:alpine
+          then
+              echo_fail "Failed to download atmoz/sftp:alpine"
+              exit 1
+          fi
+      fi
+
+      if ! ${pkgs'.docker}/bin/docker images | grep axllent/mailpit
+      then
+          echo_step "Downloading atmoz/sftp:alpine"
+          if ! ${pkgs'.docker}/bin/docker pull axllent/mailpit
+          then
+              echo_fail "Failed to download axllent/mailpit"
+              exit 1
+          fi
+      fi
+
+  }
+
+  setup_go_env() {
+      echo_step "Setting GO111MODULE=auto"
+      if ! ${pkgs'.go}/bin/go env -w GO111MODULE=auto
+      then
+          echo_fail "Failed to set GO111MODULE=auto"
+          exit 1
+      fi
+  }
+
+''
diff --git a/nix/scripts/build-cover-report.nix b/nix/scripts/build-cover-report.nix
new file mode 100644
index 0000000..fc5c0b6
--- /dev/null
+++ b/nix/scripts/build-cover-report.nix
@@ -0,0 +1,60 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "build-cover-report" ''
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Building cover report"
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+    setup_go_env
+    download_test_images
+
+    if [ -z "''${out}" ];
+    then
+      echo_fail "No out directory specified"
+      exit 1
+    fi
+
+    writableDir="''${out}/coverage"
+    if ! ${pkgs'.coreutils}/bin/mkdir -p ''${writableDir} > /dev/null 2>&1
+    then
+      write_fail "Failed to create directory ''${writableDir}"
+      exit 1
+    fi
+
+    echo_step "Running tests"
+
+    echo_section "Building"
+    ${pkgs'.go}/bin/go test -v -coverprofile=''${writableDir}/coverage.out ./...
+    if [ $? -ne 0 ];
+    then
+      echo_fail "Failed to run tests"
+      exit 1
+    fi
+
+    if ! ${pkgs'.go}/bin/go tool cover -html=''${writableDir}/coverage.out -o ''${writableDir}/coverage.html
+    then
+      echo_fail "Failed to generate coverage report"
+      exit 1
+    fi
+    echo_ok "Coverage report stored at ''${writableDir}"
+
+    if [ -f ''${writableDir}/coverage.html ];
+    then
+      echo_fail "Coverage report not found"
+      exit 1
+    fi
+
+    echo_step "Opening coverage report in browser"
+    if ! ${pkgs'.xdg-utils}/bin/xdg-open ''${writableDir}/coverage.html > /dev/null 2>&1
+    then
+      echo_fail "Failed to open coverage report in browser"
+      exit 1
+    fi
+
+    echo_ok "Report opened in browser"
+  ''
diff --git a/nix/scripts/build-manual.nix b/nix/scripts/build-manual.nix
new file mode 100644
index 0000000..a5ce31f
--- /dev/null
+++ b/nix/scripts/build-manual.nix
@@ -0,0 +1,17 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+
+  updateSummary = pkgs'.callPackage ./update-manual-summary.nix {inherit pkgs';};
+in
+  pkgs'.writeShellScriptBin "build-manual" ''
+    source ${pkgs'.common}/bin/common
+    source ${bashFktScript}
+
+    ${updateSummary}
+
+    ${pkgs'.coreutils}/bin/mkdir -p $out/manual/de
+    cd ${../../documentation/manual/de}
+    ${pkgs'.mdbook}/bin/mdbook build --dest-dir $out/manual .
+  ''
diff --git a/nix/scripts/clean-up.nix b/nix/scripts/clean-up.nix
new file mode 100644
index 0000000..b83e518
--- /dev/null
+++ b/nix/scripts/clean-up.nix
@@ -0,0 +1,13 @@
+{pkgs, ...}:
+pkgs.writeShellScriptBin "clean-up" ''
+
+  echo "Cleaning up"
+
+  echo "Removing credentials"
+  ${pkgs.git}/bin/git config --global --unset credential.helper
+  if [ -f /root/.docker/config.json ]; then ${pkgs.coreutils}/bin/rm /root/.docker/config.json; fi
+  if [ -f .env-gitlab-ci ]; then ${pkgs.coreutils}/bin/rm .env-gitlab-ci; fi
+
+  echo "Cleaned up"
+
+''
diff --git a/nix/scripts/go-task.nix b/nix/scripts/go-task.nix
new file mode 100644
index 0000000..a39d0bb
--- /dev/null
+++ b/nix/scripts/go-task.nix
@@ -0,0 +1,121 @@
+{
+  pkgs',
+  system,
+  self,
+  ...
+}: let
+  scriptBuildCoverReport = pkgs'.callPackage ./build-cover-report.nix {pkgs' = pkgs';};
+  scriptRunTests = pkgs'.callPackage ./run-tests.nix {pkgs' = pkgs';};
+  scriptRunExtendedTests = pkgs'.callPackage ./run-extended-tests.nix {pkgs' = pkgs';};
+  scriptUpdateProject = pkgs'.callPackage ./update-project.nix {pkgs' = pkgs';};
+  scriptUpdateChangelog = pkgs'.callPackage ./update-changelog.nix {pkgs' = pkgs';};
+
+  taskfile = pkgs'.writeTextFile {
+    name = "taskfile.yml";
+    text = ''
+      version: '3'
+
+      tasks:
+          default:
+            cmds:
+              - task --list
+            silent: true
+
+          run-tests:
+            desc: Execute all tests.
+            aliases:
+              - a
+            env:
+              TEST_BY_TASK: true
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+            cmds:
+              - ${scriptRunTests}/bin/run-tests
+            silent: true
+
+          run-extended-tests:
+            desc: Execute all tests including cover, bench and race tests.
+            aliases:
+              - s
+            env:
+              TEST_BY_TASK: true
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+            cmds:
+              - ${scriptRunExtendedTests}/bin/run-extended-tests
+            silent: true
+
+          build-cover-report:
+            desc: Build coverage report.
+            aliases:
+              - d
+            env:
+              TEST_BY_TASK: true
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+            cmds:
+              - ${scriptBuildCoverReport}/bin/build-cover-report
+            silent: true
+
+          update-project:
+            desc: Check code style, linting, and formatting.
+            aliases:
+              - e
+            env:
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+            cmds:
+              - ${scriptUpdateProject}/bin/update-project
+            silent: true
+
+          git-commit:
+            desc: Commit changes.
+            aliases:
+              - f
+            cmds:
+              - ${scriptUpdateProject}/bin/update-project
+              - cd "{{.USER_WORKING_DIR}}" && cd $(${pkgs'.git}/bin/git rev-parse --show-toplevel) && nix run git+https://gitlab.schukai.com/schukai/entwicklung/nix-flakes#git-commit --no-write-lock-file
+            silent: true
+            env:
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+
+          build-manual:
+            aliases:
+              - g
+            desc: Build the manual
+            cmds:
+              - cd "{{.USER_WORKING_DIR}}" && cd $(${pkgs'.git}/bin/git rev-parse --show-toplevel) && ${pkgs'.nix}/bin/nix build .#manual --no-write-lock-file
+            silent: true
+
+          watch-doc:
+            aliases:
+              - l
+            desc: Build and watch the documentation (http://localhost:3000)
+            cmds:
+              - cd "{{.USER_WORKING_DIR}}" && cd $(${pkgs'.git}/bin/git rev-parse --show-toplevel) && ${pkgs'.mdbook}/bin/mdbook serve documentation/manual/de
+            silent: true
+
+          update-changelog:
+            aliases:
+              - j
+            desc: Update the changelog
+            cmds:
+              - ${scriptUpdateChangelog}/bin/update-changelog
+            silent: true
+            env:
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+
+          tool-dbeaver:
+            aliases:
+              - k
+              - dbeaver
+            desc: Open DBeaver
+            cmds:
+              - cd "{{.USER_WORKING_DIR}}" && cd $(${pkgs'.git}/bin/git rev-parse --show-toplevel) && ${pkgs'.dbeaver-bin}/bin/dbeaver -data .temp/dbeaver -con "driver=mysql|host=localhost|port=3306|user=root|password=secret" 2>&1 > /dev/null
+            silent: true
+            env:
+              USER_WORKING_DIR: "{{.USER_WORKING_DIR}}"
+
+
+    '';
+  };
+in
+  pkgs'.writeShellScriptBin "task" ''
+    ${pkgs'.go-task}/bin/task -t "${taskfile}" "$@"
+  ''
diff --git a/nix/scripts/release.nix b/nix/scripts/release.nix
new file mode 100644
index 0000000..6049e47
--- /dev/null
+++ b/nix/scripts/release.nix
@@ -0,0 +1,75 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+
+  updateChangelogScript = import ./update-changelog.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "release" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Release "
+
+    if [ -z "$CI_REPOSITORY_URL" ]; then
+        echo_fail "Error: CI_REPOSITORY_URL environment variable is not set."
+        exit 1
+    fi
+
+    if [ -z "$CI_PROJECT_DIR" ]; then
+        echo_fail "Error: CI_PROJECT_DIR environment variable is not set."
+        exit 1
+    fi
+
+    cd $CI_PROJECT_DIR || exit 1
+
+    ${pkgs'.git}/bin/git remote set-url origin https://''${CI_REPOSITORY_URL#*@}
+
+    ${pkgs'.git}/bin/git fetch --all --tags --unshallow
+    ${pkgs'.git}/bin/git reset --hard origin/master
+    ${pkgs'.git}/bin/git clean -fd
+    ${pkgs'.git}/bin/git checkout $CI_COMMIT_REF_NAME
+    ${pkgs'.git}/bin/git pull origin $CI_COMMIT_REF_NAME
+
+    if ! ${pkgs'.git}/bin/git --no-pager log --decorate=short --pretty=oneline -n 30
+    then
+        echo_fail "Error: Could not get git log."
+        exit 1
+    fi
+
+    ${pkgs'.git}/bin/git fetch --prune --prune-tags
+
+    echo_step "Bumping version"
+    gitVersion=$(${pkgs'.version}/bin/version predict --exit-code-if-no-bump)
+    if [ -z "$gitVersion" ]; then
+        echo_ok "There is no version bump."
+        echo_ok "done"
+        exit 0
+    fi
+
+    echo_step "Write project version"
+
+    export VERSION=$gitVersion
+    export COMMIT="$CI_COMMIT_SHA"
+    export NAME=$(basename $(pwd) | sed 's/./\U&/' | sed 's/-//g')
+    export MNEMONIC=$(echo $NAME | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g')
+    ${pkgs'.envsubst}/bin/envsubst < ./nix/config/release.nix.template > ./nix/config/release.nix
+
+    ${pkgs'.git}/bin/git tag -a $gitVersion -m"chore: bump version to $gitVersion"
+    ${updateChangelogScript}/bin/update-changelog
+    cd $CI_PROJECT_DIR || exit 1
+
+    ${pkgs'.git}/bin/git tag -d "$gitVersion"
+    ${pkgs'.git}/bin/git commit -m "chore: release $gitVersion" CHANGELOG.md ./nix/config/release.nix
+
+    ${pkgs'.git}/bin/git tag -a $gitVersion -m"chore: bump version to $gitVersion"
+    ${pkgs'.git}/bin/git --no-pager log --decorate=short --pretty=oneline -n 5
+
+    ${pkgs'.git}/bin/git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@}
+    ${pkgs'.git}/bin/git push -o ci.skip origin "$CI_COMMIT_REF_NAME" --tags
+
+    echo_ok "done"
+  ''
diff --git a/nix/scripts/run-ci-tests.nix b/nix/scripts/run-ci-tests.nix
new file mode 100644
index 0000000..301724f
--- /dev/null
+++ b/nix/scripts/run-ci-tests.nix
@@ -0,0 +1,29 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "run-ci-tests" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Running CI tests"
+    setup_go_env
+
+    if [[ -f "assets/test.env" ]]; then
+      echo_hint "Loading test environment variables"
+      set -a
+      source "assets/test.env"
+      set +a
+    fi
+
+    echo_section "Running tests"
+    cd ${./../..} || (echo_fail "Failed to cd to application source" && exit 1)
+    if ! CGO_CFLAGS="-Wno-format-security" ${pkgs'.go}/bin/go test -tags "runOnTask" ./...
+    then
+      echo_fail "Failed to run tests"
+      exit 1
+    fi
+
+  ''
diff --git a/nix/scripts/run-extended-tests.nix b/nix/scripts/run-extended-tests.nix
new file mode 100644
index 0000000..dc23615
--- /dev/null
+++ b/nix/scripts/run-extended-tests.nix
@@ -0,0 +1,52 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "run-extended-tests" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Running extended tests"
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+
+    setup_go_env
+
+    echo_step "Running tests"
+    if ! ${pkgs'.go}/bin/go test -tags "runOnTask" -cover ./...
+    then
+      echo_fail "Failed to run tests"
+      exit 1
+    fi
+    echo_ok "All tests passed"
+
+    echo_step "Running benchmarks"
+    if ! ${pkgs'.go}/bin/go test -tags "runOnTask,bench" -bench ./...
+    then
+      echo_fail "Failed to run benchmarks"
+      exit 1
+    fi
+    echo_ok "Benchmarks passed"
+
+    echo_step "Running race tests"
+    if ! ${pkgs'.go}/bin/go test -tags "runOnTask,race" -race ./...
+    then
+      echo_fail "Failed to run race tests"
+      exit 1
+    fi
+    echo_ok "race tests passed"
+
+    echo_step "Running fuzz tests"
+    if ! ${pkgs'.go}/bin/go test -tags "runOnTask,fuzz" -fuzz ./...
+    then
+      echo_fail "Failed to run fuzz tests"
+      exit 1
+    fi
+
+    echo_ok "Fuzz tests passed"
+    echo_ok "All tests passed"
+
+
+  ''
diff --git a/nix/scripts/run-tests.nix b/nix/scripts/run-tests.nix
new file mode 100644
index 0000000..42ec638
--- /dev/null
+++ b/nix/scripts/run-tests.nix
@@ -0,0 +1,72 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "run-tests" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Running tests"
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+
+    setup_go_env
+
+    echo_section "Select test to run"
+    selection=$(${pkgs'.gum}/bin/gum choose "run all tests" "run specific test" "Cancel")
+
+    if [[ "$selection" == "Cancel" ]]; then
+      echo_ok "Exiting."
+      exit 0
+    fi
+    
+    if [[ -f "assets/test.env" ]]; then
+      echo_hint "Loading test environment variables"
+      set -a
+      source "assets/test.env"
+      set +a
+    fi
+
+    if [[ "$selection" == "run all tests" ]]; then
+      echo_ok "Running all tests"
+      if ! CGO_CFLAGS="-Wno-format-security" ${pkgs'.go}/bin/go test -tags runOnTask -v -failfast ./...
+      then
+        echo_fail "ERROR: Tests failed, check your Go!"
+        exit 1
+      fi
+      echo_ok "All tests passed!"
+      exit 0
+    fi
+
+    test_files=$(${pkgs'.findutils}/bin/find . -name "*_test.go")
+
+    test_names=""
+    for file in $test_files; do
+        names=$(${pkgs'.gnugrep}/bin/grep -oP 'func (Test\w+)' $file | ${pkgs'.gawk}/bin/gawk '{print $2}')
+        test_names+="$names "
+    done
+
+    if [[ -z "$test_names" ]]; then
+        echo_fail "No tests found!"
+        exit 1
+    fi
+
+    selected_tests=$(echo "$test_names" | ${pkgs'.coreutils}/bin/tr ' ' '\n' | ${pkgs'.gum}/bin/gum filter --no-limit  )
+
+    if [[ -z "$selected_tests" ]]; then
+        echo_ok "No tests selected, exiting."
+        exit 0
+    fi
+
+    if ! CGO_CFLAGS="-Wno-format-security" ${pkgs'.go}/bin/go test -tags runOnTask -run "$(echo $selected_tests)"
+    then
+      echo_fail "ERROR: Tests failed, check your Go!"
+      exit 1
+    fi
+
+    echo_ok "All tests passed!"
+
+
+  ''
diff --git a/nix/scripts/update-changelog.nix b/nix/scripts/update-changelog.nix
new file mode 100644
index 0000000..3c43219
--- /dev/null
+++ b/nix/scripts/update-changelog.nix
@@ -0,0 +1,76 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "update-changelog" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_section "Update Changelog"
+    echo_hint "This script will update the changelog."
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+
+    echo_step "Updating changelog"
+
+    CHANGELOG_PATH="./CHANGELOG.md"
+    latestDocumentedVersion=$(${pkgs'.gnugrep}/bin/grep '## \['  $CHANGELOG_PATH |  sed -E 's/## \[([0-9]+\.[0-9]+\.[0-9]+).*/\1/' | head -1)
+    if [ -z "$latestDocumentedVersion" ]; then
+         echo_fail "Could not find latest documented version in changelog"
+         echo_hint "Please add a version entry in the file $CHANGELOG_PATH"
+         exit 1
+    fi
+
+    currentVersion=$(${pkgs'.version}/bin/version print -g)
+    if [ "$latestDocumentedVersion" = "$currentVersion" ]; then
+      echo_ok "changelog already up to date"
+    else
+
+        tags=$(${pkgs'.git}/bin/git tag --sort=creatordate)
+        tags_array=($tags)
+        position=$(${pkgs'.coreutils}/bin/printf "%s\n" "''${tags_array[@]}" | ${pkgs'.gnugrep}/bin/grep -n "^$latestDocumentedVersion$" | ${pkgs'.coreutils}/bin/cut -d: -f1)
+        if [ -z "$position" ]; then
+            echo_fail "Could not find latest documented version in git tags"
+            echo_hint "Please check the git tags"
+            exit 1
+        fi
+
+        next_position=$((position + 1))
+
+        if [ $next_position -le ''${#tags_array[@]} ]; then
+            next_tag=''${tags_array[''$next_position - 1]}
+        else
+            echo_fail "Could not find next tag"
+            echo_hint "Please check the git tags"
+            exit 1
+        fi
+
+        echo_step "Generating changelog"
+        tmpChangelog=$(${pkgs'.mktemp}/bin/mktemp)
+        if ! ${pkgs'.git-chglog}/bin/git-chglog --config ./.config/chglog/config.yml -o $tmpChangelog $next_tag..
+        then
+          echo_fail "git-chglog failed"
+          ${pkgs'.coreutils}/bin/rm $tmpChangelog
+          exit 1
+        fi
+
+        newChanges=$(${pkgs'.coreutils}/bin/cat $tmpChangelog)
+        ${pkgs'.coreutils}/bin/rm $tmpChangelog
+
+        if [ -n "$newChanges" ]; then
+          ${pkgs'.gnused}/bin/sed -i '/^# Changelog/d' $CHANGELOG_PATH
+          ${pkgs'.coreutils}/bin/mv $CHANGELOG_PATH ''${CHANGELOG_PATH}.old
+
+          echo -e "# Changelog\n\n" > $CHANGELOG_PATH
+          echo "$newChanges" >> $CHANGELOG_PATH
+
+          ${pkgs'.coreutils}/bin/cat "''${CHANGELOG_PATH}.old" >> $CHANGELOG_PATH
+          ${pkgs'.coreutils}/bin/rm ''${CHANGELOG_PATH}.old
+          echo_ok "changelog updated"
+        fi
+    fi
+
+    echo_ok "Change log updated"
+  ''
diff --git a/nix/scripts/update-inputs.nix b/nix/scripts/update-inputs.nix
new file mode 100644
index 0000000..0dbbf02
--- /dev/null
+++ b/nix/scripts/update-inputs.nix
@@ -0,0 +1,44 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "update-inputs" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Update inputs"
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+
+    echo_section "Updating inputs for the following packages:"
+    selection=$(${pkgs'.gum}/bin/gum choose --no-limit "Version")
+    exitCode=$?
+    if [[ $exitCode -ne 0 ]]; then
+      echo_ok "Exiting."
+      exit 0
+    fi
+
+    packages=($selection)
+    echo "Updating inputs for the following packages: ''${packages[@]}"
+
+    if [[ "''${packages[@]}" == "" || $exitCode -ne 0 ]]; then
+      echo_ok "Exiting."
+      exit 0
+    fi
+
+    for package in "''${packages[@]}"; do
+        echo_step "$package updating"
+
+        ## pck is the package name (to lower with flake suffix
+        pck=$(echo "$package" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g')
+
+        if ! ${pkgs'.nix}/bin/nix flake lock --update-input "$pck"Flake; then
+            echo_fail "$package failed to update"
+        else
+            echo_ok "$package updated"
+        fi
+    done
+
+  ''
diff --git a/nix/scripts/update-manual-summary.nix b/nix/scripts/update-manual-summary.nix
new file mode 100644
index 0000000..1b219cc
--- /dev/null
+++ b/nix/scripts/update-manual-summary.nix
@@ -0,0 +1,91 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "update-manual-summary" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_section "Update manual summary"
+    echo_hint "This script will update the SUMMARY.md file with the files in the manual directory."
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+
+    echo_step "Updating summary file..."
+
+    doc_dir="documentation/manual/de/source/"
+    summary_file="''${doc_dir}SUMMARY.md"
+
+    echo "# Summary" > "$summary_file"
+    echo "" >> "$summary_file"
+
+    extract_first_h1() {
+        local file_path="$1"
+
+        ${pkgs'.gnused}/bin/sed -n '/^# /{
+        s/^# //;
+        s/[()]//g;
+        s/\\n//g;
+        s/\\r//g;
+        s/\\t//g;
+        p;
+        q;
+        }' "$file_path"
+
+    }
+
+
+    generate_summary() {
+        local path="$1"
+        local indent="$2"
+        local rel_path="''${path#$doc_dir}"
+
+        for item in "$path"/*; do
+            if [ -d "$item" ]; then
+                # Es ist ein Verzeichnis#
+                dirname=$(${pkgs'.coreutils}/bin/basename "$item")
+                md_files=$(${pkgs'.findutils}/bin/find "$item" -maxdepth 1 -type f -name '*.md')
+
+                subdir_count=$(${pkgs'.findutils}/bin/find "$item" -mindepth 1 -maxdepth 1 -type d | wc -l)
+
+                if [ ! -z "$md_files" ] || [ $subdir_count -gt 0 ]; then
+                    main_doc=$(${pkgs'.findutils}/bin/find "$item" -maxdepth 1 -type f \( -name 'index.md' -o -name 'README.md' \) | ${pkgs'.coreutils}/bin/head -n 1)
+                    if [ -n "$main_doc" ]; then
+                        main_doc_filename=$(${pkgs'.coreutils}/bin/basename "$main_doc")
+                        echo "''${indent}* [''${dirname^}](''${rel_path#/}/''${dirname}/''${main_doc_filename})" >> "$summary_file"
+                    else
+                        echo "''${indent}*  [''${dirname^}]()" >> "$summary_file"
+                    fi
+                    generate_summary "$item" "''${indent}    "
+                fi
+            elif [[ "$item" == *.md ]]; then
+                filename=$(${pkgs'.coreutils}/bin/basename "$item")
+                title="''${filename%.*}"
+
+                h1=$(extract_first_h1 "$item")
+
+                if [ -n "$h1" ]; then
+                    title="$h1"
+                fi
+
+                echo "''${indent}* [''${title}](''${rel_path#/}/''${filename})" >> "$summary_file"
+            fi
+        done
+    }
+
+    generate_summary "$doc_dir" ""
+
+    ## remopve all lines with imprint.md and privacy.md and 404.md
+    ${pkgs'.gnused}/bin/sed -i '/\(imprint\.md\|privacy\.md\|404\.md\|SUMMARY.md\)/d' "$summary_file"
+
+    echo "---" >> "$summary_file"
+    echo "* [imprint](imprint.md)" >> "$summary_file"
+
+
+    echo_ok "SUMMARY.md updated successfully."
+    echo_hint "Use task watch-manual to check the manual for errors."
+    echo_hint "Please check the file for correctness and commit the changes."
+
+  ''
diff --git a/nix/scripts/update-project.nix b/nix/scripts/update-project.nix
new file mode 100644
index 0000000..ef7ad45
--- /dev/null
+++ b/nix/scripts/update-project.nix
@@ -0,0 +1,85 @@
+{pkgs', ...}: let
+  bashFktScript = import ./bash-fkt.nix {
+    inherit pkgs';
+  };
+in
+  pkgs'.writeShellScriptBin "update-project" ''
+
+    source ${pkgs'.common}/bin/common
+    ${bashFktScript}
+
+    echo_header "Update project"
+    echo_hint "The command is executed in the current working directory and not in a nix derivation."
+    cd_working_dir
+
+    currentVersion=$(${pkgs'.version}/bin/version print -e -g)
+    currentHash=$(${pkgs'.git}/bin/git rev-parse HEAD)
+
+    echo_step "Write project version"
+    export VERSION=$currentVersion
+    export COMMIT=$currentHash
+
+    export NAME=$(basename $(pwd) | sed 's/./\U&/' | sed 's/-//g')
+    export MNEMONIC=$(echo $NAME | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g')
+
+    ${pkgs'.envsubst}/bin/envsubst < ./nix/config/release.nix.template > ./nix/config/release.nix
+
+    echo_step "Formatting Nix code"
+    if ! ${pkgs'.alejandra}/bin/alejandra flake.nix ./nix/scripts/*.nix ./nix/config/*.nix ./nix/packages/*nix
+    then
+      echo_fail "alejandra formatting failed"
+      exit 1
+    fi
+
+    echo_step "change working directory to source"
+    setup_go_env
+    echo_step "Formatting Go code"
+    if ! ${pkgs'.findutils}/bin/find . -type f -name '*.go' ! -path './vendor/*' -print0 | xargs -0 gofmt -s -w
+    then
+      echo_fail "go fmt failed"
+      exit 1
+    fi
+
+    echo_step "Add license headers"
+    if ! ${pkgs'.addlicense}/bin/addlicense -c "schukai GmbH" -s -l "proprietary" $(${pkgs'.fd}/bin/fd --extension go --exclude models/ --exclude vendor --exclude embedded/)
+    then
+      echo_fail "addlicense failed"
+      exit 1
+    fi
+
+    export NIX_CFLAGS_COMPILE=" -Wno-error=format-security"
+
+    echo_step "Running go-licenses"
+    readonly defaultPacke=$(awk -F ' ' '/^module / { print $2 }' ./go.mod)
+    ${pkgs'.go-licenses}/bin/go-licenses save "$defaultPacke" -v2 --ignore "gitlab.schukai.com" --force --save_path ./documentation/licenses/
+
+    echo_step "Running go vet"
+    if ! ${pkgs'.go}/bin/go vet .
+    then
+      echo_fail "go vet failed"
+      exit 1
+    fi
+
+    echo_step "Running go mod tidy"
+    if ! ${pkgs'.go}/bin/go mod tidy
+    then
+      echo_fail "go mod tidy failed"
+      exit 1
+    fi
+
+    echo_step "Running lint"
+    if ! ${pkgs'.golangci-lint}/bin/golangci-lint run .
+    then
+      echo_fail "lint failed"
+      exit 1
+    fi
+
+    echo_step "Running gosec"
+    if ! ${pkgs'.gosec}/bin/gosec -quiet .
+    then
+      echo_fail "gosec failed"
+      exit 1
+    fi
+
+
+  ''
-- 
GitLab