From 9eba3001d3271a1f9f5e7b67cc7e25ca9f6e509c Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 16 Jan 2024 18:56:59 +0100
Subject: [PATCH 01/38] chore: Added sonar-project config and deprecated
 MAINTAINER docker directive

---
 Dockerfile                       | 2 +-
 docker/php-fpm-alpine/Dockerfile | 3 ++-
 sonar-project.properties         | 2 ++
 3 files changed, 5 insertions(+), 2 deletions(-)
 create mode 100644 sonar-project.properties

diff --git a/Dockerfile b/Dockerfile
index 67a45fd..e76ecf2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 FROM roadiz/php82-fpm-alpine:latest
-MAINTAINER Ambroise Maupate <ambroise@rezo-zero.com>
+LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 ARG USER_UID=1000
 ENV APP_ENV=prod
 ENV APP_DEBUG=0
diff --git a/docker/php-fpm-alpine/Dockerfile b/docker/php-fpm-alpine/Dockerfile
index 185dd04..4aa9352 100755
--- a/docker/php-fpm-alpine/Dockerfile
+++ b/docker/php-fpm-alpine/Dockerfile
@@ -1,5 +1,6 @@
 FROM roadiz/php82-fpm-alpine:latest
-MAINTAINER Ambroise Maupate <ambroise@rezo-zero.com>
+LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
+
 
 ARG USER_UID=1000
 ENV COMPOSER_ALLOW_SUPERUSER=1
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000..6ecbdfd
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,2 @@
+sonar.qualitygate.wait=true
+sonar.exclusions=migrations/**,var/**,vendor/**,config/**

From 067d9fd0fc464a1d3f59eb5a6286fc031a99eb99 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 22 Jan 2024 15:42:23 +0100
Subject: [PATCH 02/38] feat: Use a dedicated docker entrypoint for docker cron
 image

---
 Dockerfile                                   |  3 +++
 docker-compose.prod.yml                      |  4 +---
 docker/php-fpm-alpine/Dockerfile             |  3 ++-
 docker/php-fpm-alpine/docker-cron-entrypoint | 14 ++++++++++++++
 4 files changed, 20 insertions(+), 4 deletions(-)
 create mode 100755 docker/php-fpm-alpine/docker-cron-entrypoint

diff --git a/Dockerfile b/Dockerfile
index e76ecf2..b702578 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,6 @@
 FROM roadiz/php82-fpm-alpine:latest
 LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
+
 ARG USER_UID=1000
 ENV APP_ENV=prod
 ENV APP_DEBUG=0
@@ -26,12 +27,14 @@ COPY docker/php-fpm-alpine/php.prod.ini /usr/local/etc/php/php.ini
 COPY docker/php-fpm-alpine/crontab.txt /crontab.txt
 COPY docker/php-fpm-alpine/wait-for-it.sh /wait-for-it.sh
 COPY docker/php-fpm-alpine/docker-php-entrypoint /usr/local/bin/docker-php-entrypoint
+COPY docker/php-fpm-alpine/docker-cron-entrypoint /usr/local/bin/docker-cron-entrypoint
 COPY --chown=www-data:www-data . /var/www/html/
 
 RUN ln -s /var/www/html/bin/console /usr/local/bin/console \
     && /usr/bin/crontab -u www-data /crontab.txt \
     && chmod +x /wait-for-it.sh \
     && chmod +x /usr/local/bin/docker-php-entrypoint \
+    && chmod +x /usr/local/bin/docker-cron-entrypoint \
     && chown -R www-data:www-data /var/www/html/
 
 VOLUME /var/www/html/config/jwt \
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 2917f85..123d547 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -160,9 +160,7 @@ services:
     cron:
         extends:
             service: app
-        # https://github.com/dubiousjim/dcron/issues/13#issuecomment-1406937781
-        init: true
-        entrypoint: [ "crond", "-f", "-L", "15" ]
+        entrypoint: 'docker-cron-entrypoint'
         restart: always
         labels:
             - "com.centurylinklabs.watchtower.enable=true"
diff --git a/docker/php-fpm-alpine/Dockerfile b/docker/php-fpm-alpine/Dockerfile
index 4aa9352..004117a 100755
--- a/docker/php-fpm-alpine/Dockerfile
+++ b/docker/php-fpm-alpine/Dockerfile
@@ -1,7 +1,6 @@
 FROM roadiz/php82-fpm-alpine:latest
 LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
-
 ARG USER_UID=1000
 ENV COMPOSER_ALLOW_SUPERUSER=1
 ENV APP_ENV=dev
@@ -24,6 +23,7 @@ ADD php.ini /usr/local/etc/php/php.ini
 ADD crontab.txt /crontab.txt
 ADD wait-for-it.sh /wait-for-it.sh
 ADD docker-php-entrypoint-dev /usr/local/bin/docker-php-entrypoint
+ADD docker-cron-entrypoint /usr/local/bin/docker-cron-entrypoint
 
 VOLUME /var/www/html
 WORKDIR /var/www/html
@@ -34,4 +34,5 @@ RUN ln -s /var/www/html/bin/console /usr/local/bin/console \
     && /usr/bin/crontab -u www-data /crontab.txt \
     && chmod +x /wait-for-it.sh \
     && chmod +x /usr/local/bin/docker-php-entrypoint \
+    && chmod +x /usr/local/bin/docker-cron-entrypoint \
     && chown -R www-data:www-data /var/www/html/
diff --git a/docker/php-fpm-alpine/docker-cron-entrypoint b/docker/php-fpm-alpine/docker-cron-entrypoint
new file mode 100755
index 0000000..307ee3f
--- /dev/null
+++ b/docker/php-fpm-alpine/docker-cron-entrypoint
@@ -0,0 +1,14 @@
+#!/bin/sh
+set -e
+
+env >> /etc/environment
+
+# Need to fix permissions for be able to create cache dir
+/bin/chown -R www-data:www-data /var/www/html/var || true;
+/bin/mkdir -p /var/www/html/var/cache || true;
+# Need to fix permissions for be able to write in cache dir
+/bin/chown -R www-data:www-data /var/www/html/var || true;
+
+# Let cron take the wheel
+echo "Starting cron in foreground."
+/usr/sbin/crond -f -l 8

From c18e318d110dae22ddc4224671f7ff969f46c110 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 22 Jan 2024 17:32:30 +0100
Subject: [PATCH 03/38] chore: dockerignore for new docker-cron-entrypoint

---
 .dockerignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.dockerignore b/.dockerignore
index d04de34..b873b22 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -55,6 +55,7 @@ project_env.sh
 !docker/solr/managed-schema.xml
 !docker/php-fpm-alpine/crontab.txt
 !docker/php-fpm-alpine/docker-php-entrypoint
+!docker/php-fpm-alpine/docker-cron-entrypoint
 !docker/php-fpm-alpine/php.ini
 !docker/php-fpm-alpine/php.prod.ini
 !docker/php-fpm-alpine/wait-for-it.sh

From 9e34fbfa243c9f8c42e2e24f29ac029f227da8bc Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 22 Jan 2024 17:39:40 +0100
Subject: [PATCH 04/38] chore: fixed default gateway example

---
 .env                       | 2 +-
 docker/varnish/default.vcl | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.env b/.env
index 3e8b8ea..743495e 100644
--- a/.env
+++ b/.env
@@ -27,7 +27,7 @@ PUBLIC_SMTP_PORT=1025
 TRUSTED_PROXIES=172.18.0.1,172.18.0.2,REMOTE_ADDR,varnish
 #TRUSTED_HOSTS=roadiz-skeleton.test,varnish.roadiz-skeleton.test
 # Docker networking
-DEFAULT_GATEWAY=172.144.0.1
+DEFAULT_GATEWAY=172.144.0.0
 
 SOLR_HOST=solr
 SOLR_PORT=8983
diff --git a/docker/varnish/default.vcl b/docker/varnish/default.vcl
index c32215b..cc7dbcc 100644
--- a/docker/varnish/default.vcl
+++ b/docker/varnish/default.vcl
@@ -21,7 +21,7 @@ acl local {
     "127.0.0.1";
     "::1";
     # Add here your $DEFAULT_GATEWAY CIDR to allow all containers in docker network to purge
-    #"172.144.0.0/24";
+    #"172.144.0.0/16";
 }
 
 sub vcl_recv {

From 1ee942dd10505d726be1b4b1291b5abb4fe47882 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 26 Jan 2024 09:50:19 +0100
Subject: [PATCH 05/38] feat: Switch to roadiz dev 2.3.x

---
 composer.json      | 28 ++++++++++++++--------------
 composer.json.dist | 28 ++++++++++++++--------------
 2 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/composer.json b/composer.json
index d21bdaa..2dce9c0 100644
--- a/composer.json
+++ b/composer.json
@@ -3,32 +3,32 @@
     "type": "project",
     "license": "mit",
     "prefer-stable": true,
+    "minimum-stability": "dev",
     "require": {
-        "php": ">=8.1",
+        "php": ">=8.2",
         "ext-ctype": "*",
         "ext-iconv": "*",
         "ext-json": "*",
-        "nelmio/cors-bundle": "^2.2",
-        "roadiz/cms-pack": "*",
-        "sentry/sentry-symfony": "^4.2",
+        "nelmio/cors-bundle": "^2.4",
+        "roadiz/cms-pack": "dev-develop",
+        "sentry/sentry-symfony": "^4.13",
         "symfony/flex": "*",
         "symfony/requirements-checker": "^2.0"
     },
     "require-dev": {
-        "blackfire/php-sdk": "^1.28",
-        "phpstan/phpstan": "^1.5.3",
+        "phpstan/phpstan": "^1.10",
         "phpstan/phpstan-doctrine": "^1.3.1",
-        "phpstan/phpstan-symfony": "^1.1.8",
+        "phpstan/phpstan-symfony": "^1.3.7",
         "phpunit/phpunit": "^9.5",
         "rezozero/intervention-request-bundle": "~3.0.0",
         "squizlabs/php_codesniffer": "^3.6",
-        "symfony/browser-kit": "5.4.*",
-        "symfony/css-selector": "5.4.*",
-        "symfony/debug-bundle": "5.4.*",
+        "symfony/browser-kit": "6.4.*",
+        "symfony/css-selector": "6.4.*",
+        "symfony/debug-bundle": "6.4.*",
         "symfony/maker-bundle": "^1.0",
-        "symfony/phpunit-bridge": "5.4.*",
-        "symfony/stopwatch": "5.4.*",
-        "symfony/web-profiler-bundle": "5.4.*"
+        "symfony/phpunit-bridge": "6.4.*",
+        "symfony/stopwatch": "6.4.*",
+        "symfony/web-profiler-bundle": "6.4.*"
     },
     "config": {
         "optimize-autoloader": true,
@@ -92,7 +92,7 @@
     "extra": {
         "symfony": {
             "allow-contrib": false,
-            "require": "5.4.*",
+            "require": "6.4.*",
             "docker": false
         }
     }
diff --git a/composer.json.dist b/composer.json.dist
index d21bdaa..2dce9c0 100644
--- a/composer.json.dist
+++ b/composer.json.dist
@@ -3,32 +3,32 @@
     "type": "project",
     "license": "mit",
     "prefer-stable": true,
+    "minimum-stability": "dev",
     "require": {
-        "php": ">=8.1",
+        "php": ">=8.2",
         "ext-ctype": "*",
         "ext-iconv": "*",
         "ext-json": "*",
-        "nelmio/cors-bundle": "^2.2",
-        "roadiz/cms-pack": "*",
-        "sentry/sentry-symfony": "^4.2",
+        "nelmio/cors-bundle": "^2.4",
+        "roadiz/cms-pack": "dev-develop",
+        "sentry/sentry-symfony": "^4.13",
         "symfony/flex": "*",
         "symfony/requirements-checker": "^2.0"
     },
     "require-dev": {
-        "blackfire/php-sdk": "^1.28",
-        "phpstan/phpstan": "^1.5.3",
+        "phpstan/phpstan": "^1.10",
         "phpstan/phpstan-doctrine": "^1.3.1",
-        "phpstan/phpstan-symfony": "^1.1.8",
+        "phpstan/phpstan-symfony": "^1.3.7",
         "phpunit/phpunit": "^9.5",
         "rezozero/intervention-request-bundle": "~3.0.0",
         "squizlabs/php_codesniffer": "^3.6",
-        "symfony/browser-kit": "5.4.*",
-        "symfony/css-selector": "5.4.*",
-        "symfony/debug-bundle": "5.4.*",
+        "symfony/browser-kit": "6.4.*",
+        "symfony/css-selector": "6.4.*",
+        "symfony/debug-bundle": "6.4.*",
         "symfony/maker-bundle": "^1.0",
-        "symfony/phpunit-bridge": "5.4.*",
-        "symfony/stopwatch": "5.4.*",
-        "symfony/web-profiler-bundle": "5.4.*"
+        "symfony/phpunit-bridge": "6.4.*",
+        "symfony/stopwatch": "6.4.*",
+        "symfony/web-profiler-bundle": "6.4.*"
     },
     "config": {
         "optimize-autoloader": true,
@@ -92,7 +92,7 @@
     "extra": {
         "symfony": {
             "allow-contrib": false,
-            "require": "5.4.*",
+            "require": "6.4.*",
             "docker": false
         }
     }

From 1a5203becde3970692ddeb01c0c9b85ac447cd70 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 7 Feb 2024 15:31:08 +0100
Subject: [PATCH 06/38] chore: Use php83

---
 .gitignore                       |   1 -
 .gitlab-ci.yml                   |   2 +-
 Dockerfile                       |   2 +-
 docker/php-fpm-alpine/Dockerfile |   2 +-
 symfony.lock                     | 429 -------------------------------
 5 files changed, 3 insertions(+), 433 deletions(-)
 delete mode 100644 symfony.lock

diff --git a/.gitignore b/.gitignore
index 08e5f17..bfd6371 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,7 +37,6 @@ report.txt
 /phpcs.xml
 ###< squizlabs/php_codesniffer ###
 openapi.json
-composer.lock
 /*.sql
 /*.zip
 /*.tar
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f68f314..78e6af8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,6 @@
 # Gitlab CI
 # Replace “roadiz_skeleton” with your project slug
-image: roadiz/php81-runner
+image: roadiz/php83-runner
 
 stages:
     - test
diff --git a/Dockerfile b/Dockerfile
index b702578..809ab38 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM roadiz/php82-fpm-alpine:latest
+FROM roadiz/php83-fpm-alpine:latest
 LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
 ARG USER_UID=1000
diff --git a/docker/php-fpm-alpine/Dockerfile b/docker/php-fpm-alpine/Dockerfile
index 004117a..3cd7de9 100755
--- a/docker/php-fpm-alpine/Dockerfile
+++ b/docker/php-fpm-alpine/Dockerfile
@@ -1,4 +1,4 @@
-FROM roadiz/php82-fpm-alpine:latest
+FROM roadiz/php83-fpm-alpine:latest
 LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
 ARG USER_UID=1000
diff --git a/symfony.lock b/symfony.lock
deleted file mode 100644
index 922843c..0000000
--- a/symfony.lock
+++ /dev/null
@@ -1,429 +0,0 @@
-{
-    "api-platform/core": {
-        "version": "2.7",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "2.5",
-            "ref": "b86557ce5677fa855b1b2608f4a4bc4a8fed8be7"
-        },
-        "files": [
-            "config/packages/api_platform.yaml",
-            "config/routes/api_platform.yaml",
-            "src/Entity/.gitignore"
-        ]
-    },
-    "doctrine/annotations": {
-        "version": "1.14",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "1.0",
-            "ref": "a2759dd6123694c8d901d0ec80006e044c2e6457"
-        },
-        "files": [
-            "config/routes/annotations.yaml"
-        ]
-    },
-    "doctrine/doctrine-bundle": {
-        "version": "2.11",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "2.4",
-            "ref": "013b823e7fee65890b23e40f31e6667a1ac519ac"
-        },
-        "files": [
-            "config/packages/doctrine.yaml",
-            "src/Entity/.gitignore",
-            "src/Repository/.gitignore"
-        ]
-    },
-    "doctrine/doctrine-migrations-bundle": {
-        "version": "3.3",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "3.1",
-            "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
-        },
-        "files": [
-            "config/packages/doctrine_migrations.yaml",
-            "migrations/.gitignore"
-        ]
-    },
-    "jms/serializer-bundle": {
-        "version": "3.10",
-        "recipe": {
-            "repo": "github.com/symfony/recipes-contrib",
-            "branch": "main",
-            "version": "3.0",
-            "ref": "384cec52df45f3bfd46a09930d6960a58872b268"
-        }
-    },
-    "league/flysystem-bundle": {
-        "version": "3.3",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "1.0",
-            "ref": "913dc3d7a5a1af0d2b044c5ac3a16e2f851d7380"
-        },
-        "files": [
-            "config/packages/flysystem.yaml",
-            "var/storage/.gitignore"
-        ]
-    },
-    "lexik/jwt-authentication-bundle": {
-        "version": "2.20",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "2.5",
-            "ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7"
-        },
-        "files": [
-            "config/packages/lexik_jwt_authentication.yaml"
-        ]
-    },
-    "nelmio/cors-bundle": {
-        "version": "2.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "1.5",
-            "ref": "6bea22e6c564fba3a1391615cada1437d0bde39c"
-        },
-        "files": [
-            "config/packages/nelmio_cors.yaml"
-        ]
-    },
-    "php-http/discovery": {
-        "version": "1.19",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "1.18",
-            "ref": "f45b5dd173a27873ab19f5e3180b2f661c21de02"
-        },
-        "files": [
-            "config/packages/http_discovery.yaml"
-        ]
-    },
-    "phpstan/phpstan": {
-        "version": "1.10",
-        "recipe": {
-            "repo": "github.com/symfony/recipes-contrib",
-            "branch": "main",
-            "version": "1.0",
-            "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767"
-        }
-    },
-    "phpunit/phpunit": {
-        "version": "9.6",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "9.6",
-            "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326"
-        },
-        "files": [
-            ".env.test",
-            "phpunit.xml.dist",
-            "tests/bootstrap.php"
-        ]
-    },
-    "rezozero/intervention-request-bundle": {
-        "version": "3.0.0"
-    },
-    "rezozero/liform-bundle": {
-        "version": "v0.19.0"
-    },
-    "roadiz/compat-bundle": {
-        "version": "v2.2.0"
-    },
-    "roadiz/core-bundle": {
-        "version": "v2.2.0"
-    },
-    "roadiz/rozier-bundle": {
-        "version": "v2.2.0"
-    },
-    "rollerworks/password-common-list": {
-        "version": "v0.2.1"
-    },
-    "rollerworks/password-strength-bundle": {
-        "version": "v2.2.4"
-    },
-    "sensio/framework-extra-bundle": {
-        "version": "6.2",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.2",
-            "ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b"
-        },
-        "files": [
-            "config/packages/sensio_framework_extra.yaml"
-        ]
-    },
-    "sentry/sentry-symfony": {
-        "version": "4.13",
-        "recipe": {
-            "repo": "github.com/symfony/recipes-contrib",
-            "branch": "main",
-            "version": "4.6",
-            "ref": "f7b4706a3e8a6f096b7392f3146f4f7f65ff594c"
-        }
-    },
-    "squizlabs/php_codesniffer": {
-        "version": "3.8",
-        "recipe": {
-            "repo": "github.com/symfony/recipes-contrib",
-            "branch": "main",
-            "version": "3.6",
-            "ref": "1019e5c08d4821cb9b77f4891f8e9c31ff20ac6f"
-        }
-    },
-    "symfony-cmf/routing-bundle": {
-        "version": "2.5.1"
-    },
-    "symfony/console": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
-        },
-        "files": [
-            "bin/console"
-        ]
-    },
-    "symfony/debug-bundle": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b"
-        },
-        "files": [
-            "config/packages/debug.yaml"
-        ]
-    },
-    "symfony/flex": {
-        "version": "2.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "1.0",
-            "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
-        },
-        "files": [
-            ".env"
-        ]
-    },
-    "symfony/framework-bundle": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.4",
-            "ref": "3cd216a4d007b78d8554d44a5b1c0a446dab24fb"
-        },
-        "files": [
-            "config/packages/cache.yaml",
-            "config/packages/framework.yaml",
-            "config/preload.php",
-            "config/routes/framework.yaml",
-            "config/services.yaml",
-            "public/index.php",
-            "src/Controller/.gitignore",
-            "src/Kernel.php"
-        ]
-    },
-    "symfony/lock": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.2",
-            "ref": "8e937ff2b4735d110af1770f242c1107fdab4c8e"
-        },
-        "files": [
-            "config/packages/lock.yaml"
-        ]
-    },
-    "symfony/mailer": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "4.3",
-            "ref": "2bf89438209656b85b9a49238c4467bff1b1f939"
-        },
-        "files": [
-            "config/packages/mailer.yaml"
-        ]
-    },
-    "symfony/maker-bundle": {
-        "version": "1.50",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "1.0",
-            "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
-        }
-    },
-    "symfony/messenger": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.4",
-            "ref": "8bd5f27013fb1d7217191c548e340f0bdb11912c"
-        },
-        "files": [
-            "config/packages/messenger.yaml"
-        ]
-    },
-    "symfony/monolog-bundle": {
-        "version": "3.10",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "3.7",
-            "ref": "213676c4ec929f046dfde5ea8e97625b81bc0578"
-        },
-        "files": [
-            "config/packages/monolog.yaml"
-        ]
-    },
-    "symfony/notifier": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.0",
-            "ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc"
-        },
-        "files": [
-            "config/packages/notifier.yaml"
-        ]
-    },
-    "symfony/phpunit-bridge": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "221b9cc0a623f567e83ccd61a8ac82a9a91e2b5b"
-        },
-        "files": [
-            ".env.test",
-            "bin/phpunit",
-            "phpunit.xml.dist",
-            "tests/bootstrap.php"
-        ]
-    },
-    "symfony/requirements-checker": {
-        "version": "2.0",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "2.0",
-            "ref": "02c6e4b9b117c39e8a23eab7f3840ef6e62293b9"
-        }
-    },
-    "symfony/routing": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "85de1d8ae45b284c3c84b668171d2615049e698f"
-        },
-        "files": [
-            "config/packages/routing.yaml",
-            "config/routes.yaml"
-        ]
-    },
-    "symfony/security-bundle": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "98f1f2b0d635908c2b40f3675da2d23b1a069d30"
-        },
-        "files": [
-            "config/packages/security.yaml"
-        ]
-    },
-    "symfony/translation": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "da64f5a2b6d96f5dc24914517c0350a5f91dee43"
-        },
-        "files": [
-            "config/packages/translation.yaml",
-            "translations/.gitignore"
-        ]
-    },
-    "symfony/twig-bundle": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.4",
-            "ref": "bb2178c57eee79e6be0b297aa96fc0c0def81387"
-        },
-        "files": [
-            "config/packages/twig.yaml",
-            "templates/base.html.twig"
-        ]
-    },
-    "symfony/validator": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "c32cfd98f714894c4f128bb99aa2530c1227603c"
-        },
-        "files": [
-            "config/packages/validator.yaml"
-        ]
-    },
-    "symfony/web-profiler-bundle": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "5.3",
-            "ref": "24bbc3d84ef2f427f82104f766014e799eefcc3e"
-        },
-        "files": [
-            "config/packages/web_profiler.yaml",
-            "config/routes/web_profiler.yaml"
-        ]
-    },
-    "symfony/workflow": {
-        "version": "5.4",
-        "recipe": {
-            "repo": "github.com/symfony/recipes",
-            "branch": "main",
-            "version": "3.3",
-            "ref": "3b2f8ca32a07fcb00f899649053943fa3d8bbfb6"
-        },
-        "files": [
-            "config/packages/workflow.yaml"
-        ]
-    },
-    "twig/extra-bundle": {
-        "version": "v3.8.0"
-    }
-}

From edc2550cbdd311058285480cff87db4894485a6a Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 9 Feb 2024 16:32:12 +0100
Subject: [PATCH 07/38] feat: Added Footers and error page to common content

---
 config/packages/doctrine.yaml                 |  2 +-
 src/Api/Model/CommonContent.php               |  6 +++
 src/Controller/GetCommonContentController.php | 43 ++++++++++++-------
 src/TreeWalker/MenuNodeSourceWalker.php       |  4 --
 4 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml
index 72fc77d..4bf9ce6 100644
--- a/config/packages/doctrine.yaml
+++ b/config/packages/doctrine.yaml
@@ -2,7 +2,7 @@ doctrine:
     dbal:
         url: '%env(resolve:DATABASE_URL)%'
     orm:
-        auto_generate_proxy_classes: true
+        auto_generate_proxy_classes: '%kernel.debug%'
         default_entity_manager: default
         entity_managers:
             # Put `logger` entity manager first to select it as default for Log entity
diff --git a/src/Api/Model/CommonContent.php b/src/Api/Model/CommonContent.php
index 14bd2ad..a668b01 100644
--- a/src/Api/Model/CommonContent.php
+++ b/src/Api/Model/CommonContent.php
@@ -17,9 +17,15 @@ final class CommonContent
     #[Groups(["common_content"])]
     public ?NodesSources $home = null;
 
+    #[Groups(["common_content"])]
+    public ?NodesSources $errorPage = null;
+
     #[Groups(["common_content"])]
     public ?NodesSourcesHeadInterface $head = null;
 
     #[Groups(["common_content"])]
     public ?array $menus = null;
+
+    #[Groups(["common_content"])]
+    public ?array $footers = null;
 }
diff --git a/src/Controller/GetCommonContentController.php b/src/Controller/GetCommonContentController.php
index 2538dae..2130189 100644
--- a/src/Controller/GetCommonContentController.php
+++ b/src/Controller/GetCommonContentController.php
@@ -9,7 +9,9 @@
 use Doctrine\Persistence\ManagerRegistry;
 use RZ\Roadiz\Core\AbstractEntities\TranslationInterface;
 use RZ\Roadiz\CoreBundle\Api\Model\NodesSourcesHeadFactoryInterface;
+use RZ\Roadiz\CoreBundle\Api\TreeWalker\AutoChildrenNodeSourceWalker;
 use RZ\Roadiz\CoreBundle\Api\TreeWalker\TreeWalkerGenerator;
+use RZ\Roadiz\CoreBundle\Entity\NodesSources;
 use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
 use RZ\Roadiz\CoreBundle\Repository\TranslationRepository;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -19,21 +21,12 @@
 
 final class GetCommonContentController extends AbstractController
 {
-    private ManagerRegistry $managerRegistry;
-    private NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory;
-    private PreviewResolverInterface $previewResolver;
-    private TreeWalkerGenerator $treeWalkerGenerator;
-
     public function __construct(
-        ManagerRegistry $managerRegistry,
-        NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory,
-        PreviewResolverInterface $previewResolver,
-        TreeWalkerGenerator $treeWalkerGenerator
+        private readonly ManagerRegistry $managerRegistry,
+        private readonly NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory,
+        private readonly PreviewResolverInterface $previewResolver,
+        private readonly TreeWalkerGenerator $treeWalkerGenerator
     ) {
-        $this->managerRegistry = $managerRegistry;
-        $this->nodesSourcesHeadFactory = $nodesSourcesHeadFactory;
-        $this->previewResolver = $previewResolver;
-        $this->treeWalkerGenerator = $treeWalkerGenerator;
     }
 
     public function __invoke(Request $request): ?CommonContent
@@ -46,19 +39,39 @@ public function __invoke(Request $request): ?CommonContent
             $request->attributes->set('data', $resource);
             $resource->head = $this->nodesSourcesHeadFactory->createForTranslation($translation);
             $resource->home = $resource->head->getHomePage();
+            $resource->errorPage = $this->getErrorPage($translation);
             $resource->menus = $this->treeWalkerGenerator->getTreeWalkersForTypeAtRoot(
                 'Menu',
                 MenuNodeSourceWalker::class,
                 $translation,
                 3
             );
+            $resource->footers = $this->treeWalkerGenerator->getTreeWalkersForTypeAtRoot(
+                'Footer',
+                AutoChildrenNodeSourceWalker::class,
+                $translation,
+                4
+            );
             return $resource;
         } catch (ResourceNotFoundException $exception) {
             throw $this->createNotFoundException($exception->getMessage(), $exception);
         }
     }
 
-    protected function getTranslationFromRequest(?Request $request): TranslationInterface
+    private function getErrorPage(TranslationInterface $translation): ?NodesSources
+    {
+        if (!class_exists('\App\GeneratedEntity\NSErrorPage')) {
+            return null;
+        }
+        // @phpstan-ignore-next-line
+        return $this->managerRegistry->getRepository('\App\GeneratedEntity\NSErrorPage')
+            ->findOneBy([
+                'translation' => $translation,
+                'node.nodeName' => 'error-page'
+            ]);
+    }
+
+    private function getTranslationFromRequest(?Request $request): TranslationInterface
     {
         $locale = null;
 
@@ -90,7 +103,7 @@ protected function getTranslationFromRequest(?Request $request): TranslationInte
         return $translation;
     }
 
-    protected function getTranslationRepository(): TranslationRepository
+    private function getTranslationRepository(): TranslationRepository
     {
         $repository = $this->managerRegistry->getRepository(TranslationInterface::class);
         if (!$repository instanceof TranslationRepository) {
diff --git a/src/TreeWalker/MenuNodeSourceWalker.php b/src/TreeWalker/MenuNodeSourceWalker.php
index c8adcdb..4591184 100644
--- a/src/TreeWalker/MenuNodeSourceWalker.php
+++ b/src/TreeWalker/MenuNodeSourceWalker.php
@@ -32,10 +32,6 @@ protected function initializeDefinitions(): void
         }
     }
 
-    /**
-     * @param NodeTypeInterface $nodeType
-     * @return callable
-     */
     protected function createDefinitionForNodeType(NodeTypeInterface $nodeType): callable
     {
         $context = $this->getContext();

From 0be1cdeadae888cea647356818344d3cee86bad0 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 9 Feb 2024 18:17:53 +0100
Subject: [PATCH 08/38] feat: Allow sub Menu

---
 src/Resources/node-types/Menu.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Resources/node-types/Menu.json b/src/Resources/node-types/Menu.json
index 5d2db41..9814a1d 100644
--- a/src/Resources/node-types/Menu.json
+++ b/src/Resources/node-types/Menu.json
@@ -12,7 +12,7 @@
             "position": 1.0,
             "name": "menu_items",
             "label": "Menu items",
-            "default_values": "Page, MenuLink",
+            "default_values": "Page, Menu, MenuLink",
             "type": 16,
             "expanded": false,
             "node_type_name": "Menu",

From 2d514a84c5c92b3d50d961579d090bbcba671a53 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 13 Feb 2024 12:18:46 +0100
Subject: [PATCH 09/38] feat: Added git-cliff configuration template

---
 README.md  |   5 +++
 cliff.toml | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)
 create mode 100644 cliff.toml

diff --git a/README.md b/README.md
index cf18532..e4a29c1 100644
--- a/README.md
+++ b/README.md
@@ -221,6 +221,11 @@ a local environment.
 **We do not recommend this workflow on complex applications** in which you will need to control and version your node-types
 schema. This is only recommended for small and basic websites.
 
+### Generate a CHANGELOG file
+
+You can use `git-cliff` to generate a `CHANGELOG.md` file from your Git tags and commits.
+A `cliff.toml` configuration file is already provided in this skeleton.
+
 ### Credits
 
 This skeleton uses https://github.com/vishnubob/wait-for-it script to wait for MySQL readiness before launching app entrypoint.
diff --git a/cliff.toml b/cliff.toml
new file mode 100644
index 0000000..d53fc37
--- /dev/null
+++ b/cliff.toml
@@ -0,0 +1,105 @@
+# git-cliff ~ default configuration file
+# https://git-cliff.org/docs/configuration
+#
+# Lines starting with "#" are comments.
+# Configuration options are organized into tables and keys.
+# See documentation for more information on available options.
+
+[changelog]
+# changelog header
+header = """
+# Changelog\n
+All notable changes to project will be documented in this file.\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    {% if previous.version %}\
+        ## [{{ version | trim_start_matches(pat="v") }}](<REPO>/compare/{{ previous.version }}...{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
+    {% else %}\
+        ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
+    {% endif %}\
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+
+{% set_global breaking_descriptions = [] %}\
+{% for commit in commits | filter(attribute="breaking_description") %}\
+{% set_global breaking_descriptions = breaking_descriptions | concat(with=commit.breaking_description) %}\
+{% endfor %}\
+{% if breaking_descriptions | length > 0 %}
+### Breaking changes
+{% for description in breaking_descriptions %}
+- {{ description | upper_first }}\
+{% endfor %}
+{% endif %}\
+
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }} - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }}))\
+          {% if commit.links | length > 0 %}\
+              {% for link in commit.links %}\
+                  ([{{ link.text }}]({{ link.href }}))\
+              {% endfor %}\
+          {% endif %}\
+    {% endfor %}
+{% endfor %}\n
+"""
+# remove the leading and trailing whitespace from the template
+trim = true
+# changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# postprocessors
+postprocessors = [
+  { pattern = '<REPO>', replace = "https://gitlab.com/example-project/example-project/-/" },
+]
+[git]
+# parse the commits based on https://www.conventionalcommits.org
+conventional_commits = true
+# filter out the commits that are not conventional
+filter_unconventional = true
+# process each line of a commit as an individual commit
+split_commits = false
+# regex for preprocessing the commit messages
+commit_preprocessors = [
+  { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, # replace issue numbers
+]
+# regex for parsing and grouping commits
+commit_parsers = [
+  { message = "^feat", group = "Features" },
+  { message = "^fix", group = "Bug Fixes" },
+  { message = "^doc", group = "Documentation" },
+  { message = "^perf", group = "Performance" },
+  { message = "^refactor", group = "Refactor" },
+  { message = "^style", group = "Styling" },
+  { message = "^test", group = "Testing" },
+  { message = "^chore", skip = true },
+  { message = "^chore\\(release\\): prepare for", skip = true },
+  { message = "^chore\\(deps\\)", skip = true },
+  { message = "^chore\\(pr\\)", skip = true },
+  { message = "^chore\\(pull\\)", skip = true },
+  { message = "^ci", group = "CI/CD" },
+  { body = ".*security", group = "Security" },
+  { message = "^revert", group = "Revert" },
+]
+# protect breaking changes from being skipped due to matching a skipping commit_parser
+protect_breaking_commits = false
+# filter out the commits that are not matched by commit parsers
+filter_commits = false
+# regex for matching git tags
+tag_pattern = "v[0-9].*"
+
+# regex for skipping tags
+skip_tags = "v0.1.0-beta.1"
+# regex for ignoring tags
+ignore_tags = ""
+# sort the tags topologically
+topo_order = false
+# sort the commits inside sections by oldest/newest order
+sort_commits = "oldest"
+# limit the number of commits included in the changelog.
+# limit_commits = 42

From bd0f2e840dbd416a1be927af8ae881cc118dbb6d Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 13 Feb 2024 13:43:27 +0100
Subject: [PATCH 10/38] feat: Added git-cliff configuration template

---
 cliff.toml | 42 ++++++++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/cliff.toml b/cliff.toml
index d53fc37..332e031 100644
--- a/cliff.toml
+++ b/cliff.toml
@@ -25,26 +25,36 @@ body = """
 {% endif %}\
 
 {% set_global breaking_descriptions = [] %}\
-{% for commit in commits | filter(attribute="breaking_description") %}\
-{% set_global breaking_descriptions = breaking_descriptions | concat(with=commit.breaking_description) %}\
+{% for commit in commits | filter(attribute="breaking", value=true) %}\
+    {% if commit.breaking_description %}\
+        {% set_global breaking_descriptions = breaking_descriptions | concat(with=commit.breaking_description) %}\
+    {% else %}\
+        {% set_global breaking_descriptions = breaking_descriptions | concat(with=commit.message) %}\
+    {% endif %}\
 {% endfor %}\
 {% if breaking_descriptions | length > 0 %}
-### Breaking changes
-{% for description in breaking_descriptions %}
-- {{ description | upper_first }}\
-{% endfor %}
+    ### ⚠ Breaking changes
+    {% for description in breaking_descriptions %}
+        - {{ description | upper_first }}\
+    {% endfor %}
 {% endif %}\
 
 {% for group, commits in commits | group_by(attribute="group") %}
-    ### {{ group | upper_first }}
-    {% for commit in commits %}
-        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }} - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }}))\
-          {% if commit.links | length > 0 %}\
-              {% for link in commit.links %}\
-                  ([{{ link.text }}]({{ link.href }}))\
-              {% endfor %}\
-          {% endif %}\
-    {% endfor %}
+    ### {{ group | striptags | trim | upper_first }}
+    {% for commit in commits
+    | filter(attribute="scope")
+    | sort(attribute="scope") %}
+        - **({{commit.scope}})**{% if commit.breaking %} [**breaking**]{% endif %} \
+            {{ commit.message }} - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }})) - {{ commit.author.name }}
+    {%- endfor -%}
+    {% raw %}\n{% endraw %}\
+    {%- for commit in commits %}
+        {%- if commit.scope -%}
+        {% else -%}
+            - {% if commit.breaking %} [**breaking**]{% endif %}\
+                {{ commit.message }} - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }})) - {{ commit.author.name }}
+        {% endif -%}
+    {% endfor -%}
 {% endfor %}\n
 """
 # remove the leading and trailing whitespace from the template
@@ -55,7 +65,7 @@ footer = """
 """
 # postprocessors
 postprocessors = [
-  { pattern = '<REPO>', replace = "https://gitlab.com/example-project/example-project/-/" },
+  { pattern = '<REPO>', replace = "https://gitlab.com/example-project/example-project/-" },
 ]
 [git]
 # parse the commits based on https://www.conventionalcommits.org

From a130e298474f06108b80e2c8ccb53c85829800f8 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 13 Feb 2024 14:19:14 +0100
Subject: [PATCH 11/38] chore: Regenerate changelog using git-cliff

---
 CHANGELOG.md | 328 +++++++++++++++++++++++++++++++--------------------
 Makefile     |   6 +
 README.md    |  21 +++-
 cliff.toml   |   5 +-
 4 files changed, 228 insertions(+), 132 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index dbc32ea..b3d1c58 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,231 +1,303 @@
-## [v2.2.0](https://github.com/roadiz/skeleton/compare/v2.1.15...v2.2.0) (2023-12-12)
+# Changelog
 
+All notable changes to project will be documented in this file.
+
+## [unreleased]
 
 ### Features
 
-* Added `APP_ROUTER_DEFAULT_URI` to configure framework.router.default_uri ([67ef138](https://github.com/roadiz/skeleton/commit/67ef1389069144257f43cc2df59da799a58902c7))
-* Added Restic services for production backup and restoration in development env ([fc28b13](https://github.com/roadiz/skeleton/commit/fc28b134f03e7bebeaec778ef673d8755f889daf))
-* Do not expose WebResponse resource directly ([a972b80](https://github.com/roadiz/skeleton/commit/a972b80a02e9e65e37f1fbc36d5f20c1c333a14c))
-* Do not use `themes:install` and `themes:migrate` command anymore as Roadiz will generate Doctrine migration at node-type changes ([09b1714](https://github.com/roadiz/skeleton/commit/09b171417d68349c0a77b0d05dd2318c73627af6))
-* Requires php 8.1 minimum ([424783d](https://github.com/roadiz/skeleton/commit/424783d01f95fa3c80536f372ccbc9e67a150217))
-* **Solr:** Added *_ps field type for multiple geolocations ([2c9f5e3](https://github.com/roadiz/skeleton/commit/2c9f5e36c6f0e81a05130c83f94d5872bc99478e))
-* **Solr:** Better Solr managed schema for French fields asciifolding ([141186c](https://github.com/roadiz/skeleton/commit/141186cd0743233e4283ebc5be0b7fd611846232))
-* Switched to php 82 ([8824e7e](https://github.com/roadiz/skeleton/commit/8824e7e9f21338c86ec6b47328fa808f03bc8835))
-* Updated docker-php-entrypoint to perform db migrations first then app:install ([4b2079a](https://github.com/roadiz/skeleton/commit/4b2079a5dbad0f17f3f91be822d5a02be663b6f4))
-* Updated README and Makefile for new `app:migrate` command, disabled default Varnish invalidation ([b34cf42](https://github.com/roadiz/skeleton/commit/b34cf42f8b03879bc3152653d8819d63e3e72ca9))
-* Upgraded configuration for Roadiz 2.2 ([8ef0d3f](https://github.com/roadiz/skeleton/commit/8ef0d3f18a74f78dd99df94c2d029ee5b1cd0a4b))
+- Use a dedicated docker entrypoint for docker cron image - ([067d9fd](https://github.com/roadiz/skeleton/commit/067d9fd0fc464a1d3f59eb5a6286fc031a99eb99)) - Ambroise Maupate
+- Switch to roadiz dev 2.3.x - ([1ee942d](https://github.com/roadiz/skeleton/commit/1ee942dd10505d726be1b4b1291b5abb4fe47882)) - Ambroise Maupate
+- Added Footers and error page to common content - ([edc2550](https://github.com/roadiz/skeleton/commit/edc2550cbdd311058285480cff87db4894485a6a)) - Ambroise Maupate
+- Allow sub Menu - ([0be1cde](https://github.com/roadiz/skeleton/commit/0be1cdeadae888cea647356818344d3cee86bad0)) - Ambroise Maupate
+- Added git-cliff configuration template - ([2d514a8](https://github.com/roadiz/skeleton/commit/2d514a84c5c92b3d50d961579d090bbcba671a53)) - Ambroise Maupate
+- Added git-cliff configuration template - ([bd0f2e8](https://github.com/roadiz/skeleton/commit/bd0f2e840dbd416a1be927af8ae881cc118dbb6d)) - Ambroise Maupate
 
+## [2.2.1](https://github.com/roadiz/skeleton/compare/v2.2.0...v2.2.1) - 2023-12-12
 
 ### Bug Fixes
 
-* Configure API firewall as database-less JWT by default to ensure PreviewUser are not reloaded. Missing `user_checker` ([23d64e4](https://github.com/roadiz/skeleton/commit/23d64e49b613286f1a7b1818c8fbbea5db336dfa))
-* **Docker:** Clear caches after migrations and db ready ([91c6220](https://github.com/roadiz/skeleton/commit/91c62209a44ac4a6fc092e4cd1ffe57cf9e70a1d))
-* Fix docker compose watchtower depends-on labels ([f5afbd3](https://github.com/roadiz/skeleton/commit/f5afbd38294523b7d9ca4a6faa7ae87af49be54b))
-* Force watchtower to restart dependent containers ([a2b0357](https://github.com/roadiz/skeleton/commit/a2b0357f1ff1a8c6032b5e77b5b6d5f77c0c449e))
-* Removed deprecated `lexik_jwt_authentication.jwt_token_authenticator` ([42850a0](https://github.com/roadiz/skeleton/commit/42850a0cfe79628557c1454b65c75e2d4c78e57b))
-* Set default empty dotenv vars for OpenID and ignore large files and archives from Varnish cache ([94f3975](https://github.com/roadiz/skeleton/commit/94f3975ccdfdf5369acf1cbae7ea7a013ab5196b))
-* Use VARNISH_HOST instead of URL for reverseProxyCache host param ([5af0965](https://github.com/roadiz/skeleton/commit/5af0965020325714737c11b23c7b95c52b8fc63f))
-
-## [v2.1.15](https://github.com/roadiz/skeleton/compare/v2.1.14...v2.1.15) (2023-09-20)
+- Updated Github action version matrix - ([2ea26ef](https://github.com/roadiz/skeleton/commit/2ea26efda32ac04a52b0afbaa2409b89ab2bb464)) - Ambroise Maupate
 
+## [2.2.0](https://github.com/roadiz/skeleton/compare/v2.1.15...v2.2.0) - 2023-12-12
 
 ### Bug Fixes
 
-* **CI:** Build and tag at the same time to avoid push same docker image digest from different jobs ([6a96982](https://github.com/roadiz/skeleton/commit/6a96982957e029c9fb19f771ae8a32b88b685798))
+- **(Docker)** Clear caches after migrations and db ready - ([91c6220](https://github.com/roadiz/skeleton/commit/91c62209a44ac4a6fc092e4cd1ffe57cf9e70a1d)) - Ambroise Maupate
+- Configure API firewall as database-less JWT by default to ensure PreviewUser are not reloaded. Missing `user_checker` - ([23d64e4](https://github.com/roadiz/skeleton/commit/23d64e49b613286f1a7b1818c8fbbea5db336dfa)) - Ambroise Maupate
+- Fix docker compose watchtower depends-on labels - ([f5afbd3](https://github.com/roadiz/skeleton/commit/f5afbd38294523b7d9ca4a6faa7ae87af49be54b)) - Ambroise Maupate
+- Removed deprecated `lexik_jwt_authentication.jwt_token_authenticator` - ([42850a0](https://github.com/roadiz/skeleton/commit/42850a0cfe79628557c1454b65c75e2d4c78e57b)) - Ambroise Maupate
 
-## [v2.1.14](https://github.com/roadiz/skeleton/compare/v2.1.13...v2.1.14) (2023-07-28)
+### Features
 
+- **(Solr)** Better Solr managed schema for French fields asciifolding - ([141186c](https://github.com/roadiz/skeleton/commit/141186cd0743233e4283ebc5be0b7fd611846232)) - Ambroise Maupate
+- **(Solr)** Added *_ps field type for multiple geolocations - ([2c9f5e3](https://github.com/roadiz/skeleton/commit/2c9f5e36c6f0e81a05130c83f94d5872bc99478e)) - Ambroise Maupate
+- Added Restic services for production backup and restoration in development env - ([fc28b13](https://github.com/roadiz/skeleton/commit/fc28b134f03e7bebeaec778ef673d8755f889daf)) - Ambroise Maupate
+- Added `APP_ROUTER_DEFAULT_URI` to configure framework.router.default_uri - ([67ef138](https://github.com/roadiz/skeleton/commit/67ef1389069144257f43cc2df59da799a58902c7)) - Ambroise Maupate
+- Switched to php 82 - ([8824e7e](https://github.com/roadiz/skeleton/commit/8824e7e9f21338c86ec6b47328fa808f03bc8835)) - Ambroise Maupate
+- Requires php 8.1 minimum - ([424783d](https://github.com/roadiz/skeleton/commit/424783d01f95fa3c80536f372ccbc9e67a150217)) - Ambroise Maupate
+
+## [2.1.15](https://github.com/roadiz/skeleton/compare/v2.1.14...v2.1.15) - 2023-09-20
 
 ### Bug Fixes
 
-* Added AutoDevops templates for Gitlab CI/CD ([769495d](https://github.com/roadiz/skeleton/commit/769495dd8460fd66c8844a04c56be5fd9e259d69))
+- **(CI)** Build and tag at the same time to avoid push same docker image digest from different jobs - ([6a96982](https://github.com/roadiz/skeleton/commit/6a96982957e029c9fb19f771ae8a32b88b685798)) - Ambroise Maupate
+- Set default empty dotenv vars for OpenID and ignore large files and archives from Varnish cache - ([94f3975](https://github.com/roadiz/skeleton/commit/94f3975ccdfdf5369acf1cbae7ea7a013ab5196b)) - Ambroise Maupate
+- Use VARNISH_HOST instead of URL for reverseProxyCache host param - ([5af0965](https://github.com/roadiz/skeleton/commit/5af0965020325714737c11b23c7b95c52b8fc63f)) - Ambroise Maupate
 
-## [v2.1.13](https://github.com/roadiz/skeleton/compare/v2.1.12...v2.1.13) (2023-07-25)
+### Documentation
 
+- More config hints - ([1c0504d](https://github.com/roadiz/skeleton/commit/1c0504d18bfb45b34d27102d2115f3b31677ce7d)) - Ambroise Maupate
 
-### Bug Fixes
+### Features
+
+- Updated docker-php-entrypoint to perform db migrations first then app:install - ([4b2079a](https://github.com/roadiz/skeleton/commit/4b2079a5dbad0f17f3f91be822d5a02be663b6f4)) - Ambroise Maupate
 
-* Wrong args order for docker compose with custom config file ([f00addf](https://github.com/roadiz/skeleton/commit/f00addff020f3b9b583db854b29d556429dec43e))
+## [2.1.14](https://github.com/roadiz/skeleton/compare/v2.1.13...v2.1.14) - 2023-07-28
 
-## [v2.1.12](https://github.com/roadiz/skeleton/compare/v2.1.11...v2.1.12) (2023-07-25)
+### Bug Fixes
 
+- Added AutoDevops templates for Gitlab CI/CD - ([769495d](https://github.com/roadiz/skeleton/commit/769495dd8460fd66c8844a04c56be5fd9e259d69)) - Ambroise Maupate
 
 ### Features
 
-* Added some doc about using symfony server:start instead of full docker stack ([b7ed89e](https://github.com/roadiz/skeleton/commit/b7ed89e1fd3bef5ce7bdb49b97e978037595d65d))
-
-## [v2.1.11](https://github.com/roadiz/skeleton/compare/v2.1.10...v2.1.11) (2023-07-25)
+- Do not use `themes:install` and `themes:migrate` command anymore as Roadiz will generate Doctrine migration at node-type changes - ([09b1714](https://github.com/roadiz/skeleton/commit/09b171417d68349c0a77b0d05dd2318c73627af6)) - Ambroise Maupate
+- Do not expose WebResponse resource directly - ([a972b80](https://github.com/roadiz/skeleton/commit/a972b80a02e9e65e37f1fbc36d5f20c1c333a14c)) - Ambroise Maupate
+- Updated README and Makefile for new `app:migrate` command, disabled default Varnish invalidation - ([b34cf42](https://github.com/roadiz/skeleton/commit/b34cf42f8b03879bc3152653d8819d63e3e72ca9)) - Ambroise Maupate
 
+## [2.1.13](https://github.com/roadiz/skeleton/compare/v2.1.12...v2.1.13) - 2023-07-25
 
 ### Bug Fixes
 
-* Added missing Makefile entries, README and API platform `metadata_backward_compatibility_layer` ([3346d79](https://github.com/roadiz/skeleton/commit/3346d794a60e3e94978a13d3f56d5bf28927f07b))
-* Run secrets command after composer install ([4ef7f4c](https://github.com/roadiz/skeleton/commit/4ef7f4c6a855fac2e604c208fe212f91c8912470))
+- Wrong args order for docker compose with custom config file - ([f00addf](https://github.com/roadiz/skeleton/commit/f00addff020f3b9b583db854b29d556429dec43e)) - Ambroise Maupate
 
-## [v2.1.10](https://github.com/roadiz/skeleton/compare/v2.1.9...v2.1.10) (2023-07-12)
+## [2.1.12](https://github.com/roadiz/skeleton/compare/v2.1.11...v2.1.12) - 2023-07-25
 
+### Features
+
+- Added some doc about using symfony server:start instead of full docker stack - ([b7ed89e](https://github.com/roadiz/skeleton/commit/b7ed89e1fd3bef5ce7bdb49b97e978037595d65d)) - Ambroise Maupate
+
+## [2.1.11](https://github.com/roadiz/skeleton/compare/v2.1.10...v2.1.11) - 2023-07-25
 
 ### Bug Fixes
 
-* Missing `gedmo_loggable` doctrine mapping for Superclasses ([ce63709](https://github.com/roadiz/skeleton/commit/ce63709c317b795ab3ee1e31ade0b8b4f3383ffd))
+- Added missing Makefile entries, README and API platform `metadata_backward_compatibility_layer` - ([3346d79](https://github.com/roadiz/skeleton/commit/3346d794a60e3e94978a13d3f56d5bf28927f07b)) - Ambroise Maupate
+- Run secrets command after composer install - ([4ef7f4c](https://github.com/roadiz/skeleton/commit/4ef7f4c6a855fac2e604c208fe212f91c8912470)) - Ambroise Maupate
+
+### Features
 
-## [v2.1.9](https://github.com/roadiz/skeleton/compare/v2.1.8...v2.1.9) (2023-06-27)
+- Upgraded configuration for Roadiz 2.2 - ([8ef0d3f](https://github.com/roadiz/skeleton/commit/8ef0d3f18a74f78dd99df94c2d029ee5b1cd0a4b)) - Ambroise Maupate
 
+## [2.1.10](https://github.com/roadiz/skeleton/compare/v2.1.9...v2.1.10) - 2023-07-12
 
 ### Bug Fixes
 
-* Fixed `com.centurylinklabs.watchtower.depends-on` syntax ([fc484c4](https://github.com/roadiz/skeleton/commit/fc484c43e08a1301922d614469e0046730cd9862))
+- Missing gedmo_loggable doctrine mapping for Superclasses - ([ce63709](https://github.com/roadiz/skeleton/commit/ce63709c317b795ab3ee1e31ade0b8b4f3383ffd)) - Ambroise Maupate
 
-## [v2.1.8](https://github.com/roadiz/skeleton/compare/v2.1.7...v2.1.8) (2023-06-12)
+## [2.1.9](https://github.com/roadiz/skeleton/compare/v2.1.8...v2.1.9) - 2023-06-27
 
+### Bug Fixes
+
+- Fixed `com.centurylinklabs.watchtower.depends-on` syntax - ([fc484c4](https://github.com/roadiz/skeleton/commit/fc484c43e08a1301922d614469e0046730cd9862)) - Ambroise Maupate
+
+## [2.1.8](https://github.com/roadiz/skeleton/compare/v2.1.7...v2.1.8) - 2023-06-12
 
 ### Bug Fixes
 
-* Renamed Gitlab CI dropped vars ([809af31](https://github.com/roadiz/skeleton/commit/809af3128ae18bce471a7140c3603facf1111ab5))
+- Rename Gitlab CI dropped vars - ([809af31](https://github.com/roadiz/skeleton/commit/809af3128ae18bce471a7140c3603facf1111ab5)) - Ambroise Maupate
+
+## [2.1.7](https://github.com/roadiz/skeleton/compare/v2.1.6...v2.1.7) - 2023-06-01
 
-## [v2.1.7](https://github.com/roadiz/skeleton/compare/v2.1.6...v2.1.7) (2023-06-01)
+### Bug Fixes
+
+- Clear all cache pools on Symfony 5.4 on docker-entrypoint - ([03b93a8](https://github.com/roadiz/skeleton/commit/03b93a895e8dca451e8d261c43dca498fe8264a6)) - Ambroise Maupate
 
+## [2.1.6](https://github.com/roadiz/skeleton/compare/v2.1.5...v2.1.6) - 2023-05-31
 
 ### Bug Fixes
 
-* Clear all cache pools on Symfony 5.4 on docker-entrypoint ([03b93a8](https://github.com/roadiz/skeleton/commit/03b93a895e8dca451e8d261c43dca498fe8264a6))
+- Missing serialization group on custom_form operations - ([41d57cc](https://github.com/roadiz/skeleton/commit/41d57cc57ead98c56981c26418570adc5c6b131b)) - Ambroise Maupate
 
-## [v2.1.6](https://github.com/roadiz/skeleton/compare/v2.1.5...v2.1.6) (2023-05-31)
+## [2.1.5](https://github.com/roadiz/skeleton/compare/v2.1.4...v2.1.5) - 2023-05-31
 
+### CI/CD
 
-### Bug Fixes
+- Added `symfony/requirements-checker` and composer install --no-dev during CI build - ([3585c15](https://github.com/roadiz/skeleton/commit/3585c15a2f133d2ae2a4d7085e234a3a5d3ab44d)) - Ambroise Maupate
 
-* Missing serialization group on custom_form operations ([41d57cc](https://github.com/roadiz/skeleton/commit/41d57cc57ead98c56981c26418570adc5c6b131b))
+## [2.1.4](https://github.com/roadiz/skeleton/compare/v2.1.3...v2.1.4) - 2023-05-17
 
-## [v2.1.5](https://github.com/roadiz/skeleton/compare/v2.1.4...v2.1.5) (2023-05-31)
+### Bug Fixes
 
-## [v2.1.4](https://github.com/roadiz/skeleton/compare/v2.1.3...v2.1.4) (2023-05-17)
+- Force watchtower to restart dependent containers - ([a2b0357](https://github.com/roadiz/skeleton/commit/a2b0357f1ff1a8c6032b5e77b5b6d5f77c0c449e)) - Ambroise Maupate
+- Mixed up public and private file volumes for backup - ([8d954ac](https://github.com/roadiz/skeleton/commit/8d954acb885bda28fd071c7db3b747bf57ac9af3)) - Ambroise Maupate
 
+## [2.1.3](https://github.com/roadiz/skeleton/compare/v2.1.2...v2.1.3) - 2023-03-20
 
 ### Bug Fixes
 
-* Mixed up public and private file volumes for backup ([8d954ac](https://github.com/roadiz/skeleton/commit/8d954acb885bda28fd071c7db3b747bf57ac9af3))
+- Fixed GetCommonContentController using NodesSourcesHeadFactoryInterface and type-hinting Request - ([33b637a](https://github.com/roadiz/skeleton/commit/33b637aea034111199b4edc00ceec788ff5b659c)) - Ambroise Maupate
+- Missing docker/php-fpm-alpine/wait-for-it.sh in Dockerfile COPY - ([54785fe](https://github.com/roadiz/skeleton/commit/54785fef5fd0847a85c1746e51669563999b5363)) - Ambroise Maupate
+- Varnish ACL should allow cron and worker hostname to purge - ([b1a69e4](https://github.com/roadiz/skeleton/commit/b1a69e4d367330bd4b86a606de3da835f00ba69e)) - Ambroise Maupate
 
-## [v2.1.3](https://github.com/roadiz/skeleton/compare/v2.1.2...v2.1.3) (2023-03-20)
+### CI/CD
 
+- Improve Docker compose templates - ([6ae85ee](https://github.com/roadiz/skeleton/commit/6ae85ee0e748905a7d8160886d5d3c493ac05732)) - Ambroise Maupate
 
 ### Features
 
-* Allow MultiTypeChildren treeWalker definition to fetch invisible nodes ([3785331](https://github.com/roadiz/skeleton/commit/3785331d6220dfb8497ff5b4620193127fa01db6))
-* Migrate from monolithic docker image to app, nginx, worker and cron containers. ([2a88497](https://github.com/roadiz/skeleton/commit/2a8849779778dd2e1ccf2217944cd8bcd8d6d97a))
+- Migrate from monolithic docker image to app, nginx, worker and cron containers. - ([2a88497](https://github.com/roadiz/skeleton/commit/2a8849779778dd2e1ccf2217944cd8bcd8d6d97a)) - Ambroise Maupate
+- Allow MultiTypeChildren treeWalker definition to fetch invisible nodes - ([3785331](https://github.com/roadiz/skeleton/commit/3785331d6220dfb8497ff5b4620193127fa01db6)) - Ambroise Maupate
 
+## [2.1.2](https://github.com/roadiz/skeleton/compare/v2.1.1...v2.1.2) - 2023-03-14
 
 ### Bug Fixes
 
-* Fixed GetCommonContentController using NodesSourcesHeadFactoryInterface and type-hinting Request ([33b637a](https://github.com/roadiz/skeleton/commit/33b637aea034111199b4edc00ceec788ff5b659c))
-* Missing docker/php-fpm-alpine/wait-for-it.sh in Dockerfile COPY ([54785fe](https://github.com/roadiz/skeleton/commit/54785fef5fd0847a85c1746e51669563999b5363))
-* Varnish ACL should allow cron and worker hostname to purge ([b1a69e4](https://github.com/roadiz/skeleton/commit/b1a69e4d367330bd4b86a606de3da835f00ba69e))
+- Strip out irrelevant data - ([929756f](https://github.com/roadiz/skeleton/commit/929756fa1a5148dd5abb9d4240a11c368c858cc0)) - Ambroise Maupate
 
-## [v2.1.2](https://github.com/roadiz/skeleton/compare/v2.1.1...v2.1.2) (2023-03-14)
+## [2.1.1](https://github.com/roadiz/skeleton/compare/v2.1.0...v2.1.1) - 2023-03-08
 
+### Bug Fixes
+
+- Missing return types on provided node-types - ([c5208fa](https://github.com/roadiz/skeleton/commit/c5208fa95f47fc5d9105b7c32139af9cf3082dd5)) - Ambroise Maupate
+
+## [2.1.0](https://github.com/roadiz/skeleton/compare/2.0.5...v2.1.0) - 2023-03-06
 
 ### Bug Fixes
 
-* Strip out irrelevant data ([929756f](https://github.com/roadiz/skeleton/commit/929756fa1a5148dd5abb9d4240a11c368c858cc0))
+- **(Nginx)** Missing CORS on pdf extension - ([3fddf0e](https://github.com/roadiz/skeleton/commit/3fddf0e68b4212fce1f93427d40151954426f99c)) - Ambroise Maupate
+- Missing path prefix for Symfony profiler - ([7015e36](https://github.com/roadiz/skeleton/commit/7015e368e9cc2b3ca38efe6a6b5cf4c2685d15c1)) - Ambroise Maupate
+- Workaround for https://github.com/varnish/docker-varnish/issues/53 - ([1d9b847](https://github.com/roadiz/skeleton/commit/1d9b8477f342d12b82bb53e1e1d81faab62fa748)) - Ambroise Maupate
+- Fixed doctrine resolved entities - ([3d2e029](https://github.com/roadiz/skeleton/commit/3d2e029f7c25b80ccf24be4848657d0942f6e080)) - Ambroise Maupate
+- Missing ,`/css/login/image` path - ([06e6a70](https://github.com/roadiz/skeleton/commit/06e6a70a787067fe2b1b543e667a7a09bcca36cd)) - Ambroise Maupate
+- SSO user roles - ([a3a3b92](https://github.com/roadiz/skeleton/commit/a3a3b9290e26bdb9fe894fb49899b860b3f1cb62)) - Ambroise Maupate
+- Keep themes and bundles assets to include them in docker image - ([c43a3ee](https://github.com/roadiz/skeleton/commit/c43a3ee1799f59e095150637167f343dd306ec78)) - Ambroise Maupate
+- added isTransactional: false on Doctrine migrations - ([7164208](https://github.com/roadiz/skeleton/commit/71642086cf28b342f5089a40850eb1f871f2cc9a)) - Ambroise Maupate
+- skip messenger_messages migration if table already exists - ([e594113](https://github.com/roadiz/skeleton/commit/e594113ae15dcd7cbe813eca1ac295bb3b16cde1)) - Ambroise Maupate
 
-## [v2.1.1](https://github.com/roadiz/skeleton/compare/v2.1.0...v2.1.1) (2023-03-08)
+### Features
 
+- **(Documents)** Moved private documents to a dedicated listing - ([eaf8ce6](https://github.com/roadiz/skeleton/commit/eaf8ce6d4a188bce173c0d2caf3bba2046f32243)) - Ambroise Maupate
+- Up to PHP 8.0, changed api resources config for roadiz v2.1 - ([d2bb269](https://github.com/roadiz/skeleton/commit/d2bb26980d86a5830faedc4a8a38a2bee67e0b2c)) - Ambroise Maupate
+- Change doctrine mapping to attribute - ([f2521cc](https://github.com/roadiz/skeleton/commit/f2521cc3d43967994df1ab903b1a4f0651d1ea56)) - Ambroise Maupate
+- Use attributes on Models - ([61a4763](https://github.com/roadiz/skeleton/commit/61a47634bfa0b13f8468b1aab38683f4fdd59fea)) - Ambroise Maupate
+- Added wait-for-it before launching app - ([9c19335](https://github.com/roadiz/skeleton/commit/9c1933504897fbc1b2e507bea9c5c06a5c913e21)) - Ambroise Maupate
+- Deprecated api_platform config - ([38235f3](https://github.com/roadiz/skeleton/commit/38235f3b0804f7345dc7a8d18df66cb82ff08008)) - Ambroise Maupate
+- Do not wait for 1 sec on before_launch script thanks to wait-for-it.sh - ([0f9f317](https://github.com/roadiz/skeleton/commit/0f9f31747768ce3bc776de2f96e8be89b5f348d1)) - Ambroise Maupate
+- Use traefik path_prefix to host API and NuxtJS on the same domain - ([8b5f4c5](https://github.com/roadiz/skeleton/commit/8b5f4c5ab598ce4936081b22a1e60ad43295194c)) - Ambroise Maupate
+- Added backup docker service example - ([d1dc286](https://github.com/roadiz/skeleton/commit/d1dc2860dc2b0195fd467e6ad4f3a733bd64c5d2)) - Ambroise Maupate
+- Added CIDR to Varnish ACLs - ([498d708](https://github.com/roadiz/skeleton/commit/498d70841c0865cdc946c504fd7f25f7ca518e2f)) - Ambroise Maupate
+- Use Redis as default cache backend for production - ([e8144e3](https://github.com/roadiz/skeleton/commit/e8144e371ebf7080e103534c105bfd7aadda7291)) - Ambroise Maupate
+- Default enable Varnish for dev env and disable Solr by default - ([bb180f6](https://github.com/roadiz/skeleton/commit/bb180f667f59776a76bb630db455f320919341f0)) - Ambroise Maupate
+- Stop messenger workers when clearing cache or migrating - ([13664c9](https://github.com/roadiz/skeleton/commit/13664c93d2259ba6e0ae036470f41f1c7a18327e)) - Ambroise Maupate
+- Added document_thumbnails serialization group - ([7dcaff8](https://github.com/roadiz/skeleton/commit/7dcaff82e17c5c04597852934cf1977b14baa485)) - Ambroise Maupate
+- Moved constant settings to DotEnv variables - ([cde8a48](https://github.com/roadiz/skeleton/commit/cde8a4809484371fdc00b92bcdcf7f5599291c69)) - Ambroise Maupate
+- Use Symfony secrets to store sensitive configuration values - ([446d5c5](https://github.com/roadiz/skeleton/commit/446d5c54afb40159cb4b7c97376f54da23cdc257)) - Ambroise Maupate
+- Added Flysystem default storages - ([687ef20](https://github.com/roadiz/skeleton/commit/687ef2053e941adc5f2fbb158daafeac19b4bd0f)) - Ambroise Maupate
+- Added default Menu and MenuLink node-types - ([891f378](https://github.com/roadiz/skeleton/commit/891f3783943b3489e35d48c4780584c194e2c287)) - Ambroise Maupate
+- Use dev-develop bundles - ([7252f2c](https://github.com/roadiz/skeleton/commit/7252f2c5353dd5a48ed007a4a06b680b071bae04)) - Ambroise Maupate
+- Restrict open_id users to editors roles - ([2672f26](https://github.com/roadiz/skeleton/commit/2672f26ffa331a4e94679abf6deb8770590ad9c1)) - Ambroise Maupate
+- Declare docker volumes to persist node-types configuration - ([5d17b89](https://github.com/roadiz/skeleton/commit/5d17b89a100f0cadf2385ce80aa34cde9968f6a0)) - Ambroise Maupate
+- Force dev-develop version - ([e99cda4](https://github.com/roadiz/skeleton/commit/e99cda45d160d229f4bc9d5e79116e718d20cdab)) - Ambroise Maupate
+- Always pretty print with JMS Serializer - ([d7154fd](https://github.com/roadiz/skeleton/commit/d7154fd916e1d60ba2aad8963d5e8aa4c58ac86f)) - Ambroise Maupate
+- Dotenv for API name and description - ([4a8ac47](https://github.com/roadiz/skeleton/commit/4a8ac4747c5409e76cbca836a08c28397156cd7c)) - Ambroise Maupate
+- Added migration for Symfony Messenger message table - ([7a5a410](https://github.com/roadiz/skeleton/commit/7a5a410e4d721b0277efc460d4bc80c57a704afc)) - Ambroise Maupate
+- Invert secret gen and jwt in README - ([d89ecd6](https://github.com/roadiz/skeleton/commit/d89ecd62fb0960692ebd6bed44d75eac27662b5a)) - Ambroise Maupate
+- Ignore /config/secrets/*/*.decrypt.private.php - ([a4e32c3](https://github.com/roadiz/skeleton/commit/a4e32c3a9b046dfce86b3cb93b9f9348b86af88d)) - Ambroise Maupate
+- Do not commit prod secret keys - ([0103b9f](https://github.com/roadiz/skeleton/commit/0103b9f41955c8506d6dd1f9ca29e5a05f61009d)) - Ambroise Maupate
+- Added trusted_headers to accept HTTPS proto from Load balancers - ([4cc8130](https://github.com/roadiz/skeleton/commit/4cc8130419c455aefcf322eaa60f45b650659ee3)) - Ambroise Maupate
+- Fixed Roadiz to v2.1 - ([106a79f](https://github.com/roadiz/skeleton/commit/106a79f1b0a38f05dffb5ca3155c995e91ed8e45)) - Ambroise Maupate
+
+### Styling
+
+- Customize Api Platform Swagger UI - ([fadb753](https://github.com/roadiz/skeleton/commit/fadb753305649da071a9475098a7ef6121ddd8c2)) - Ambroise Maupate
+
+### Testing
+
+- Added Github actions - ([4a353a9](https://github.com/roadiz/skeleton/commit/4a353a9bac29cd81b32220ad79eb5b7c31d12538)) - Ambroise Maupate
+
+## [2.0.5](https://github.com/roadiz/skeleton/compare/2.0.4...2.0.5) - 2022-09-15
 
 ### Bug Fixes
 
-* Missing return types on provided node-types ([c5208fa](https://github.com/roadiz/skeleton/commit/c5208fa95f47fc5d9105b7c32139af9cf3082dd5))
+- Missing realms Rozier admin section - ([834cd85](https://github.com/roadiz/skeleton/commit/834cd85ec9a2c26e29235bc05bb5b5b0ac89e5f5)) - Ambroise Maupate
+
+## [2.0.4](https://github.com/roadiz/skeleton/compare/2.0.3...2.0.4) - 2022-09-15
 
-## v2.1.0 (2023-03-06)
+### Bug Fixes
 
+- Removed redundant dependencies - ([911924a](https://github.com/roadiz/skeleton/commit/911924a3a3e1646a7f7795ea5c1270625cf4424f)) - Ambroise Maupate
 
 ### Features
 
-* Added backup docker service example ([d1dc286](https://github.com/roadiz/skeleton/commit/d1dc2860dc2b0195fd467e6ad4f3a733bd64c5d2))
-* Added CIDR to Varnish ACLs ([498d708](https://github.com/roadiz/skeleton/commit/498d70841c0865cdc946c504fd7f25f7ca518e2f))
-* Added default Menu and MenuLink node-types ([891f378](https://github.com/roadiz/skeleton/commit/891f3783943b3489e35d48c4780584c194e2c287))
-* Added document_thumbnails serialization group ([7dcaff8](https://github.com/roadiz/skeleton/commit/7dcaff82e17c5c04597852934cf1977b14baa485))
-* Added Flysystem default storages ([687ef20](https://github.com/roadiz/skeleton/commit/687ef2053e941adc5f2fbb158daafeac19b4bd0f))
-* Added migration for Symfony Messenger message table ([7a5a410](https://github.com/roadiz/skeleton/commit/7a5a410e4d721b0277efc460d4bc80c57a704afc))
-* Added trusted_headers to accept HTTPS proto from Load balancers ([4cc8130](https://github.com/roadiz/skeleton/commit/4cc8130419c455aefcf322eaa60f45b650659ee3))
-* Added wait-for-it before launching app ([9c19335](https://github.com/roadiz/skeleton/commit/9c1933504897fbc1b2e507bea9c5c06a5c913e21))
-* Always pretty print with JMS Serializer ([d7154fd](https://github.com/roadiz/skeleton/commit/d7154fd916e1d60ba2aad8963d5e8aa4c58ac86f))
-* Change doctrine mapping to attribute ([f2521cc](https://github.com/roadiz/skeleton/commit/f2521cc3d43967994df1ab903b1a4f0651d1ea56))
-* Declare docker volumes to persist node-types configuration ([5d17b89](https://github.com/roadiz/skeleton/commit/5d17b89a100f0cadf2385ce80aa34cde9968f6a0))
-* Default enable Varnish for dev env and disable Solr by default ([bb180f6](https://github.com/roadiz/skeleton/commit/bb180f667f59776a76bb630db455f320919341f0))
-* Deprecated api_platform config ([38235f3](https://github.com/roadiz/skeleton/commit/38235f3b0804f7345dc7a8d18df66cb82ff08008))
-* Do not commit prod secret keys ([0103b9f](https://github.com/roadiz/skeleton/commit/0103b9f41955c8506d6dd1f9ca29e5a05f61009d))
-* Do not wait for 1 sec on before_launch script thanks to wait-for-it.sh ([0f9f317](https://github.com/roadiz/skeleton/commit/0f9f31747768ce3bc776de2f96e8be89b5f348d1))
-* **Documents:** Moved private documents to a dedicated listing ([eaf8ce6](https://github.com/roadiz/skeleton/commit/eaf8ce6d4a188bce173c0d2caf3bba2046f32243))
-* Dotenv for API name and description ([4a8ac47](https://github.com/roadiz/skeleton/commit/4a8ac4747c5409e76cbca836a08c28397156cd7c))
-* Fixed Roadiz to v2.1 ([106a79f](https://github.com/roadiz/skeleton/commit/106a79f1b0a38f05dffb5ca3155c995e91ed8e45))
-* Force dev-develop version ([e99cda4](https://github.com/roadiz/skeleton/commit/e99cda45d160d229f4bc9d5e79116e718d20cdab))
-* Ignore /config/secrets/*/*.decrypt.private.php ([a4e32c3](https://github.com/roadiz/skeleton/commit/a4e32c3a9b046dfce86b3cb93b9f9348b86af88d))
-* Invert secret gen and jwt in README ([d89ecd6](https://github.com/roadiz/skeleton/commit/d89ecd62fb0960692ebd6bed44d75eac27662b5a))
-* Moved constant settings to DotEnv variables ([cde8a48](https://github.com/roadiz/skeleton/commit/cde8a4809484371fdc00b92bcdcf7f5599291c69))
-* Restrict open_id users to editors roles ([2672f26](https://github.com/roadiz/skeleton/commit/2672f26ffa331a4e94679abf6deb8770590ad9c1))
-* Stop messenger workers when clearing cache or migrating ([13664c9](https://github.com/roadiz/skeleton/commit/13664c93d2259ba6e0ae036470f41f1c7a18327e))
-* Up to PHP 8.0, changed api resources config for roadiz v2.1 ([d2bb269](https://github.com/roadiz/skeleton/commit/d2bb26980d86a5830faedc4a8a38a2bee67e0b2c))
-* Use attributes on Models ([61a4763](https://github.com/roadiz/skeleton/commit/61a47634bfa0b13f8468b1aab38683f4fdd59fea))
-* Use dev-develop bundles ([7252f2c](https://github.com/roadiz/skeleton/commit/7252f2c5353dd5a48ed007a4a06b680b071bae04))
-* Use Redis as default cache backend for production ([e8144e3](https://github.com/roadiz/skeleton/commit/e8144e371ebf7080e103534c105bfd7aadda7291))
-* Use Symfony secrets to store sensitive configuration values ([446d5c5](https://github.com/roadiz/skeleton/commit/446d5c54afb40159cb4b7c97376f54da23cdc257))
-* Use traefik path_prefix to host API and NuxtJS on the same domain ([8b5f4c5](https://github.com/roadiz/skeleton/commit/8b5f4c5ab598ce4936081b22a1e60ad43295194c))
-
-
-### Bug Fixes
-
-* added isTransactional: false on Doctrine migrations ([7164208](https://github.com/roadiz/skeleton/commit/71642086cf28b342f5089a40850eb1f871f2cc9a))
-* Fixed doctrine resolved entities ([3d2e029](https://github.com/roadiz/skeleton/commit/3d2e029f7c25b80ccf24be4848657d0942f6e080))
-* Keep themes and bundles assets to include them in docker image ([c43a3ee](https://github.com/roadiz/skeleton/commit/c43a3ee1799f59e095150637167f343dd306ec78))
-* Missing ,`/css/login/image` path ([06e6a70](https://github.com/roadiz/skeleton/commit/06e6a70a787067fe2b1b543e667a7a09bcca36cd))
-* Missing path prefix for Symfony profiler ([7015e36](https://github.com/roadiz/skeleton/commit/7015e368e9cc2b3ca38efe6a6b5cf4c2685d15c1))
-* **Nginx:** Missing CORS on pdf extension ([3fddf0e](https://github.com/roadiz/skeleton/commit/3fddf0e68b4212fce1f93427d40151954426f99c))
-* skip messenger_messages migration if table already exists ([e594113](https://github.com/roadiz/skeleton/commit/e594113ae15dcd7cbe813eca1ac295bb3b16cde1))
-* SSO user roles ([a3a3b92](https://github.com/roadiz/skeleton/commit/a3a3b9290e26bdb9fe894fb49899b860b3f1cb62))
-* Workaround for https://github.com/varnish/docker-varnish/issues/53 ([1d9b847](https://github.com/roadiz/skeleton/commit/1d9b8477f342d12b82bb53e1e1d81faab62fa748))
-
-## 2.0.5 (2022-09-15)
-
-### Bug Fixes
-
-* Missing `realms` Rozier admin section ([834cd85](https://github.com/roadiz/skeleton/commit/834cd85ec9a2c26e29235bc05bb5b5b0ac89e5f5))
-
-## 2.0.4 (2022-09-15)
+- Missing some default .env vars - ([6052505](https://github.com/roadiz/skeleton/commit/605250508651574dde83192591cd9fcf2ff2258e)) - Ambroise Maupate
+- Improved config/packages files and default .env - ([910f32b](https://github.com/roadiz/skeleton/commit/910f32b70e75424598c000199d03315cf5e2c8a4)) - Ambroise Maupate
+
+## [2.0.3](https://github.com/roadiz/skeleton/compare/2.0.2...2.0.3) - 2022-09-07
 
 ### Features
 
-* Improved config/packages files and default .env ([910f32b](https://github.com/roadiz/skeleton/commit/910f32b70e75424598c000199d03315cf5e2c8a4))
-* Missing some default .env vars ([6052505](https://github.com/roadiz/skeleton/commit/605250508651574dde83192591cd9fcf2ff2258e))
+- Added APP_FFMPEG_PATH DotEnv and ffmpeg binary to Docker images - ([4c0f063](https://github.com/roadiz/skeleton/commit/4c0f063df497553d9fcd411bd47167c05b1beedb)) - Ambroise Maupate
+- Use Imagick as default image driver to support AVIF/HEIC files formats - ([20ee3f6](https://github.com/roadiz/skeleton/commit/20ee3f643dc25deff3632385bbfe3e94f7faed28)) - Ambroise Maupate
 
-### Bug Fixes
+## [2.0.2](https://github.com/roadiz/skeleton/compare/2.0.1...2.0.2) - 2022-08-04
 
-* Removed redundant dependencies ([911924a](https://github.com/roadiz/skeleton/commit/911924a3a3e1646a7f7795ea5c1270625cf4424f))
+### Bug Fixes
 
-## 2.0.3 (2022-09-07)
+- **(PHP)** Removed PHP warnings on prod env - ([879e23b](https://github.com/roadiz/skeleton/commit/879e23b29ef341fe7d9c8c7ca8e02b659fb0b43e)) - Ambroise Maupate
+- Removed useless API collection operations - ([85d58e9](https://github.com/roadiz/skeleton/commit/85d58e9d8b41be02609d7a8185cd7b67561a1aec)) - Ambroise Maupate
+- Useless php-soap requirement - ([fcab0eb](https://github.com/roadiz/skeleton/commit/fcab0eb8ced1bd338306f3a098e0bac537157f2a)) - Ambroise Maupate
 
-### Features
+### CI/CD
 
-* Added `APP_FFMPEG_PATH` DotEnv and ffmpeg binary to Docker images ([4c0f063](https://github.com/roadiz/skeleton/commit/4c0f063df497553d9fcd411bd47167c05b1beedb))
-* Use Imagick as default image driver to support AVIF/HEIC files formats ([20ee3f6](https://github.com/roadiz/skeleton/commit/20ee3f643dc25deff3632385bbfe3e94f7faed28))
-
-## 2.0.2 (2022-08-04)
+- Docker and CI configuration fixes - ([675eb1e](https://github.com/roadiz/skeleton/commit/675eb1edb1eed607611da82d45a9171d6b064278)) - Ambroise Maupate
+- Docker and CI configuration fixes - ([4635ae8](https://github.com/roadiz/skeleton/commit/4635ae8235e29dc778d994b8e9e0f877bf3c0b89)) - Ambroise Maupate
 
 ### Features
 
-* Added /api/common_content endpoint example ([f909aa7](https://github.com/roadiz/skeleton/commit/f909aa78446b56803b2f6ee888d124c6dac2837c))
-* Added realms api resource configuration ([9f2d035](https://github.com/roadiz/skeleton/commit/9f2d0350cf9072f9e1019eef0a70fdc9723feaf0))
-* Additional CORS allowed headers ([6501e2c](https://github.com/roadiz/skeleton/commit/6501e2c5dc62f849ea5b692917900871f01dca17))
-* **Performances:** Added php.ini preload configuration ([0e291fd](https://github.com/roadiz/skeleton/commit/0e291fdd038fe1a5c393c9b9e2cfadbc8a7c3679))
+- **(Performances)** Added php.ini preload configuration - ([0e291fd](https://github.com/roadiz/skeleton/commit/0e291fdd038fe1a5c393c9b9e2cfadbc8a7c3679)) - Ambroise Maupate
+- Added /api/common_content endpoint example - ([f909aa7](https://github.com/roadiz/skeleton/commit/f909aa78446b56803b2f6ee888d124c6dac2837c)) - Ambroise Maupate
+- Added realms api resource configuration - ([9f2d035](https://github.com/roadiz/skeleton/commit/9f2d0350cf9072f9e1019eef0a70fdc9723feaf0)) - Ambroise Maupate
+- Additional CORS allowed headers - ([6501e2c](https://github.com/roadiz/skeleton/commit/6501e2c5dc62f849ea5b692917900871f01dca17)) - Ambroise Maupate
+
+## [2.0.1](https://github.com/roadiz/skeleton/compare/2.0.0...2.0.1) - 2022-07-04
 
 ### Bug Fixes
 
-* **PHP:** Removed PHP warnings on prod env ([879e23b](https://github.com/roadiz/skeleton/commit/879e23b29ef341fe7d9c8c7ca8e02b659fb0b43e))
-* Removed useless API collection operations ([85d58e9](https://github.com/roadiz/skeleton/commit/85d58e9d8b41be02609d7a8185cd7b67561a1aec))
-* Useless php-soap requirement ([fcab0eb](https://github.com/roadiz/skeleton/commit/fcab0eb8ced1bd338306f3a098e0bac537157f2a))
+- Non existent Varnish docker image tag - ([5217af9](https://github.com/roadiz/skeleton/commit/5217af94c5f16f25db0d3b8fcc333edfd8cdb72f)) - Ambroise Maupate
 
-## 2.0.1 (2022-07-04)
+## [2.0.0] - 2022-07-04
 
 ### Bug Fixes
 
-* Non-existent Varnish docker image tag ([5217af9](https://github.com/roadiz/skeleton/commit/5217af94c5f16f25db0d3b8fcc333edfd8cdb72f))
+- dump only real env vars - ([80c1d6a](https://github.com/roadiz/skeleton/commit/80c1d6a97cafd734031719d3653400b661d90f39)) - Ambroise Maupate
+- refactored config - ([b9cd98d](https://github.com/roadiz/skeleton/commit/b9cd98d9913383a1eb40ed3fcc55fb3c6f56b780)) - Ambroise Maupate
+- Production environment - ([a6d11d6](https://github.com/roadiz/skeleton/commit/a6d11d6819f23d31d4cafadcedc4518ff89e2ea0)) - Ambroise Maupate
+- trusted proxies - ([8395028](https://github.com/roadiz/skeleton/commit/83950281ba7d69d59238515505f1b8b8af85c4d9)) - Ambroise Maupate
+- do not add volume on var/cache - ([65b979a](https://github.com/roadiz/skeleton/commit/65b979a553ea8c4978a1da9d520ab5397c59d495)) - Ambroise Maupate
+- Use rezozero Liform fork - ([1caa915](https://github.com/roadiz/skeleton/commit/1caa915f712ea03755528864d41f8f32b4184722)) - Ambroise Maupate
+- Increase nginx buffer size for large collection of Cache-Tags - ([efa3db4](https://github.com/roadiz/skeleton/commit/efa3db447b863cd1c4648ea883e8df91f4ccbf80)) - Ambroise Maupate
+
+### Features
 
+- Better makefile using docker-compose - ([af83464](https://github.com/roadiz/skeleton/commit/af8346479767365350b10e7c4c662b6bdbe999e4)) - Ambroise Maupate
+- Env var HTTP_CACHE_SHARED_MAX_AGE - ([f416070](https://github.com/roadiz/skeleton/commit/f41607042bb229abb54b83b60a07b24feff037ca)) - Ambroise Maupate
+- Use OpenIdAuthenticator for backoffice access - ([3b1ccc5](https://github.com/roadiz/skeleton/commit/3b1ccc5ae37d99a220b7285ab45d9236821539eb)) - Ambroise Maupate
+- Enable Scienta\DoctrineJsonFunctions JSON_CONTAINS - ([982c914](https://github.com/roadiz/skeleton/commit/982c914055db497c7e32584587f7ed8a4d6dc53b)) - Ambroise Maupate
+- Added contact form controller and rate-limiter - ([90ee246](https://github.com/roadiz/skeleton/commit/90ee24628e867b14f52530a55d8a568a9e09202d)) - Ambroise Maupate
+- Separate WebResponse Api Resource - ([c841437](https://github.com/roadiz/skeleton/commit/c841437a7227061f2d846b6807bfeff1e92994dc)) - Ambroise Maupate
+- new APP_USE_ACCEPT_LANGUAGE_HEADER dotenv - ([5147c36](https://github.com/roadiz/skeleton/commit/5147c3697f5f2c691b99ba9d917252045eb64752)) - Ambroise Maupate
+- Use php81 - ([cb4ed6a](https://github.com/roadiz/skeleton/commit/cb4ed6a8ab2f0c46c9f1d6678540e20db0813d5f)) - Ambroise Maupate
+- Added dotenv vars and healthcheck entry-point - ([f34f106](https://github.com/roadiz/skeleton/commit/f34f1061bf9a238fc11dec34badc772c3f9d4c36)) - Ambroise Maupate
+- New document section menu - ([b74997a](https://github.com/roadiz/skeleton/commit/b74997a003340d3627329c7c2ee8c49fc91c3d67)) - Ambroise Maupate
+- Use built-in Symfony login throttling - ([97bca11](https://github.com/roadiz/skeleton/commit/97bca110744ead44aa03340c618c2e5fbd7f3ace)) - Ambroise Maupate
+- Update crontab example with custom-form-answer prune command - ([4612eae](https://github.com/roadiz/skeleton/commit/4612eae801480e9d46f8c9cdf7c3f01e13e9290e)) - Ambroise Maupate
+- Use custom Solr image to allow ASCII folding - ([d7633fe](https://github.com/roadiz/skeleton/commit/d7633fe774b61edfc3d9a9a4950d0b47da2ef4b1)) - Ambroise Maupate
+- Moved open_id configuration from core to rozier bundle - ([8b534c1](https://github.com/roadiz/skeleton/commit/8b534c15d01bbe59cac79099005ac1acc945cae9)) - Ambroise Maupate
+- Fixed roadiz packages to 2.0.0 - ([93fbd0b](https://github.com/roadiz/skeleton/commit/93fbd0b4cc75e74eec979b955912233d4eceb794)) - Ambroise Maupate
+- Fixed dependencies, upgraded configuration files, added Contactform definition action - ([1b4c2e1](https://github.com/roadiz/skeleton/commit/1b4c2e1cf8ebfec239d42f35f441bbfd00b06b6a)) - Ambroise Maupate
+
+### Refactor
+
+- Removed VCS repositories for liform - ([0596a11](https://github.com/roadiz/skeleton/commit/0596a119a358fd2439c7f2fb884aa4b968406c00)) - Ambroise Maupate
+
+<!-- generated by git-cliff -->
diff --git a/Makefile b/Makefile
index 6bfeaa0..9ff1f30 100644
--- a/Makefile
+++ b/Makefile
@@ -18,3 +18,9 @@ install:
 	make migrate;
 	docker compose exec -u www-data app bin/console install;
 	make cache;
+
+changelog:
+	git-cliff -o CHANGELOG.md
+
+bump:
+	git-cliff --bump -o CHANGELOG.md
diff --git a/README.md b/README.md
index e4a29c1..cec6a9d 100644
--- a/README.md
+++ b/README.md
@@ -221,11 +221,28 @@ a local environment.
 **We do not recommend this workflow on complex applications** in which you will need to control and version your node-types
 schema. This is only recommended for small and basic websites.
 
-### Generate a CHANGELOG file
+### Conventional commits
 
-You can use `git-cliff` to generate a `CHANGELOG.md` file from your Git tags and commits.
+This project uses conventional commits to automate the release process and 
+*changelog* generation with [git-cliff](https://github.com/orhun/git-cliff).
 A `cliff.toml` configuration file is already provided in this skeleton.
 
+#### Generate a CHANGELOG file
+```bash
+git-cliff -o CHANGELOG.md
+```
+
+#### Before releasing
+
+- With a known tag
+    ```bash
+    git-cliff -o CHANGELOG.md --tag 1.0.0
+    ```
+- Without knowing tag, let `git-cliff` find the right version
+    ```bash
+    git-cliff -o CHANGELOG.md --bump
+    ```
+
 ### Credits
 
 This skeleton uses https://github.com/vishnubob/wait-for-it script to wait for MySQL readiness before launching app entrypoint.
diff --git a/cliff.toml b/cliff.toml
index 332e031..7322b62 100644
--- a/cliff.toml
+++ b/cliff.toml
@@ -65,7 +65,8 @@ footer = """
 """
 # postprocessors
 postprocessors = [
-  { pattern = '<REPO>', replace = "https://gitlab.com/example-project/example-project/-" },
+  { pattern = '<REPO>', replace = "https://github.com/roadiz/skeleton" },
+#  { pattern = '<REPO>', replace = "https://gitlab.com/example-project/example-project/-" },
 ]
 [git]
 # parse the commits based on https://www.conventionalcommits.org
@@ -101,7 +102,7 @@ protect_breaking_commits = false
 # filter out the commits that are not matched by commit parsers
 filter_commits = false
 # regex for matching git tags
-tag_pattern = "v[0-9].*"
+tag_pattern = "v?[0-9].*"
 
 # regex for skipping tags
 skip_tags = "v0.1.0-beta.1"

From db460658f04c089462cabe699757891c0addf69e Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 14 Feb 2024 16:40:43 +0100
Subject: [PATCH 12/38] chore: Removed roadiz crypto. Use symfony:secrets
 instead

---
 config/packages/roadiz_core.yaml | 2 --
 var/secret/.gitkeep              | 0
 2 files changed, 2 deletions(-)
 delete mode 100644 var/secret/.gitkeep

diff --git a/config/packages/roadiz_core.yaml b/config/packages/roadiz_core.yaml
index a735005..229263c 100644
--- a/config/packages/roadiz_core.yaml
+++ b/config/packages/roadiz_core.yaml
@@ -11,8 +11,6 @@ roadiz_core:
     # Be careful if you are using a reverse-proxy cache, YOU MUST vary on Accept-Language header and normalize it.
     # @see https://varnish-cache.org/docs/6.3/users-guide/increasing-your-hitrate.html#http-vary
     useAcceptLanguageHeader: '%env(bool:APP_USE_ACCEPT_LANGUAGE_HEADER)%'
-    security:
-        private_key_name: default
     medias:
         unsplash_client_id: '%env(string:APP_UNSPLASH_CLIENT_ID)%'
         soundcloud_client_id: '%env(string:APP_SOUNDCLOUD_CLIENT_ID)%'
diff --git a/var/secret/.gitkeep b/var/secret/.gitkeep
deleted file mode 100644
index e69de29..0000000

From 164991b415a2cfc33546ac3ca3c248fe382e1e0c Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 27 Feb 2024 11:39:05 +0100
Subject: [PATCH 13/38] chore: Added SWR

---
 config/packages/api_platform.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml
index 13f036b..752ed97 100644
--- a/config/packages/api_platform.yaml
+++ b/config/packages/api_platform.yaml
@@ -1,3 +1,8 @@
+parameters:
+    env(HTTP_CACHE_STALE_WHILE_REVALIDATE): 3600
+    env(HTTP_CACHE_MAX_AGE): 60
+    env(HTTP_CACHE_SHARED_MAX_AGE): 600
+
 api_platform:
     patch_formats:
         json: ['application/merge-patch+json']
@@ -32,6 +37,7 @@ api_platform:
             max_age: '%env(int:HTTP_CACHE_MAX_AGE)%'
             # Default value for the response shared (proxy) max age.
             shared_max_age: '%env(int:HTTP_CACHE_SHARED_MAX_AGE)%'
+            stale_while_revalidate: '%env(int:HTTP_CACHE_STALE_WHILE_REVALIDATE)%'
             # Default values of the "Vary" HTTP header.
             vary: ['Accept', 'Authorization', 'Origin', 'Accept-Encoding', 'Content-Type']
     collection:

From 44553441627473572043d78e12a24f2fc264018f Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 28 Feb 2024 01:50:40 +0100
Subject: [PATCH 14/38] feat: Upgrade to ApiPlatform 3.2

---
 .env                              |  4 ++
 composer_dev.json.dist            | 61 ++++++++++++++++---------------
 config/bundles.php                |  2 +-
 config/packages/api_platform.yaml |  8 +++-
 config/routes/security.yaml       |  3 ++
 5 files changed, 47 insertions(+), 31 deletions(-)
 create mode 100644 config/routes/security.yaml

diff --git a/.env b/.env
index 743495e..325aa2f 100644
--- a/.env
+++ b/.env
@@ -169,3 +169,7 @@ DATABASE_URL="mysql://roadiz:roadiz@db:3306/roadiz?serverVersion=8&charset=utf8m
 #RESTIC_PASSWORD=
 RESTIC_REPOSITORY=
 MYSQL_DUMP_FILENAME=api_database_dump.sql
+
+###> sentry/sentry-symfony ###
+SENTRY_DSN=
+###< sentry/sentry-symfony ###
diff --git a/composer_dev.json.dist b/composer_dev.json.dist
index 66e03fd..2dce9c0 100644
--- a/composer_dev.json.dist
+++ b/composer_dev.json.dist
@@ -3,44 +3,32 @@
     "type": "project",
     "license": "mit",
     "prefer-stable": true,
+    "minimum-stability": "dev",
     "require": {
-        "php": ">=8.0",
+        "php": ">=8.2",
         "ext-ctype": "*",
         "ext-iconv": "*",
         "ext-json": "*",
-        "nelmio/cors-bundle": "^2.2",
-        "roadiz/cms-pack": "*",
-        "sentry/sentry-symfony": "^4.2",
-        "symfony/flex": "*"
+        "nelmio/cors-bundle": "^2.4",
+        "roadiz/cms-pack": "dev-develop",
+        "sentry/sentry-symfony": "^4.13",
+        "symfony/flex": "*",
+        "symfony/requirements-checker": "^2.0"
     },
     "require-dev": {
-        "blackfire/php-sdk": "^1.28",
-        "phpstan/phpstan": "^1.5.3",
+        "phpstan/phpstan": "^1.10",
         "phpstan/phpstan-doctrine": "^1.3.1",
-        "phpstan/phpstan-symfony": "^1.1.8",
+        "phpstan/phpstan-symfony": "^1.3.7",
         "phpunit/phpunit": "^9.5",
         "rezozero/intervention-request-bundle": "~3.0.0",
-        "roadiz/compat-bundle": "2.2.x-dev",
-        "roadiz/core-bundle": "2.2.x-dev",
-        "roadiz/documents": "2.2.x-dev",
-        "roadiz/entity-generator": "2.2.x-dev",
-        "roadiz/models": "2.2.x-dev",
-        "roadiz/rozier": "2.2.x-dev",
-        "roadiz/openid": "2.2.x-dev",
-        "roadiz/doc-generator": "2.2.x-dev",
-        "roadiz/dts-generator": "2.2.x-dev",
-        "roadiz/jwt": "2.2.x-dev",
-        "roadiz/random": "2.2.x-dev",
-        "roadiz/markdown": "2.2.x-dev",
-        "roadiz/rozier-bundle": "2.2.x-dev",
         "squizlabs/php_codesniffer": "^3.6",
-        "symfony/browser-kit": "5.4.*",
-        "symfony/css-selector": "5.4.*",
-        "symfony/debug-bundle": "5.4.*",
+        "symfony/browser-kit": "6.4.*",
+        "symfony/css-selector": "6.4.*",
+        "symfony/debug-bundle": "6.4.*",
         "symfony/maker-bundle": "^1.0",
-        "symfony/phpunit-bridge": "5.4.*",
-        "symfony/stopwatch": "5.4.*",
-        "symfony/web-profiler-bundle": "5.4.*"
+        "symfony/phpunit-bridge": "6.4.*",
+        "symfony/stopwatch": "6.4.*",
+        "symfony/web-profiler-bundle": "6.4.*"
     },
     "config": {
         "optimize-autoloader": true,
@@ -71,14 +59,24 @@
         "symfony/polyfill-php72": "*"
     },
     "scripts": {
+        "post-root-package-install": [
+            "mkdir -p var/cache var/files var/log var/export var/secret"
+        ],
         "auto-scripts": {
             "cache:clear": "symfony-cmd",
             "assets:install %PUBLIC_DIR%": "symfony-cmd",
-            "themes:assets:install Rozier": "symfony-cmd"
+            "themes:assets:install Rozier": "symfony-cmd",
+            "requirements-checker": "script"
         },
         "post-install-cmd": [
             "@auto-scripts"
         ],
+        "post-create-project-cmd": [
+            "bin/console secrets:generate-keys",
+            "bin/console secrets:set JWT_PASSPHRASE --random",
+            "bin/console secrets:set APP_SECRET --random",
+            "bin/console lexik:jwt:generate-keypair"
+        ],
         "post-update-cmd": [
             "@auto-scripts"
         ]
@@ -86,10 +84,15 @@
     "conflict": {
         "symfony/symfony": "*"
     },
+    "suggest": {
+        "roadiz/two-factor-bundle": "Provides a two-factor authentication system for Roadiz CMS",
+        "roadiz/user-bundle": "Public user management bundle for Roadiz CMS",
+        "roadiz/font-bundle": "Manage and expose web fonts with Roadiz CMS"
+    },
     "extra": {
         "symfony": {
             "allow-contrib": false,
-            "require": "5.4.*",
+            "require": "6.4.*",
             "docker": false
         }
     }
diff --git a/config/bundles.php b/config/bundles.php
index e0b7278..421156e 100644
--- a/config/bundles.php
+++ b/config/bundles.php
@@ -18,7 +18,7 @@
     RZ\InterventionRequestBundle\RZInterventionRequestBundle::class => ['all' => true],
     JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
     RZ\Roadiz\CoreBundle\RoadizCoreBundle::class => ['all' => true],
-    ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
+    ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
     RZ\Roadiz\CompatBundle\RoadizCompatBundle::class => ['all' => true],
     RZ\Roadiz\RozierBundle\RoadizRozierBundle::class => ['all' => true],
     Sentry\SentryBundle\SentryBundle::class => ['all' => true],
diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml
index 752ed97..39e69a7 100644
--- a/config/packages/api_platform.yaml
+++ b/config/packages/api_platform.yaml
@@ -7,7 +7,6 @@ api_platform:
     patch_formats:
         json: ['application/merge-patch+json']
     enable_swagger_ui: false
-    metadata_backward_compatibility_layer: false
     enable_re_doc: true
     graphql:
         graphiql:
@@ -26,6 +25,13 @@ api_platform:
             - '%kernel.project_dir%/vendor/rezozero/tree-walker/src'
             - '%kernel.project_dir%/config/api_resources'
     defaults:
+        stateless: true
+        extra_properties:
+            standard_put: true
+            rfc_7807_compliant_errors: false
+        enable_max_depth: true
+        normalization_context:
+            skip_null_values: true
         pagination_client_items_per_page: true
         pagination_items_per_page: 15
         pagination_maximum_items_per_page: 50
diff --git a/config/routes/security.yaml b/config/routes/security.yaml
new file mode 100644
index 0000000..f853be1
--- /dev/null
+++ b/config/routes/security.yaml
@@ -0,0 +1,3 @@
+_security_logout:
+    resource: security.route_loader.logout
+    type: service

From d51461e89a184ffbb885e4aa59ab2e9b1efef6e3 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 28 Feb 2024 15:35:22 +0100
Subject: [PATCH 15/38] refactor: Changed MenuLinkPathNormalizer.php method
 signature

---
 src/Controller/ContactFormController.php          | 15 ++++-----------
 .../Normalizer/MenuLinkPathNormalizer.php         |  2 +-
 2 files changed, 5 insertions(+), 12 deletions(-)

diff --git a/src/Controller/ContactFormController.php b/src/Controller/ContactFormController.php
index b31abb8..4e75ce8 100644
--- a/src/Controller/ContactFormController.php
+++ b/src/Controller/ContactFormController.php
@@ -13,20 +13,13 @@
 use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
 use Symfony\Component\RateLimiter\RateLimiterFactory;
 
-final class ContactFormController
+final readonly class ContactFormController
 {
-    private ContactFormManager $contactFormManager;
-    private RateLimiterFactory $contactFormLimiter;
-    private LiformInterface $liform;
-
     public function __construct(
-        ContactFormManager $contactFormManager,
-        RateLimiterFactory $contactFormLimiter,
-        LiformInterface $liform
+        private ContactFormManager $contactFormManager,
+        private RateLimiterFactory $contactFormLimiter,
+        private LiformInterface $liform
     ) {
-        $this->contactFormManager = $contactFormManager;
-        $this->contactFormLimiter = $contactFormLimiter;
-        $this->liform = $liform;
     }
 
     public function definitionAction(Request $request): JsonResponse
diff --git a/src/Serializer/Normalizer/MenuLinkPathNormalizer.php b/src/Serializer/Normalizer/MenuLinkPathNormalizer.php
index 6f52118..8c40f7e 100644
--- a/src/Serializer/Normalizer/MenuLinkPathNormalizer.php
+++ b/src/Serializer/Normalizer/MenuLinkPathNormalizer.php
@@ -17,7 +17,7 @@ final class MenuLinkPathNormalizer extends AbstractPathNormalizer
      * @return array|\ArrayObject|bool|float|int|mixed|string|null
      * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
      */
-    public function normalize($object, $format = null, array $context = [])
+    public function normalize(mixed $object, ?string $format = null, array $context = []): mixed
     {
         $data = $this->decorated->normalize($object, $format, $context);
         if (($object instanceof NSMenuLink) && is_array($data)) {

From 997bd4e172e96ac13504173213e80b9c0a909823 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 4 Mar 2024 13:54:20 +0100
Subject: [PATCH 16/38] feat: Added simple `HEALTHCHECK` command for docker
 containers

---
 Dockerfile                       | 2 ++
 docker/php-fpm-alpine/Dockerfile | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/Dockerfile b/Dockerfile
index 809ab38..cc6ec4b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,6 +8,8 @@ ENV APP_FFMPEG_PATH=/usr/bin/ffmpeg
 ENV MYSQL_HOST=db
 ENV MYSQL_PORT=3306
 
+HEALTHCHECK --start-period=1m --interval=1m --timeout=6s CMD bin/console -q
+
 # Added ffmpeg to extract video files thumbnails
 RUN apk add --no-cache ffmpeg
 
diff --git a/docker/php-fpm-alpine/Dockerfile b/docker/php-fpm-alpine/Dockerfile
index 3cd7de9..417263c 100755
--- a/docker/php-fpm-alpine/Dockerfile
+++ b/docker/php-fpm-alpine/Dockerfile
@@ -9,6 +9,8 @@ ENV APP_FFMPEG_PATH=/usr/bin/ffmpeg
 ENV MYSQL_HOST=db
 ENV MYSQL_PORT=3306
 
+HEALTHCHECK --start-period=1m --interval=1m --timeout=6s CMD bin/console -q
+
 RUN apk add --no-cache shadow make git ffmpeg \
     && usermod -u ${USER_UID} www-data \
     && groupmod -g ${USER_UID} www-data \

From 59fcb39f85e39e10eb2653ee027c194117801cef Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 5 Mar 2024 17:02:12 +0100
Subject: [PATCH 17/38] feat: Added *LiipMonitorBundle* for health-checking API
 docker container

---
 Dockerfile                       |  2 ++
 composer.json                    |  1 +
 composer.json.dist               |  1 +
 config/bundles.php               |  1 +
 config/packages/monitor.yaml     | 30 ++++++++++++++++++++++++++++++
 docker/php-fpm-alpine/Dockerfile |  2 ++
 6 files changed, 37 insertions(+)
 create mode 100644 config/packages/monitor.yaml

diff --git a/Dockerfile b/Dockerfile
index 809ab38..44d9596 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,6 +8,8 @@ ENV APP_FFMPEG_PATH=/usr/bin/ffmpeg
 ENV MYSQL_HOST=db
 ENV MYSQL_PORT=3306
 
+HEALTHCHECK --start-period=30s --interval=1m --timeout=6s CMD bin/console monitor:health -q
+
 # Added ffmpeg to extract video files thumbnails
 RUN apk add --no-cache ffmpeg
 
diff --git a/composer.json b/composer.json
index 2dce9c0..778edd5 100644
--- a/composer.json
+++ b/composer.json
@@ -9,6 +9,7 @@
         "ext-ctype": "*",
         "ext-iconv": "*",
         "ext-json": "*",
+        "liip/monitor-bundle": "^2.22",
         "nelmio/cors-bundle": "^2.4",
         "roadiz/cms-pack": "dev-develop",
         "sentry/sentry-symfony": "^4.13",
diff --git a/composer.json.dist b/composer.json.dist
index 2dce9c0..778edd5 100644
--- a/composer.json.dist
+++ b/composer.json.dist
@@ -9,6 +9,7 @@
         "ext-ctype": "*",
         "ext-iconv": "*",
         "ext-json": "*",
+        "liip/monitor-bundle": "^2.22",
         "nelmio/cors-bundle": "^2.4",
         "roadiz/cms-pack": "dev-develop",
         "sentry/sentry-symfony": "^4.13",
diff --git a/config/bundles.php b/config/bundles.php
index 421156e..cc0c6e1 100644
--- a/config/bundles.php
+++ b/config/bundles.php
@@ -26,4 +26,5 @@
     Limenius\LiformBundle\LimeniusLiformBundle::class => ['all' => true],
     Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
     Rollerworks\Bundle\PasswordCommonListBundle\RollerworksPasswordCommonListBundle::class => ['all' => true],
+    Liip\MonitorBundle\LiipMonitorBundle::class => ['all' => true],
 ];
diff --git a/config/packages/monitor.yaml b/config/packages/monitor.yaml
new file mode 100644
index 0000000..24a7167
--- /dev/null
+++ b/config/packages/monitor.yaml
@@ -0,0 +1,30 @@
+liip_monitor:
+    # enabling the controller requires that `assets` are enabled in the framework bundle
+    enable_controller: false
+    checks:
+        groups:
+            default:
+                # Checks to see if the disk usage is below warning/critical percent thresholds
+                disk_usage:
+                    warning:              70
+                    critical:             90
+                    path:                 '%kernel.cache_dir%'
+
+                # Connection name or an array of connection names
+                doctrine_dbal:       [default]
+
+                # Checks to see if migrations from specified configuration file are applied
+                doctrine_migrations:
+                    migrations:
+                        connection: default
+
+                # Validate that a Redis service is running
+#                redis:
+#                    cache_service:
+#                        dsn: '%env(string:REDIS_DSN)%'
+
+                # Validate that a messenger transport does not contain more than warning/critical messages
+                # Transport must implement MessageCountAwareInterface
+                messenger_transports:
+                    async:
+                        critical_threshold:   10   # required
diff --git a/docker/php-fpm-alpine/Dockerfile b/docker/php-fpm-alpine/Dockerfile
index 3cd7de9..bb2d7ba 100755
--- a/docker/php-fpm-alpine/Dockerfile
+++ b/docker/php-fpm-alpine/Dockerfile
@@ -9,6 +9,8 @@ ENV APP_FFMPEG_PATH=/usr/bin/ffmpeg
 ENV MYSQL_HOST=db
 ENV MYSQL_PORT=3306
 
+HEALTHCHECK --start-period=30s --interval=1m --timeout=6s CMD bin/console monitor:health -q
+
 RUN apk add --no-cache shadow make git ffmpeg \
     && usermod -u ${USER_UID} www-data \
     && groupmod -g ${USER_UID} www-data \

From aefde96f3660dc6d54c16a4e0073a97c087c4bdf Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Thu, 7 Mar 2024 13:41:42 +0100
Subject: [PATCH 18/38] fix: Fixed docker compose specification with `extends`
 and `depends_on`

---
 docker-compose.prod.yml | 16 +++-------------
 docker-compose.yml      |  8 +++-----
 2 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 123d547..d190548 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -104,7 +104,7 @@ services:
             - "com.centurylinklabs.watchtower.enable=true"
             - "com.centurylinklabs.watchtower.depends-on=/skeleton-app-1"
 
-    app:
+    app: &app_template
         image: my-registry/roadiz_skeleton:latest
         restart: always
         depends_on:
@@ -145,26 +145,16 @@ services:
             - "com.centurylinklabs.watchtower.depends-on=/skeleton-redis-1"
 
     worker:
-        extends:
-            service: app
+        <<: *app_template
         deploy:
             # Do not use more than 1 replica if you're using Varnish and need to purge/ban cache
             # from your workers. Varnish ACL hostnames won't be resolved correctly.
             replicas: 1
         entrypoint: [ "php", "/var/www/html/bin/console", "messenger:consume", "async", "--time-limit=1800" ]
-        restart: always
-        labels:
-            - "com.centurylinklabs.watchtower.enable=true"
-            - "com.centurylinklabs.watchtower.depends-on=/skeleton-redis-1"
 
     cron:
-        extends:
-            service: app
+        <<: *app_template
         entrypoint: 'docker-cron-entrypoint'
-        restart: always
-        labels:
-            - "com.centurylinklabs.watchtower.enable=true"
-            - "com.centurylinklabs.watchtower.depends-on=/skeleton-redis-1"
 
     #solr:
     #    image: my-registry/roadiz_skeleton/solr:latest
diff --git a/docker-compose.yml b/docker-compose.yml
index 55fe755..8700a3b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -49,7 +49,7 @@ services:
             - "traefik.http.routers.${APP_NAMESPACE}_pma_secure.rule=Host(${HOSTNAME_PMA})"
             - "traefik.http.routers.${APP_NAMESPACE}_pma_secure.service=${APP_NAMESPACE}_pma"
 
-    app:
+    app: &app_template
         # Need to pass all vars to docker env for Crontab and supervisor scripts
         #env_file: "./.env.local"
         build:
@@ -113,8 +113,7 @@ services:
 #            - "traefik.http.routers.${APP_NAMESPACE}_secure.service=${APP_NAMESPACE}"
 
     worker:
-        extends:
-            service: app
+        <<: *app_template
         deploy:
             # Do not use more than 1 replica if you're using Varnish and need to purge/ban cache
             # from your workers. Varnish ACL hostnames won't be resolved correctly.
@@ -123,8 +122,7 @@ services:
         restart: unless-stopped
 
     cron:
-        extends:
-            service: app
+        <<: *app_template
         # https://github.com/dubiousjim/dcron/issues/13#issuecomment-1406937781
         init: true
         entrypoint: [ "crond", "-f", "-L", "15" ]

From 095cccca56e105bdbf40339391776e63e4cd8391 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Thu, 7 Mar 2024 13:57:00 +0100
Subject: [PATCH 19/38] fix: Fixed monolog log level on prod

---
 config/packages/monolog.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml
index 679d91c..c8a99fb 100644
--- a/config/packages/monolog.yaml
+++ b/config/packages/monolog.yaml
@@ -55,7 +55,7 @@ when@prod:
             nested:
                 type: stream
                 path: php://stderr
-                level: debug
+                level: info
                 formatter: monolog.formatter.json
     #        sentry:
     #            type: sentry

From 970ba381ea4df3179decd74b1ccfb42c4790d557 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 8 Mar 2024 22:03:26 +0100
Subject: [PATCH 20/38] fix: Attribute class
 ApiPlatform\Core\Annotation\ApiProperty does not exist.

---
 src/Api/Model/CommonContent.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Api/Model/CommonContent.php b/src/Api/Model/CommonContent.php
index a668b01..6087c7d 100644
--- a/src/Api/Model/CommonContent.php
+++ b/src/Api/Model/CommonContent.php
@@ -4,7 +4,7 @@
 
 namespace App\Api\Model;
 
-use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Metadata\ApiProperty;
 use RZ\Roadiz\CoreBundle\Api\Model\NodesSourcesHeadInterface;
 use RZ\Roadiz\CoreBundle\Entity\NodesSources;
 use Symfony\Component\Serializer\Annotation\Groups;

From 3341faa38d6dae06332e9710bd1943af666c009f Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 8 Mar 2024 23:19:09 +0100
Subject: [PATCH 21/38] ci: Removed php 8.1 from version matrix

---
 .github/workflows/run-test.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/run-test.yml b/.github/workflows/run-test.yml
index 189e3a5..5b0323a 100644
--- a/.github/workflows/run-test.yml
+++ b/.github/workflows/run-test.yml
@@ -19,7 +19,7 @@ jobs:
         runs-on: ubuntu-latest
         strategy:
             matrix:
-                php-version: ['8.1', '8.2', '8.3']
+                php-version: ['8.2', '8.3']
         steps:
             - uses: shivammathur/setup-php@v2
               with:

From b50e50cea7768b84f92c72d1a0deae669554e92b Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 15 Mar 2024 13:49:30 +0100
Subject: [PATCH 22/38] chore: Config files improvements

---
 .env                              |  1 +
 cliff.toml                        |  8 ++------
 config/api_resources/document.yml | 10 +++++-----
 config/api_resources/realm.yml    | 10 +++++-----
 config/packages/api_platform.yaml |  2 +-
 docker/varnish/default.vcl        | 30 ++++++++++++++++++++++++++++--
 6 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/.env b/.env
index 325aa2f..1a11a4e 100644
--- a/.env
+++ b/.env
@@ -38,6 +38,7 @@ VARNISH_URL=http://varnish
 VARNISH_SIZE=256M
 HTTP_CACHE_MAX_AGE=60
 HTTP_CACHE_SHARED_MAX_AGE=600
+HTTP_CACHE_STALE_WHILE_REVALIDATE=60
 
 # To use with Traefik and your local dev environment
 # On linux you can use dnsmasq to redirect all DNS for *.test TLD to your machine.
diff --git a/cliff.toml b/cliff.toml
index 7322b62..fc12eef 100644
--- a/cliff.toml
+++ b/cliff.toml
@@ -89,10 +89,6 @@ commit_parsers = [
   { message = "^style", group = "Styling" },
   { message = "^test", group = "Testing" },
   { message = "^chore", skip = true },
-  { message = "^chore\\(release\\): prepare for", skip = true },
-  { message = "^chore\\(deps\\)", skip = true },
-  { message = "^chore\\(pr\\)", skip = true },
-  { message = "^chore\\(pull\\)", skip = true },
   { message = "^ci", group = "CI/CD" },
   { body = ".*security", group = "Security" },
   { message = "^revert", group = "Revert" },
@@ -100,7 +96,7 @@ commit_parsers = [
 # protect breaking changes from being skipped due to matching a skipping commit_parser
 protect_breaking_commits = false
 # filter out the commits that are not matched by commit parsers
-filter_commits = false
+filter_commits = true
 # regex for matching git tags
 tag_pattern = "v?[0-9].*"
 
@@ -109,7 +105,7 @@ skip_tags = "v0.1.0-beta.1"
 # regex for ignoring tags
 ignore_tags = ""
 # sort the tags topologically
-topo_order = false
+topo_order = true
 # sort the commits inside sections by oldest/newest order
 sort_commits = "oldest"
 # limit the number of commits included in the changelog.
diff --git a/config/api_resources/document.yml b/config/api_resources/document.yml
index d875d9f..acb4a7d 100644
--- a/config/api_resources/document.yml
+++ b/config/api_resources/document.yml
@@ -1,11 +1,11 @@
 ---
 RZ\Roadiz\CoreBundle\Entity\Document:
     operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                groups: ["urls", "document_display", "document_folders", "document_folders_all", "document_display_sources"]
-                enable_max_depth: true
+#        ApiPlatform\Metadata\GetCollection:
+#            method: "GET"
+#            normalizationContext:
+#                groups: ["urls", "document_display", "document_folders", "document_folders_all", "document_display_sources"]
+#                enable_max_depth: true
 
         ApiPlatform\Metadata\Get:
             method: 'GET'
diff --git a/config/api_resources/realm.yml b/config/api_resources/realm.yml
index 50dbdd8..e2fc1dc 100644
--- a/config/api_resources/realm.yml
+++ b/config/api_resources/realm.yml
@@ -1,11 +1,11 @@
 ---
 RZ\Roadiz\CoreBundle\Entity\Realm:
     operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                groups: [ "realm" ]
-                enable_max_depth: true
+#        ApiPlatform\Metadata\GetCollection:
+#            method: "GET"
+#            normalizationContext:
+#                groups: [ "realm" ]
+#                enable_max_depth: true
 
         ApiPlatform\Metadata\Get:
             method: "GET"
diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml
index 39e69a7..186a06b 100644
--- a/config/packages/api_platform.yaml
+++ b/config/packages/api_platform.yaml
@@ -6,7 +6,7 @@ parameters:
 api_platform:
     patch_formats:
         json: ['application/merge-patch+json']
-    enable_swagger_ui: false
+    enable_swagger_ui: true
     enable_re_doc: true
     graphql:
         graphiql:
diff --git a/docker/varnish/default.vcl b/docker/varnish/default.vcl
index cc7dbcc..f8485ec 100644
--- a/docker/varnish/default.vcl
+++ b/docker/varnish/default.vcl
@@ -69,10 +69,36 @@ sub vcl_recv {
         }
     }
 
+    # Some generic cookie manipulation, useful for all templates that follow
     # Remove has_js and Cloudflare/Google Analytics __* cookies.
     set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
-    # Remove a ";" prefix, if present.
-    set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
+    # Remove Axeptio cookies.
+    set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(axeptio_[_a-z]+)=[^;]*", "");
+    # Remove the "has_js" cookie
+    set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
+
+    # Remove any Google Analytics based cookies
+    set req.http.Cookie = regsuball(req.http.Cookie, "__utm[^=]+=[^;]+(; )?", "");
+    set req.http.Cookie = regsuball(req.http.Cookie, "_ga[^=]*=[^;]+(; )?", "");
+    set req.http.Cookie = regsuball(req.http.Cookie, "_gcl_[^=]+=[^;]+(; )?", "");
+    set req.http.Cookie = regsuball(req.http.Cookie, "_gid=[^;]+(; )?", "");
+
+    # Remove DoubleClick offensive cookies
+    set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", "");
+
+    # Remove the Quant Capital cookies (added by some plugin, all __qca)
+    set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
+
+    # Remove the AddThis cookies
+    set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", "");
+
+    # Remove a ";" prefix in the cookie if present
+    set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
+
+    # Are there cookies left with only spaces or that are empty?
+    if (req.http.cookie ~ "^\s*$") {
+        unset req.http.cookie;
+    }
 
     # Happens before we check if we have this in cache already.
     #

From 3c1024b008491b1a86e0add6327b6b4a9a44698e Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 18 Mar 2024 12:12:47 +0100
Subject: [PATCH 23/38] fix: Do not migrate app on make install

---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 9ff1f30..94d7fc6 100644
--- a/Makefile
+++ b/Makefile
@@ -10,12 +10,15 @@ test:
 
 migrate:
 	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate
+	# Apply files changes and create new Doctrine migrations if necessary
 	docker compose exec -u www-data app php bin/console app:migrate
 	# Stop workers to force restart them (Supervisord)
 	docker compose exec -u www-data app php bin/console messenger:stop-workers
 
 install:
-	make migrate;
+	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate
+	# Do not perform files changes on the database
+	docker compose exec -u www-data app php bin/console app:install
 	docker compose exec -u www-data app bin/console install;
 	make cache;
 

From bc721ea2e3b5429f7a1f3697e07623614b3a6776 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 18 Mar 2024 12:29:47 +0100
Subject: [PATCH 24/38] doc: Improved README and added new Makefile recipe

---
 Makefile  |  6 ++++++
 README.md | 29 +++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/Makefile b/Makefile
index 94d7fc6..09f4fe7 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,12 @@ test:
 	docker compose exec -u www-data app php -d "memory_limit=-1" vendor/bin/phpcbf --report=full --report-file=./report.txt -p ./src
 	docker compose exec -u www-data app php -d "memory_limit=-1" vendor/bin/phpstan analyse -c phpstan.neon
 
+update:
+	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate -n
+	# Do not perform files changes just apply existing migrations and import data
+	docker compose exec -u www-data app php bin/console app:install -n
+	make cache;
+
 migrate:
 	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate
 	# Apply files changes and create new Doctrine migrations if necessary
diff --git a/README.md b/README.md
index cec6a9d..0df9026 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,35 @@ docker compose exec -u www-data app bin/console cache:clear
 docker compose exec -u www-data app bin/console users:create -m username@roadiz.io -b -s username
 ```
 
+### Manage Node-types
+
+Node-types can be managed through back-office interface or by editing JSON files in `src/Resources/node-types` directory.
+If you edit JSON files manually you need to synchronize your database with these files and generate Doctrine Migrations
+if this leads to database schema changes.
+
+#### Migrate node-types
+
+When you direct update the `node-types` JSON files, you need to add them into `src/Resources/config.yml` 
+and run the following command to update the database:
+
+```bash 
+make migrate
+```
+
+This command will **update PHP entities** and **create a Doctrine migration** file if necessary.
+
+#### Apply node-type migration
+
+When you pull the project and just want to sync your local node-types, you need to apply the migration:
+
+```bash 
+make update
+```
+
+This will **only load node-types** that are not already in the database. But it won't create any migration.
+This is the same script that is executed when you run `make install` and in your docker image entrypoint.
+
+
 ### Features
 
 - Configured to be used in headless mode with *API Platform*

From 5377feb1d7b37bd3ed8b28e98560195f55f24e5a Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 18 Mar 2024 23:25:06 +0100
Subject: [PATCH 25/38] feat: Upgraded example node-types entities

---
 composer_dev.json.dist                        |  1 +
 src/GeneratedEntity/NSMenu.php                |  6 +++---
 src/GeneratedEntity/NSMenuLink.php            | 19 +++++++++----------
 .../Repository/NSMenuLinkRepository.php       |  2 +-
 .../Repository/NSMenuRepository.php           |  2 +-
 src/Resources/node-types/Menu.json            |  2 +-
 src/Resources/node-types/MenuLink.json        |  3 +--
 7 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/composer_dev.json.dist b/composer_dev.json.dist
index 2dce9c0..778edd5 100644
--- a/composer_dev.json.dist
+++ b/composer_dev.json.dist
@@ -9,6 +9,7 @@
         "ext-ctype": "*",
         "ext-iconv": "*",
         "ext-json": "*",
+        "liip/monitor-bundle": "^2.22",
         "nelmio/cors-bundle": "^2.4",
         "roadiz/cms-pack": "dev-develop",
         "sentry/sentry-symfony": "^4.13",
diff --git a/src/GeneratedEntity/NSMenu.php b/src/GeneratedEntity/NSMenu.php
index 74631f4..7a930bf 100644
--- a/src/GeneratedEntity/NSMenu.php
+++ b/src/GeneratedEntity/NSMenu.php
@@ -13,9 +13,9 @@
 use Symfony\Component\Serializer\Annotation as SymfonySerializer;
 use Gedmo\Mapping\Annotation as Gedmo;
 use Doctrine\ORM\Mapping as ORM;
-use ApiPlatform\Core\Annotation\ApiFilter;
-use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter as OrmFilter;
-use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
+use ApiPlatform\Metadata\ApiFilter;
+use ApiPlatform\Doctrine\Orm\Filter as OrmFilter;
+use ApiPlatform\Serializer\Filter\PropertyFilter;
 
 /**
  * DO NOT EDIT
diff --git a/src/GeneratedEntity/NSMenuLink.php b/src/GeneratedEntity/NSMenuLink.php
index b2e6ef7..401c1a1 100644
--- a/src/GeneratedEntity/NSMenuLink.php
+++ b/src/GeneratedEntity/NSMenuLink.php
@@ -13,9 +13,9 @@
 use Symfony\Component\Serializer\Annotation as SymfonySerializer;
 use Gedmo\Mapping\Annotation as Gedmo;
 use Doctrine\ORM\Mapping as ORM;
-use ApiPlatform\Core\Annotation\ApiFilter;
-use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter as OrmFilter;
-use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
+use ApiPlatform\Metadata\ApiFilter;
+use ApiPlatform\Doctrine\Orm\Filter as OrmFilter;
+use ApiPlatform\Serializer\Filter\PropertyFilter;
 
 /**
  * DO NOT EDIT
@@ -35,6 +35,7 @@ class NSMenuLink extends \RZ\Roadiz\CoreBundle\Entity\NodesSources
     #[
         SymfonySerializer\SerializedName(serializedName: "linkExternalUrl"),
         SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
+        \ApiPlatform\Metadata\ApiProperty(description: "URL externe"),
         SymfonySerializer\MaxDepth(2),
         Gedmo\Versioned,
         ORM\Column(
@@ -76,6 +77,7 @@ public function setLinkExternalUrl(?string $linkExternalUrl): static
      * linkInternalReferenceSources NodesSources direct field buffer.
      * (Virtual field, this var is a buffer)
      *
+     * Node reference (internal link).
      * Default values: Page
      * @var \RZ\Roadiz\CoreBundle\Entity\NodesSources[]|null
      */
@@ -83,6 +85,7 @@ public function setLinkExternalUrl(?string $linkExternalUrl): static
         Serializer\Exclude,
         SymfonySerializer\SerializedName(serializedName: "linkInternalReference"),
         SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default", "nodes_sources_nodes"]),
+        \ApiPlatform\Metadata\ApiProperty(description: "Node reference (internal link)"),
         SymfonySerializer\MaxDepth(2)
     ]
     private ?array $linkInternalReferenceSources = null;
@@ -100,16 +103,12 @@ public function setLinkExternalUrl(?string $linkExternalUrl): static
     public function getLinkInternalReferenceSources(): array
     {
         if (null === $this->linkInternalReferenceSources) {
-            if (
-                null !== $this->objectManager &&
-                null !== $this->getNode() &&
-                null !== $this->getNode()->getNodeType()
-            ) {
+            if (null !== $this->objectManager) {
                 $this->linkInternalReferenceSources = $this->objectManager
                     ->getRepository(\RZ\Roadiz\CoreBundle\Entity\NodesSources::class)
-                    ->findByNodesSourcesAndFieldAndTranslation(
+                    ->findByNodesSourcesAndFieldNameAndTranslation(
                         $this,
-                        $this->getNode()->getNodeType()->getFieldByName("link_internal_reference")
+                        'link_internal_reference'
                     );
             } else {
                 $this->linkInternalReferenceSources = [];
diff --git a/src/GeneratedEntity/Repository/NSMenuLinkRepository.php b/src/GeneratedEntity/Repository/NSMenuLinkRepository.php
index cd5e30a..9a807eb 100644
--- a/src/GeneratedEntity/Repository/NSMenuLinkRepository.php
+++ b/src/GeneratedEntity/Repository/NSMenuLinkRepository.php
@@ -11,7 +11,7 @@
 use Doctrine\Persistence\ManagerRegistry;
 use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
 use RZ\Roadiz\CoreBundle\SearchEngine\NodeSourceSearchHandlerInterface;
-use Symfony\Component\Security\Core\Security;
+use Symfony\Bundle\SecurityBundle\Security;
 use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
 
 /**
diff --git a/src/GeneratedEntity/Repository/NSMenuRepository.php b/src/GeneratedEntity/Repository/NSMenuRepository.php
index 9bf05d7..cbcf390 100644
--- a/src/GeneratedEntity/Repository/NSMenuRepository.php
+++ b/src/GeneratedEntity/Repository/NSMenuRepository.php
@@ -11,7 +11,7 @@
 use Doctrine\Persistence\ManagerRegistry;
 use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
 use RZ\Roadiz\CoreBundle\SearchEngine\NodeSourceSearchHandlerInterface;
-use Symfony\Component\Security\Core\Security;
+use Symfony\Bundle\SecurityBundle\Security;
 use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
 
 /**
diff --git a/src/Resources/node-types/Menu.json b/src/Resources/node-types/Menu.json
index 9814a1d..7555549 100644
--- a/src/Resources/node-types/Menu.json
+++ b/src/Resources/node-types/Menu.json
@@ -4,6 +4,7 @@
     "display_name": "Menu",
     "visible": true,
     "publishable": false,
+    "attributable": false,
     "reachable": false,
     "hiding_nodes": false,
     "hiding_non_reachable_nodes": false,
@@ -15,7 +16,6 @@
             "default_values": "Page, Menu, MenuLink",
             "type": 16,
             "expanded": false,
-            "node_type_name": "Menu",
             "universal": false,
             "exclude_from_search": false,
             "excluded_from_serialization": false,
diff --git a/src/Resources/node-types/MenuLink.json b/src/Resources/node-types/MenuLink.json
index 61e39ab..25bbf3e 100644
--- a/src/Resources/node-types/MenuLink.json
+++ b/src/Resources/node-types/MenuLink.json
@@ -4,6 +4,7 @@
     "display_name": "Lien du menu",
     "visible": false,
     "publishable": false,
+    "attributable": false,
     "reachable": false,
     "hiding_nodes": false,
     "hiding_non_reachable_nodes": false,
@@ -14,7 +15,6 @@
             "label": "URL externe",
             "type": 0,
             "expanded": false,
-            "node_type_name": "MenuLink",
             "universal": false,
             "exclude_from_search": true,
             "excluded_from_serialization": false,
@@ -28,7 +28,6 @@
             "default_values": "Page",
             "type": 13,
             "expanded": false,
-            "node_type_name": "MenuLink",
             "universal": true,
             "exclude_from_search": false,
             "excluded_from_serialization": false,

From 0e5e3c9ae82630bb7ae209d913fbc0ac24de64b6 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 22 Mar 2024 17:28:33 +0100
Subject: [PATCH 26/38] ci: Added php-unit configuration for Gitlab CI

---
 .gitignore       |  2 +-
 .gitlab-ci.yml   | 12 +++++++++
 Makefile         |  1 +
 phpunit.xml.dist | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 phpunit.xml.dist

diff --git a/.gitignore b/.gitignore
index bfd6371..120123a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,12 +15,12 @@
 ###> symfony/phpunit-bridge ###
 .phpunit.result.cache
 /phpunit.xml
+/coverage
 ###< symfony/phpunit-bridge ###
 
 ###> phpunit/phpunit ###
 /phpunit.xml
 .phpunit.result.cache
-/phpunit.xml.dist
 ###< phpunit/phpunit ###
 
 ###> lexik/jwt-authentication-bundle ###
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 78e6af8..5620939 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,6 +29,17 @@ roadiz_skeleton_test:
         key: ${CI_COMMIT_REF_SLUG}
         paths:
             - vendor/
+    variables:
+        XDEBUG_MODE: "coverage"
+    artifacts:
+        expire_in: 1 day
+        paths:
+            - coverage
+        reports:
+            junit: coverage/report.xml
+            coverage_report:
+                coverage_format: cobertura
+                path: coverage/cobertura.xml
     #before_script:
         #- eval "$(ssh-agent -s)"
         #- echo "$COMPOSER_SERVER_PRIVATE_KEY" | tr -d '\r' | ssh-add -
@@ -44,6 +55,7 @@ roadiz_skeleton_test:
         - composer install
         - php -d memory_limit=-1 vendor/bin/phpcs -p ./src
         - php -d memory_limit=-1 vendor/bin/phpstan analyse -c phpstan.neon
+        - php -d memory_limit=-1 vendor/bin/phpunit --colors=never
 
 roadiz_skeleton_build:
     stage: build
diff --git a/Makefile b/Makefile
index 09f4fe7..2ae832e 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ cache:
 test:
 	docker compose exec -u www-data app php -d "memory_limit=-1" vendor/bin/phpcbf --report=full --report-file=./report.txt -p ./src
 	docker compose exec -u www-data app php -d "memory_limit=-1" vendor/bin/phpstan analyse -c phpstan.neon
+	XDEBUG_MODE=coverage php -d "memory_limit=-1" vendor/bin/phpunit
 
 update:
 	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate -n
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..ce14acd
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
+         backupGlobals="false"
+         colors="true"
+         bootstrap="tests/bootstrap.php"
+         convertDeprecationsToExceptions="false"
+>
+    <php>
+        <ini name="display_errors" value="1" />
+        <ini name="error_reporting" value="-1" />
+        <server name="APP_ENV" value="test" force="true" />
+        <server name="SHELL_VERBOSITY" value="-1" />
+        <server name="SYMFONY_PHPUNIT_REMOVE" value="" />
+        <server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
+
+        <!-- ###+ symfony/framework-bundle ### -->
+        <env name="APP_ENV" value="dev"/>
+        <env name="APP_SECRET" value="a187ac3261df1e2fb8593e5d4317ba8f"/>
+        <!-- ###- symfony/framework-bundle ### -->
+
+        <!-- ###+ lexik/jwt-authentication-bundle ### -->
+        <env name="JWT_SECRET_KEY" value="%kernel.project_dir%/config/jwt/private.pem"/>
+        <env name="JWT_PUBLIC_KEY" value="%kernel.project_dir%/config/jwt/public.pem"/>
+        <env name="JWT_PASSPHRASE" value="0727af357f199ca3d67b150ac4607096"/>
+        <!-- ###- lexik/jwt-authentication-bundle ### -->
+
+        <!-- ###+ nelmio/cors-bundle ### -->
+        <env name="CORS_ALLOW_ORIGIN" value="'^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'"/>
+        <!-- ###- nelmio/cors-bundle ### -->
+    </php>
+
+    <testsuites>
+        <testsuite name="Project Test Suite">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <coverage cacheDirectory="coverage"
+              includeUncoveredFiles="true"
+              processUncoveredFiles="true"
+              pathCoverage="false"
+              ignoreDeprecatedCodeUnits="true"
+              disableCodeCoverageIgnore="true">
+        <include>
+            <directory suffix=".php">src</directory>
+        </include>
+        <report>
+            <text outputFile="php://stdout"/>
+            <clover outputFile="coverage/clover.xml"/>
+            <cobertura outputFile="coverage/cobertura.xml"/>
+        </report>
+    </coverage>
+
+    <listeners>
+        <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
+    </listeners>
+
+    <!-- Run `composer require symfony/panther` before enabling this extension -->
+    <!--
+    <extensions>
+        <extension class="Symfony\Component\Panther\ServerExtension" />
+    </extensions>
+    -->
+</phpunit>

From 981b3efd74784da97574df7a8cc8b266423bd537 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 26 Mar 2024 18:55:24 +0100
Subject: [PATCH 27/38] fix: Prefix all api_resource config file with
 `resources`

---
 config/api_resources/attribute.yml       |   6 +-
 config/api_resources/attribute_value.yml |  26 +--
 config/api_resources/common_content.yml  |  55 +++---
 config/api_resources/custom_form.yml     | 202 +++++++++++------------
 config/api_resources/document.yml        |  26 +--
 config/api_resources/folder.yml          |  26 +--
 config/api_resources/node.yml            |  26 +--
 config/api_resources/nodes_sources.yml   | 126 +++++++-------
 config/api_resources/realm.yml           |  26 +--
 config/api_resources/tag.yml             |  34 ++--
 config/api_resources/translation.yml     |  30 ++--
 config/api_resources/web_response.yml    |  44 +----
 config/packages/api_platform.yaml        |   9 +
 13 files changed, 304 insertions(+), 332 deletions(-)

diff --git a/config/api_resources/attribute.yml b/config/api_resources/attribute.yml
index 1b48bcc..ed131e5 100644
--- a/config/api_resources/attribute.yml
+++ b/config/api_resources/attribute.yml
@@ -1,4 +1,4 @@
----
-RZ\Roadiz\CoreBundle\Entity\Attribute:
-    operations: []
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Attribute:
+        operations: []
 
diff --git a/config/api_resources/attribute_value.yml b/config/api_resources/attribute_value.yml
index 23eee57..cd24bf6 100644
--- a/config/api_resources/attribute_value.yml
+++ b/config/api_resources/attribute_value.yml
@@ -1,14 +1,14 @@
----
-RZ\Roadiz\CoreBundle\Entity\AttributeValue:
-    operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                groups: ["urls", "attribute", "document_display", "attribute_node", "attribute_documents"]
-                enable_max_depth: true
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                groups: ["urls", "attribute", "document_display", "attribute_node", "attribute_documents"]
-                enable_max_depth: true
+resources:
+    RZ\Roadiz\CoreBundle\Entity\AttributeValue:
+        operations:
+            ApiPlatform\Metadata\GetCollection:
+                method: "GET"
+                normalizationContext:
+                    groups: ["urls", "attribute", "document_display", "attribute_node", "attribute_documents"]
+                    enable_max_depth: true
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    groups: ["urls", "attribute", "document_display", "attribute_node", "attribute_documents"]
+                    enable_max_depth: true
 
diff --git a/config/api_resources/common_content.yml b/config/api_resources/common_content.yml
index 8f59e0f..7f3e5a4 100644
--- a/config/api_resources/common_content.yml
+++ b/config/api_resources/common_content.yml
@@ -1,28 +1,29 @@
-App\Api\Model\CommonContent:
-    operations:
-        getCommonContent:
-            class: ApiPlatform\Metadata\Get
-            method: 'GET'
-            uriTemplate: '/common_content'
-            read: false
-            controller: App\Controller\GetCommonContentController
-            pagination_enabled: false
-            normalizationContext:
-                enable_max_depth: true
+resources:
+    App\Api\Model\CommonContent:
+        operations:
+            getCommonContent:
+                class: ApiPlatform\Metadata\Get
+                method: 'GET'
+                uriTemplate: '/common_content'
+                read: false
+                controller: App\Controller\GetCommonContentController
                 pagination_enabled: false
-                groups:
-                    - get
-                    - common_content
-                    - web_response
-                    - walker
-                    - walker_level
-                    - children
-                    - children_count
-                    - nodes_sources_base
-                    - nodes_sources_default
-                    - urls
-                    #- blocks_urls
-                    - tag_base
-                    - translation_base
-                    - document_display
-                    - document_folders
+                normalizationContext:
+                    enable_max_depth: true
+                    pagination_enabled: false
+                    groups:
+                        - get
+                        - common_content
+                        - web_response
+                        - walker
+                        - walker_level
+                        - children
+                        - children_count
+                        - nodes_sources_base
+                        - nodes_sources_default
+                        - urls
+                        #- blocks_urls
+                        - tag_base
+                        - translation_base
+                        - document_display
+                        - document_folders
diff --git a/config/api_resources/custom_form.yml b/config/api_resources/custom_form.yml
index fbb79c5..27e15d8 100644
--- a/config/api_resources/custom_form.yml
+++ b/config/api_resources/custom_form.yml
@@ -1,110 +1,110 @@
----
-RZ\Roadiz\CoreBundle\Entity\CustomForm:
-    operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                enable_max_depth: true
+resources:
+    RZ\Roadiz\CoreBundle\Entity\CustomForm:
+        operations:
+            ApiPlatform\Metadata\GetCollection:
+                method: "GET"
+                normalizationContext:
+                    enable_max_depth: true
 
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                enable_max_depth: true
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    enable_max_depth: true
 
-        api_custom_forms_item_post:
-            method: 'POST'
-            class: ApiPlatform\Metadata\Post
-            routeName: api_custom_forms_item_post
-            normalizationContext:
-                enable_max_depth: true
-            openapiContext:
-                summary: Post a user custom form
-                description: |
-                    Post a user custom form
-                requestBody:
-                    content:
-                        multipart/form-data:
-                            schema:
-                                type: object
-                                properties:
-                                    custom_form_slug[email]:
-                                        type: string
-                                        example: test@test.test
-                                    custom_form_slug[first_name]:
-                                        type: string
-                                        example: John
-                                    custom_form_slug[last_name]:
-                                        type: string
-                                        example: Doe
-                responses:
-                    201: ~
-                    400:
-                        description: Posted custom form has errors
+            api_custom_forms_item_post:
+                method: 'POST'
+                class: ApiPlatform\Metadata\Post
+                routeName: api_custom_forms_item_post
+                normalizationContext:
+                    enable_max_depth: true
+                openapiContext:
+                    summary: Post a user custom form
+                    description: |
+                        Post a user custom form
+                    requestBody:
                         content:
-                            application/json:
+                            multipart/form-data:
                                 schema:
                                     type: object
                                     properties:
-                                        email:
-                                            type: object
-                                            example:
-                                                email: This value is not a valid email address.
-                    202:
-                        description: Posted custom form was accepted
-                        content:
-                            application/json:
-                                schema:
-                                    type: object
-                                    properties: { }
-
-        api_custom_forms_item_definition:
-            method: 'GET'
-            class: ApiPlatform\Metadata\Get
-            routeName: api_custom_forms_item_definition
-            normalizationContext:
-                enable_max_depth: true
-            openapiContext:
-                summary: Get a custom form definition for frontend
-                description: |
-                    Get a custom form definition for frontend
-                responses:
-                    200:
-                        description: Custom form definition object
-                        content:
-                            application/json:
-                                schema:
-                                    type: object
-                                    properties:
-                                        title:
+                                        custom_form_slug[email]:
+                                            type: string
+                                            example: test@test.test
+                                        custom_form_slug[first_name]:
                                             type: string
-                                            description: Form inputs prefix
-                                            example: reiciendis_natus_ducimus_nostrum
-                                        type:
+                                            example: John
+                                        custom_form_slug[last_name]:
                                             type: string
-                                            description: Form definition type
-                                            example: object
+                                            example: Doe
+                    responses:
+                        201: ~
+                        400:
+                            description: Posted custom form has errors
+                            content:
+                                application/json:
+                                    schema:
+                                        type: object
+                                        properties:
+                                            email:
+                                                type: object
+                                                example:
+                                                    email: This value is not a valid email address.
+                        202:
+                            description: Posted custom form was accepted
+                            content:
+                                application/json:
+                                    schema:
+                                        type: object
+                                        properties: { }
+
+            api_custom_forms_item_definition:
+                method: 'GET'
+                class: ApiPlatform\Metadata\Get
+                routeName: api_custom_forms_item_definition
+                normalizationContext:
+                    enable_max_depth: true
+                openapiContext:
+                    summary: Get a custom form definition for frontend
+                    description: |
+                        Get a custom form definition for frontend
+                    responses:
+                        200:
+                            description: Custom form definition object
+                            content:
+                                application/json:
+                                    schema:
+                                        type: object
                                         properties:
-                                            type: object
-                                            description: Form definition fields
-                                            example:
-                                                email:
-                                                    type: string
-                                                    title: Email
-                                                    attr:
-                                                        data-group: null
-                                                        placeholder: null
-                                                    widget: email
-                                                    propertyOrder: 1
-                                                first_name:
-                                                    type: string
-                                                    title: Firstname
-                                                    attr:
-                                                        data-group: null
-                                                        placeholder: null
-                                                    widget: string
-                                                    propertyOrder: 2
-                                        required:
-                                            type: array
-                                            description: Required fields names
-                                            example:
-                                                - 'email'
+                                            title:
+                                                type: string
+                                                description: Form inputs prefix
+                                                example: reiciendis_natus_ducimus_nostrum
+                                            type:
+                                                type: string
+                                                description: Form definition type
+                                                example: object
+                                            properties:
+                                                type: object
+                                                description: Form definition fields
+                                                example:
+                                                    email:
+                                                        type: string
+                                                        title: Email
+                                                        attr:
+                                                            data-group: null
+                                                            placeholder: null
+                                                        widget: email
+                                                        propertyOrder: 1
+                                                    first_name:
+                                                        type: string
+                                                        title: Firstname
+                                                        attr:
+                                                            data-group: null
+                                                            placeholder: null
+                                                        widget: string
+                                                        propertyOrder: 2
+                                            required:
+                                                type: array
+                                                description: Required fields names
+                                                example:
+                                                    - 'email'
diff --git a/config/api_resources/document.yml b/config/api_resources/document.yml
index acb4a7d..9af977d 100644
--- a/config/api_resources/document.yml
+++ b/config/api_resources/document.yml
@@ -1,15 +1,15 @@
----
-RZ\Roadiz\CoreBundle\Entity\Document:
-    operations:
-#        ApiPlatform\Metadata\GetCollection:
-#            method: "GET"
-#            normalizationContext:
-#                groups: ["urls", "document_display", "document_folders", "document_folders_all", "document_display_sources"]
-#                enable_max_depth: true
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Document:
+        operations:
+    #        ApiPlatform\Metadata\GetCollection:
+    #            method: "GET"
+    #            normalizationContext:
+    #                groups: ["urls", "document_display", "document_folders", "document_folders_all", "document_display_sources"]
+    #                enable_max_depth: true
 
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                groups: ["urls", "document", "document_display", "document_folders", "document_folders_all", "document_display_sources"]
-                enable_max_depth: true
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    groups: ["urls", "document", "document_display", "document_folders", "document_folders_all", "document_display_sources"]
+                    enable_max_depth: true
 
diff --git a/config/api_resources/folder.yml b/config/api_resources/folder.yml
index 38dafc5..61edc33 100644
--- a/config/api_resources/folder.yml
+++ b/config/api_resources/folder.yml
@@ -1,13 +1,13 @@
----
-RZ\Roadiz\CoreBundle\Entity\Folder:
-    operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                groups: [ "folder" ]
-                enable_max_depth: true
-        ApiPlatform\Metadata\Get:
-            method: "GET"
-            normalizationContext:
-                groups: [ "folder" ]
-                enable_max_depth: true
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Folder:
+        operations:
+            ApiPlatform\Metadata\GetCollection:
+                method: "GET"
+                normalizationContext:
+                    groups: [ "folder" ]
+                    enable_max_depth: true
+            ApiPlatform\Metadata\Get:
+                method: "GET"
+                normalizationContext:
+                    groups: [ "folder" ]
+                    enable_max_depth: true
diff --git a/config/api_resources/node.yml b/config/api_resources/node.yml
index 61e7b91..8731c34 100644
--- a/config/api_resources/node.yml
+++ b/config/api_resources/node.yml
@@ -1,13 +1,13 @@
----
-RZ\Roadiz\CoreBundle\Entity\Node:
-    operations:
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                groups:
-                    - node
-                    - tag_base
-                    - translation_base
-                    - document_display
-                    - document_display_sources
-                enable_max_depth: true
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Node:
+        operations:
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    groups:
+                        - node
+                        - tag_base
+                        - translation_base
+                        - document_display
+                        - document_display_sources
+                    enable_max_depth: true
diff --git a/config/api_resources/nodes_sources.yml b/config/api_resources/nodes_sources.yml
index 602794b..0674f81 100644
--- a/config/api_resources/nodes_sources.yml
+++ b/config/api_resources/nodes_sources.yml
@@ -1,66 +1,66 @@
----
-RZ\Roadiz\CoreBundle\Entity\NodesSources:
-    operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                groups:
-                    - nodes_sources_base
-                    - nodes_sources_default
-                    - user
-                    - urls
-                    - tag_base
-                    - translation_base
-                    - document_display
+resources:
+    RZ\Roadiz\CoreBundle\Entity\NodesSources:
+        operations:
+            ApiPlatform\Metadata\GetCollection:
+                method: "GET"
+                normalizationContext:
+                    groups:
+                        - nodes_sources_base
+                        - nodes_sources_default
+                        - user
+                        - urls
+                        - tag_base
+                        - translation_base
+                        - document_display
 
-        api_nodes_sources_archives:
-            class: ApiPlatform\Metadata\GetCollection
-            method: 'GET'
-            uriTemplate: '/nodes_sources/archives'
-            pagination_enabled: false
-            pagination_client_enabled: false
-            extraProperties:
-                archive_enabled: true
-                archive_publication_field_name: publishedAt
-            normalizationContext:
-                groups:
-                    - get
-                    - archives
-            openapiContext:
-                summary: Get available NodesSources archives
-                parameters: ~
-                description: |
-                    Get available NodesSources archives (years and months) based on their `publishedAt` field
+            api_nodes_sources_archives:
+                class: ApiPlatform\Metadata\GetCollection
+                method: 'GET'
+                uriTemplate: '/nodes_sources/archives'
+                pagination_enabled: false
+                pagination_client_enabled: false
+                extraProperties:
+                    archive_enabled: true
+                    archive_publication_field_name: publishedAt
+                normalizationContext:
+                    groups:
+                        - get
+                        - archives
+                openapiContext:
+                    summary: Get available NodesSources archives
+                    parameters: ~
+                    description: |
+                        Get available NodesSources archives (years and months) based on their `publishedAt` field
 
-        api_nodes_sources_search:
-            class: ApiPlatform\Metadata\GetCollection
-            method: 'GET'
-            uriTemplate: '/nodes_sources/search'
-            controller: RZ\Roadiz\CoreBundle\Api\Controller\NodesSourcesSearchController
-            read: false
-            normalizationContext:
-                groups:
-                    - get
-                    - nodes_sources_base
-                    - nodes_sources_default
-                    - urls
-                    - tag_base
-                    - translation_base
-                    - document_display
-            openapiContext:
-                summary: Search NodesSources resources
-                description: |
-                    Search all website NodesSources resources using **Solr** full-text search engine
-                parameters:
-                    -   type: string
-                        name: search
-                        in: query
-                        required: true
-                        description: Search pattern
-                        schema:
-                            type: string
+            api_nodes_sources_search:
+                class: ApiPlatform\Metadata\GetCollection
+                method: 'GET'
+                uriTemplate: '/nodes_sources/search'
+                controller: RZ\Roadiz\CoreBundle\Api\Controller\NodesSourcesSearchController
+                read: false
+                normalizationContext:
+                    groups:
+                        - get
+                        - nodes_sources_base
+                        - nodes_sources_default
+                        - urls
+                        - tag_base
+                        - translation_base
+                        - document_display
+                openapiContext:
+                    summary: Search NodesSources resources
+                    description: |
+                        Search all website NodesSources resources using **Solr** full-text search engine
+                    parameters:
+                        -   type: string
+                            name: search
+                            in: query
+                            required: true
+                            description: Search pattern
+                            schema:
+                                type: string
 
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                groups: ["nodes_sources", "urls", "tag_base", "translation_base", "document_display"]
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    groups: ["nodes_sources", "urls", "tag_base", "translation_base", "document_display"]
diff --git a/config/api_resources/realm.yml b/config/api_resources/realm.yml
index e2fc1dc..8188697 100644
--- a/config/api_resources/realm.yml
+++ b/config/api_resources/realm.yml
@@ -1,14 +1,14 @@
----
-RZ\Roadiz\CoreBundle\Entity\Realm:
-    operations:
-#        ApiPlatform\Metadata\GetCollection:
-#            method: "GET"
-#            normalizationContext:
-#                groups: [ "realm" ]
-#                enable_max_depth: true
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Realm:
+        operations: {}
+    #        ApiPlatform\Metadata\GetCollection:
+    #            method: "GET"
+    #            normalizationContext:
+    #                groups: [ "realm" ]
+    #                enable_max_depth: true
 
-        ApiPlatform\Metadata\Get:
-            method: "GET"
-            normalizationContext:
-                groups: [ "realm" ]
-                enable_max_depth: true
+#            ApiPlatform\Metadata\Get:
+#                method: "GET"
+#                normalizationContext:
+#                    groups: [ "realm" ]
+#                    enable_max_depth: true
diff --git a/config/api_resources/tag.yml b/config/api_resources/tag.yml
index 3f35d12..51dec44 100644
--- a/config/api_resources/tag.yml
+++ b/config/api_resources/tag.yml
@@ -1,18 +1,18 @@
----
-RZ\Roadiz\CoreBundle\Entity\Tag:
-    operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                enable_max_depth: true
-                groups:
-                    - tag_base
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Tag:
+        operations:
+            ApiPlatform\Metadata\GetCollection:
+                method: "GET"
+                normalizationContext:
+                    enable_max_depth: true
+                    groups:
+                        - tag_base
 
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                enable_max_depth: true
-                groups:
-                    - tag
-                    - tag_base
-                    - tag_parent
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    enable_max_depth: true
+                    groups:
+                        - tag
+                        - tag_base
+                        - tag_parent
diff --git a/config/api_resources/translation.yml b/config/api_resources/translation.yml
index ad19c01..20e9fb7 100644
--- a/config/api_resources/translation.yml
+++ b/config/api_resources/translation.yml
@@ -1,17 +1,17 @@
----
-RZ\Roadiz\CoreBundle\Entity\Translation:
-    operations:
-        ApiPlatform\Metadata\GetCollection:
-            method: "GET"
-            normalizationContext:
-                enable_max_depth: true
-                groups:
-                    - translation_base
+resources:
+    RZ\Roadiz\CoreBundle\Entity\Translation:
+        operations:
+            ApiPlatform\Metadata\GetCollection:
+                method: "GET"
+                normalizationContext:
+                    enable_max_depth: true
+                    groups:
+                        - translation_base
 
-        ApiPlatform\Metadata\Get:
-            method: 'GET'
-            normalizationContext:
-                enable_max_depth: true
-                groups:
-                    - translation_base
+            ApiPlatform\Metadata\Get:
+                method: 'GET'
+                normalizationContext:
+                    enable_max_depth: true
+                    groups:
+                        - translation_base
 
diff --git a/config/api_resources/web_response.yml b/config/api_resources/web_response.yml
index 865dff1..247903b 100644
--- a/config/api_resources/web_response.yml
+++ b/config/api_resources/web_response.yml
@@ -1,41 +1,3 @@
-RZ\Roadiz\CoreBundle\Api\Model\WebResponse:
-    operations:
-        getByPath:
-            class: ApiPlatform\Metadata\Get
-            method: 'GET'
-            uriTemplate: '/web_response_by_path'
-            read: false
-            controller: RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController
-            pagination_enabled: false
-            normalizationContext:
-                enable_max_depth: true
-                pagination_enabled: false
-                groups:
-                    - get
-                    - web_response
-                    - position
-                    - walker
-                    - walker_level
-                    - meta
-                    - children
-                    - children_count
-                    - nodes_sources
-                    - urls
-                    - tag_base
-                    - translation_base
-                    - document_display
-                    - document_thumbnails
-                    - node_attributes
-                    - document_display_sources
-            openapiContext:
-                summary: Get a resource by its path wrapped in a WebResponse object
-                description: |
-                    Get a resource by its path wrapped in a WebResponse
-                parameters:
-                    -   type: string
-                        name: path
-                        in: query
-                        required: true
-                        description: Resource path, or `/` for home page
-                        schema:
-                            type: string
+resources:
+    RZ\Roadiz\CoreBundle\Api\Model\WebResponse:
+        operations: {}
diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml
index 186a06b..603c808 100644
--- a/config/packages/api_platform.yaml
+++ b/config/packages/api_platform.yaml
@@ -9,8 +9,11 @@ api_platform:
     enable_swagger_ui: true
     enable_re_doc: true
     graphql:
+        introspection: '%kernel.debug%'
         graphiql:
             enabled: false
+        graphql_playground:
+            enabled: false
     show_webby: false
     swagger:
         versions: [3]
@@ -52,6 +55,12 @@ api_platform:
 
 when@prod:
     api_platform:
+        graphql:
+            introspection: false
+            graphiql:
+                enabled: false
+            graphql_playground:
+                enabled: false
         http_cache:
             invalidation:
                 enabled: true

From 6fd4063a90e3c0b5b95bd3cea48f9a66c9467c89 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 3 Apr 2024 09:54:55 +0200
Subject: [PATCH 28/38] ci: Removed /var/www/html/var/secret volume

---
 Dockerfile | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 44d9596..4f04720 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -50,5 +50,4 @@ VOLUME /var/www/html/config/jwt \
        #/var/www/html/src/GeneratedEntity \
        /var/www/html/public/files \
        /var/www/html/public/assets \
-       /var/www/html/var/files \
-       /var/www/html/var/secret
+       /var/www/html/var/files

From 185aefd733eb95624c7ebe3730694e49b92bee9c Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 9 Apr 2024 16:29:49 +0200
Subject: [PATCH 29/38] fix: Improved docker cron entrypoint

---
 docker/php-fpm-alpine/docker-cron-entrypoint | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/docker/php-fpm-alpine/docker-cron-entrypoint b/docker/php-fpm-alpine/docker-cron-entrypoint
index 307ee3f..23f97ef 100755
--- a/docker/php-fpm-alpine/docker-cron-entrypoint
+++ b/docker/php-fpm-alpine/docker-cron-entrypoint
@@ -3,11 +3,14 @@ set -e
 
 env >> /etc/environment
 
-# Need to fix permissions for be able to create cache dir
-/bin/chown -R www-data:www-data /var/www/html/var || true;
-/bin/mkdir -p /var/www/html/var/cache || true;
-# Need to fix permissions for be able to write in cache dir
 /bin/chown -R www-data:www-data /var/www/html/var || true;
+/bin/chown -R www-data:www-data /var/www/html/config || true;
+
+# Print local env vars to .env.xxx.php file for performances and crontab jobs
+/usr/bin/sudo -u www-data -- bash -c  "/usr/local/bin/composer dump-env prod"
+# To improve performance (i.e. avoid decrypting secrets at runtime),
+# you can decrypt your secrets during deployment to the "local" vault:
+/usr/bin/sudo -u www-data -- bash -c "APP_RUNTIME_ENV=prod /var/www/html/bin/console secrets:decrypt-to-local --force"
 
 # Let cron take the wheel
 echo "Starting cron in foreground."

From 1d7f23350a38ed39dcc4b649c40ece5a83b6d962 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 10 Apr 2024 11:47:10 +0200
Subject: [PATCH 30/38] doc: Added dev and stop Make recipes

---
 Makefile  | 11 ++++++++++
 README.md | 63 +++++++++++++++++++++++++++----------------------------
 2 files changed, 42 insertions(+), 32 deletions(-)

diff --git a/Makefile b/Makefile
index 2ae832e..46bb197 100644
--- a/Makefile
+++ b/Makefile
@@ -34,3 +34,14 @@ changelog:
 
 bump:
 	git-cliff --bump -o CHANGELOG.md
+
+##
+## Start the development environment using Symfony server and Docker
+##
+dev:
+	docker compose -f docker-compose.symfony.yml up -d
+	symfony serve -d
+
+stop:
+	symfony server:stop
+	docker compose -f docker-compose.symfony.yml down
diff --git a/README.md b/README.md
index 0df9026..9290a98 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,36 @@ When you're ready you can check that *Symfony* console responds through your Doc
 docker compose exec -u www-data app bin/console
 ```
 
+### Using `symfony server:start` instead of Docker
+
+If you are working on a *macOS* environment, you may prefer using `symfony` binary to start a local webserver instead of using
+a full _Docker_ stack. You will need to install `symfony` binary first:
+
+```shell
+curl -sS https://get.symfony.com/cli/installer | bash
+```
+
+And make sure your local PHP environment is configured with php-intl, php-redis, php-gd extensions.
+You will need to use at least *MySQL* and *Redis* (and *Solr* if needed) services from Docker stack in order to run your application.
+
+```shell
+docker compose -f docker-compose.symfony.yml up -d 
+```
+
+- Configure your `.env.local` variables to use your local MySQL and Redis services. Replacing `db`, `redis`, `mailer` and `solr` hostnames with `127.0.0.1`. Make sure to use `127.0.0.1` and not `localhost` on *macOS* as it will not work with Docker.
+- Remove `docker compose exec -u www-data app ` prefix from all commands in `Makefile` to execute recipes locally.
+- Remove cache invalidation Varnish configuration from `config/packages/api_platform.yaml` and `config/packages/roadiz_core.yaml` file.
+
+Then you can start your local webserver:
+
+```shell
+symfony serve -d
+```
+
+Perform all installation steps described above, without using `docker compose exec` command.
+
+Then your Roadiz backoffice will be available at `https://127.0.0.1:8000/rz-admin`
+
 ### Generate [Symfony secrets](https://symfony.com/doc/current/configuration/secrets.html)
 
 When you run `composer create-project` first time, following command should have been executed automatically:
@@ -120,7 +150,6 @@ make update
 This will **only load node-types** that are not already in the database. But it won't create any migration.
 This is the same script that is executed when you run `make install` and in your docker image entrypoint.
 
-
 ### Features
 
 - Configured to be used in headless mode with *API Platform*
@@ -202,37 +231,7 @@ You can fetch this endpoint once in your website frontend, instead of embedding
 
 Make sure your `.env` file does not contain any sensitive data as it must be added to your repository: `git add --force .env`
 in order to be overridden by `.env.local` file.
-Sensitive and local data must be filled in `.env.local` which is git-ignored. 
-
-### Using `symfony server:start` instead of Docker
-
-If you are working on a *macOS* environment, you may prefer using `symfony` binary to start a local webserver instead of using
-a full _Docker_ stack. You will need to install `symfony` binary first:
-
-```shell
-curl -sS https://get.symfony.com/cli/installer | bash
-```
-
-And make sure your local PHP environment is configured with php-intl, php-redis, php-gd extensions.
-You will need to use at least *MySQL* and *Redis* (and *Solr* if needed) services from Docker stack in order to run your application.
-
-```shell
-docker compose -f docker-compose.symfony.yml up -d 
-```
-
-- Configure your `.env` variables to use your local MySQL and Redis services. Replacing `db`, `redis`, `mailer` and `solr` hostnames with `127.0.0.1`. Make sure to use `127.0.0.1` and not `localhost` on *macOS* as it will not work with Docker.
-- Remove `docker compose exec -u www-data app ` prefix from all commands in `Makefile` to execute recipes locally. 
-- Remove cache invalidation Varnish configuration from `config/packages/api_platform.yaml` and `config/packages/roadiz_core.yaml` file.
-
-Then you can start your local webserver:
-
-```shell
-symfony server:start
-```
-
-Perform all installation steps described above, without using `docker compose exec` command.
-
-Then your Roadiz backoffice will be available at `https://127.0.0.1:8000/rz-admin`
+Sensitive and local data must be filled in `.env.local` which is git-ignored.
 
 ### Make node-types editable on production environment
 

From 9afbc972074be6ef90b9a9d7f5627089a7bcf2a7 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 10 Apr 2024 11:49:13 +0200
Subject: [PATCH 31/38] chore: Added named docker-compose for monorepos

---
 docker-compose.restore.yml | 2 +-
 docker-compose.symfony.yml | 1 +
 docker-compose.yml         | 1 +
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/docker-compose.restore.yml b/docker-compose.restore.yml
index f34a8e0..6702625 100644
--- a/docker-compose.restore.yml
+++ b/docker-compose.restore.yml
@@ -1,7 +1,7 @@
 # Restoring from a backup into development environment
 # Separate file to avoid running the restore services when using docker-compose up
 # docker compose -f docker-compose.restore.yml --env-file .env.local run --rm restore_files
-version: '3.6'
+name: skeleton
 services:
     restore_files:
         # Keep the same hostname for all Restic services
diff --git a/docker-compose.symfony.yml b/docker-compose.symfony.yml
index c0a6d96..07efbbb 100644
--- a/docker-compose.symfony.yml
+++ b/docker-compose.symfony.yml
@@ -1,6 +1,7 @@
 #
 # Only use this docker compose template if you prefer using symfony server:start
 #
+name: skeleton
 services:
     db:
         build:
diff --git a/docker-compose.yml b/docker-compose.yml
index 8700a3b..4ecaec2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,3 +1,4 @@
+name: skeleton
 services:
     db:
         build:

From 3ca08a71b69dafea299e6288417bf5074d8477f9 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Tue, 23 Apr 2024 11:49:36 +0200
Subject: [PATCH 32/38] chore: Allow local network CORS

---
 .env | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.env b/.env
index 1a11a4e..152d4e7 100644
--- a/.env
+++ b/.env
@@ -131,7 +131,7 @@ IR_DRIVER=gd
 ###< rezozero/intervention-request-bundle ###
 
 ###> nelmio/cors-bundle ###
-CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$
+CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1|192\.168\.1\.[0-9]+)(:[0-9]+)?$
 ###< nelmio/cors-bundle ###
 
 ###> symfony/framework-bundle ###

From 079eee668c421a841f789dc45770fa2e3d302cca Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 3 May 2024 17:49:06 +0200
Subject: [PATCH 33/38] chore: Dockerfile label

---
 docker/mysql/Dockerfile   | 2 +-
 docker/nginx/Dockerfile   | 2 +-
 docker/solr/Dockerfile    | 2 +-
 docker/varnish/Dockerfile | 1 +
 4 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/docker/mysql/Dockerfile b/docker/mysql/Dockerfile
index c73ae54..eb1b85b 100644
--- a/docker/mysql/Dockerfile
+++ b/docker/mysql/Dockerfile
@@ -1,5 +1,5 @@
 FROM mysql:8.0
-MAINTAINER Ambroise Maupate <ambroise@rezo-zero.com>
+LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
 ARG USER_UID=1000
 
diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile
index 7a531a5..f681ef7 100644
--- a/docker/nginx/Dockerfile
+++ b/docker/nginx/Dockerfile
@@ -1,4 +1,4 @@
 FROM roadiz/nginx-alpine
-MAINTAINER Ambroise Maupate <ambroise@rezo-zero.com>
+LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
 COPY ./public /var/www/html/public
diff --git a/docker/solr/Dockerfile b/docker/solr/Dockerfile
index 93e4406..aa7bf15 100644
--- a/docker/solr/Dockerfile
+++ b/docker/solr/Dockerfile
@@ -1,5 +1,5 @@
 FROM solr:8-slim
-MAINTAINER Ambroise Maupate <ambroise@rezo-zero.com>
+LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
 ARG USER_UID=8983
 
diff --git a/docker/varnish/Dockerfile b/docker/varnish/Dockerfile
index 6e34d85..927f060 100644
--- a/docker/varnish/Dockerfile
+++ b/docker/varnish/Dockerfile
@@ -1,4 +1,5 @@
 FROM varnish:7.1-alpine
+LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com"
 
 ENV VARNISH_SIZE 1G
 COPY ./default.vcl /etc/varnish/

From d775d9c1234f0036246f8bfc79415da5b1f29bc7 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Fri, 3 May 2024 18:27:34 +0200
Subject: [PATCH 34/38] chore: Use `docker-cron-entrypoint` in dev env

---
 docker-compose.yml | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/docker-compose.yml b/docker-compose.yml
index 4ecaec2..b796f4b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -124,9 +124,7 @@ services:
 
     cron:
         <<: *app_template
-        # https://github.com/dubiousjim/dcron/issues/13#issuecomment-1406937781
-        init: true
-        entrypoint: [ "crond", "-f", "-L", "15" ]
+        entrypoint: 'docker-cron-entrypoint'
         restart: unless-stopped
 
 #    solr:

From 2b6bfef622b78a6fe1ff3469aad704a93e5b17de Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Mon, 13 May 2024 19:39:33 +0200
Subject: [PATCH 35/38] chore: Upgraded phpstan.neon

---
 phpstan.neon | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/phpstan.neon b/phpstan.neon
index 1d05ee5..e9e5e41 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -8,6 +8,8 @@ parameters:
         - */bower_components/*
         - */static/*
     ignoreErrors:
+        - identifier: missingType.iterableValue
+        - identifier: missingType.generics
         - '#Class GeneratedNodeSources\\NS([a-zA-Z]+) not found#'
         - '#Call to method ([a-zA-Z]+)\(\) on an unknown class GeneratedNodeSources\\NS([a-zA-Z]+)#'
         - '#Call to an undefined method ([^:]+)\:\:get(?:External|Internal)Link(?:Sources)?\(\)#'
@@ -33,5 +35,3 @@ parameters:
         - '#type mapping mismatch: database can contain array\|bool\|float\|int\|JsonSerializable\|stdClass\|string\|null but property expects array\|null#'
 
     reportUnmatchedIgnoredErrors: false
-    checkGenericClassInNonGenericObjectType: false
-    checkMissingIterableValueType: false

From 1d1946b899bc2cbf04baa9695bbb8b2d0d3b1e48 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 15 May 2024 18:28:13 +0200
Subject: [PATCH 36/38] chore: Higher router priority

---
 docker-compose.prod.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index d190548..e530679 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -57,12 +57,16 @@ services:
             # - "traefik.http.services.${APP_NAMESPACE}.loadbalancer.healthcheck.headers.x-health-check=${APP_HEALTH_CHECK_TOKEN}"
             # Listen HTTP
             - "traefik.http.routers.${APP_NAMESPACE}.entrypoints=http"
+            # Always use higher priority for your API app with PathPrefix rule
+            - "traefik.http.routers.${APP_NAMESPACE}.priority=11"
             # Combine Host and PathPrefix to allow API and Frontend to share same domain name
             - "traefik.http.routers.${APP_NAMESPACE}.rule=Host(${HOSTNAME}) && PathPrefix(${PATH_PREFIX})"
             - "traefik.http.routers.${APP_NAMESPACE}.service=${APP_NAMESPACE}"
             # Listen HTTPS
             - "traefik.http.routers.${APP_NAMESPACE}_secure.entrypoints=https"
             - "traefik.http.routers.${APP_NAMESPACE}_secure.tls=true"
+            # Always use higher priority for your API app with PathPrefix rule
+            - "traefik.http.routers.${APP_NAMESPACE}_secure.priority=11"
             - "traefik.http.routers.${APP_NAMESPACE}_secure.tls.certresolver=letsencrypt"
             # Combine Host and PathPrefix to allow API and Frontend to share same domain name
             - "traefik.http.routers.${APP_NAMESPACE}_secure.rule=Host(${HOSTNAME}) && PathPrefix(${PATH_PREFIX})"

From f65adbd55d49746eee1f5a6142e3107643600770 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 15 May 2024 18:32:14 +0200
Subject: [PATCH 37/38] chore: Fixed deps version

---
 .env               | 2 +-
 Makefile           | 6 +++---
 composer.json      | 3 +--
 composer.json.dist | 3 +--
 4 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/.env b/.env
index 152d4e7..029a471 100644
--- a/.env
+++ b/.env
@@ -131,7 +131,7 @@ IR_DRIVER=gd
 ###< rezozero/intervention-request-bundle ###
 
 ###> nelmio/cors-bundle ###
-CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1|192\.168\.1\.[0-9]+)(:[0-9]+)?$
+CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1|192\.168\.[0-9]+\.[0-9]+)(:[0-9]+)?$
 ###< nelmio/cors-bundle ###
 
 ###> symfony/framework-bundle ###
diff --git a/Makefile b/Makefile
index 46bb197..8fab94f 100644
--- a/Makefile
+++ b/Makefile
@@ -16,16 +16,16 @@ update:
 	make cache;
 
 migrate:
-	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate
+	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate -n
 	# Apply files changes and create new Doctrine migrations if necessary
 	docker compose exec -u www-data app php bin/console app:migrate
 	# Stop workers to force restart them (Supervisord)
 	docker compose exec -u www-data app php bin/console messenger:stop-workers
 
 install:
-	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate
+	docker compose exec -u www-data app php bin/console doctrine:migrations:migrate -n
 	# Do not perform files changes on the database
-	docker compose exec -u www-data app php bin/console app:install
+	docker compose exec -u www-data app php bin/console app:install -n
 	docker compose exec -u www-data app bin/console install;
 	make cache;
 
diff --git a/composer.json b/composer.json
index 778edd5..e052728 100644
--- a/composer.json
+++ b/composer.json
@@ -3,7 +3,6 @@
     "type": "project",
     "license": "mit",
     "prefer-stable": true,
-    "minimum-stability": "dev",
     "require": {
         "php": ">=8.2",
         "ext-ctype": "*",
@@ -11,7 +10,7 @@
         "ext-json": "*",
         "liip/monitor-bundle": "^2.22",
         "nelmio/cors-bundle": "^2.4",
-        "roadiz/cms-pack": "dev-develop",
+        "roadiz/cms-pack": "^2.0.1",
         "sentry/sentry-symfony": "^4.13",
         "symfony/flex": "*",
         "symfony/requirements-checker": "^2.0"
diff --git a/composer.json.dist b/composer.json.dist
index 778edd5..e052728 100644
--- a/composer.json.dist
+++ b/composer.json.dist
@@ -3,7 +3,6 @@
     "type": "project",
     "license": "mit",
     "prefer-stable": true,
-    "minimum-stability": "dev",
     "require": {
         "php": ">=8.2",
         "ext-ctype": "*",
@@ -11,7 +10,7 @@
         "ext-json": "*",
         "liip/monitor-bundle": "^2.22",
         "nelmio/cors-bundle": "^2.4",
-        "roadiz/cms-pack": "dev-develop",
+        "roadiz/cms-pack": "^2.0.1",
         "sentry/sentry-symfony": "^4.13",
         "symfony/flex": "*",
         "symfony/requirements-checker": "^2.0"

From 31a351f4f867b402feaf4d6f05311f3e35738912 Mon Sep 17 00:00:00 2001
From: Ambroise Maupate <ambroise@rezo-zero.com>
Date: Wed, 15 May 2024 18:33:02 +0200
Subject: [PATCH 38/38] chore: Bumped

---
 CHANGELOG.md | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b3d1c58..57f156d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,27 @@
 
 All notable changes to project will be documented in this file.
 
-## [unreleased]
+## [2.3.0](https://github.com/roadiz/skeleton/compare/v2.2.1...v2.3.0) - 2024-05-15
+
+### Bug Fixes
+
+- Fixed docker compose specification with `extends` and `depends_on` - ([aefde96](https://github.com/roadiz/skeleton/commit/aefde96f3660dc6d54c16a4e0073a97c087c4bdf)) - Ambroise Maupate
+- Fixed monolog log level on prod - ([095cccc](https://github.com/roadiz/skeleton/commit/095cccca56e105bdbf40339391776e63e4cd8391)) - Ambroise Maupate
+- Attribute class ApiPlatform\Core\Annotation\ApiProperty does not exist. - ([970ba38](https://github.com/roadiz/skeleton/commit/970ba381ea4df3179decd74b1ccfb42c4790d557)) - Ambroise Maupate
+- Do not migrate app on make install - ([3c1024b](https://github.com/roadiz/skeleton/commit/3c1024b008491b1a86e0add6327b6b4a9a44698e)) - Ambroise Maupate
+- Prefix all api_resource config file with `resources` - ([981b3ef](https://github.com/roadiz/skeleton/commit/981b3efd74784da97574df7a8cc8b266423bd537)) - Ambroise Maupate
+- Improved docker cron entrypoint - ([185aefd](https://github.com/roadiz/skeleton/commit/185aefd733eb95624c7ebe3730694e49b92bee9c)) - Ambroise Maupate
+
+### CI/CD
+
+- Removed php 8.1 from version matrix - ([3341faa](https://github.com/roadiz/skeleton/commit/3341faa38d6dae06332e9710bd1943af666c009f)) - Ambroise Maupate
+- Added php-unit configuration for Gitlab CI - ([0e5e3c9](https://github.com/roadiz/skeleton/commit/0e5e3c9ae82630bb7ae209d913fbc0ac24de64b6)) - Ambroise Maupate
+- Removed /var/www/html/var/secret volume - ([6fd4063](https://github.com/roadiz/skeleton/commit/6fd4063a90e3c0b5b95bd3cea48f9a66c9467c89)) - Ambroise Maupate
+
+### Documentation
+
+- Improved README and added new Makefile recipe - ([bc721ea](https://github.com/roadiz/skeleton/commit/bc721ea2e3b5429f7a1f3697e07623614b3a6776)) - Ambroise Maupate
+- Added dev and stop Make recipes - ([1d7f233](https://github.com/roadiz/skeleton/commit/1d7f23350a38ed39dcc4b649c40ece5a83b6d962)) - Ambroise Maupate
 
 ### Features
 
@@ -12,6 +32,14 @@ All notable changes to project will be documented in this file.
 - Allow sub Menu - ([0be1cde](https://github.com/roadiz/skeleton/commit/0be1cdeadae888cea647356818344d3cee86bad0)) - Ambroise Maupate
 - Added git-cliff configuration template - ([2d514a8](https://github.com/roadiz/skeleton/commit/2d514a84c5c92b3d50d961579d090bbcba671a53)) - Ambroise Maupate
 - Added git-cliff configuration template - ([bd0f2e8](https://github.com/roadiz/skeleton/commit/bd0f2e840dbd416a1be927af8ae881cc118dbb6d)) - Ambroise Maupate
+- Upgrade to ApiPlatform 3.2 - ([4455344](https://github.com/roadiz/skeleton/commit/44553441627473572043d78e12a24f2fc264018f)) - Ambroise Maupate
+- Added *LiipMonitorBundle* for health-checking API docker container - ([59fcb39](https://github.com/roadiz/skeleton/commit/59fcb39f85e39e10eb2653ee027c194117801cef)) - Ambroise Maupate
+- Added simple `HEALTHCHECK` command for docker containers - ([997bd4e](https://github.com/roadiz/skeleton/commit/997bd4e172e96ac13504173213e80b9c0a909823)) - Ambroise Maupate
+- Upgraded example node-types entities - ([5377feb](https://github.com/roadiz/skeleton/commit/5377feb1d7b37bd3ed8b28e98560195f55f24e5a)) - Ambroise Maupate
+
+### Refactor
+
+- Changed MenuLinkPathNormalizer.php method signature - ([d51461e](https://github.com/roadiz/skeleton/commit/d51461e89a184ffbb885e4aa59ab2e9b1efef6e3)) - Ambroise Maupate
 
 ## [2.2.1](https://github.com/roadiz/skeleton/compare/v2.2.0...v2.2.1) - 2023-12-12
 
@@ -256,8 +284,8 @@ All notable changes to project will be documented in this file.
 
 - **(Performances)** Added php.ini preload configuration - ([0e291fd](https://github.com/roadiz/skeleton/commit/0e291fdd038fe1a5c393c9b9e2cfadbc8a7c3679)) - Ambroise Maupate
 - Added /api/common_content endpoint example - ([f909aa7](https://github.com/roadiz/skeleton/commit/f909aa78446b56803b2f6ee888d124c6dac2837c)) - Ambroise Maupate
-- Added realms api resource configuration - ([9f2d035](https://github.com/roadiz/skeleton/commit/9f2d0350cf9072f9e1019eef0a70fdc9723feaf0)) - Ambroise Maupate
 - Additional CORS allowed headers - ([6501e2c](https://github.com/roadiz/skeleton/commit/6501e2c5dc62f849ea5b692917900871f01dca17)) - Ambroise Maupate
+- Added realms api resource configuration - ([9f2d035](https://github.com/roadiz/skeleton/commit/9f2d0350cf9072f9e1019eef0a70fdc9723feaf0)) - Ambroise Maupate
 
 ## [2.0.1](https://github.com/roadiz/skeleton/compare/2.0.0...2.0.1) - 2022-07-04