diff --git a/config/inc_roles.php b/config/inc_roles.php
index a29ef2d609fd97293a4e6b4bedeb38c0036a3b65..0db2b60f59aada087f0410e4b0911cda63fc0c10 100644
--- a/config/inc_roles.php
+++ b/config/inc_roles.php
@@ -18,6 +18,7 @@ return array(
         "page_build",
         "page_cleanup",
         "page_deploy",
+        "page_doc",
         "page_htmltest",
         "page_phase",
         "page_setup",
@@ -43,6 +44,7 @@ return array(
         "page_cleanup",
         "page_delete",
         "page_deploy",
+        "page_doc",
         "page_htmltest",
         "page_phase",
         "page_setup",
diff --git a/public_html/deployment/classes/actionlog.class.php b/public_html/deployment/classes/actionlog.class.php
index 8ae8693b9f5aab7a75c2d835b25af3e111f74c05..e09d1da94a77921fa207d134eb428f932c9d7630 100644
--- a/public_html/deployment/classes/actionlog.class.php
+++ b/public_html/deployment/classes/actionlog.class.php
@@ -58,7 +58,7 @@ class Actionlog {
         $this->_sProject = $sProject;
         $oUser=new user();
         if ($oUser->getUsername()) {
-            $this->_sIP = $_SERVER["REMOTE_ADDR"];
+            $this->_sIP = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : 'local';
             $this->_sUser = $oUser->getUsername() . " (web)";
         } else {
             $this->_sIP = 'local';
diff --git a/public_html/deployment/classes/messenger.class.php b/public_html/deployment/classes/messenger.class.php
index 91eda6c5775410c95b63272ddf72ea36033a82d1..589183a847c0e220cd8f13d21e1bcb0d9167bd1a 100644
--- a/public_html/deployment/classes/messenger.class.php
+++ b/public_html/deployment/classes/messenger.class.php
@@ -61,7 +61,7 @@ class messenger {
      */
     private function _sendToSlack(){
         if (array_key_exists('slack', $this->_aCfg)) {
-            require_once('./../vendor/shooker/shooker.php');
+            require_once(__DIR__ . '/../../vendor/shooker/shooker.php');
             $shkr = new Shooker();
             $shkr->setupIncoming($this->_aCfg['slack']['incomingurl']);
             $sUser=(array_key_exists('user', $this->_aCfg['slack'])? $this->_aCfg['slack']['user']: false);
diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php
index 62236b2ef7b5dbe1cdc2b84819347937f71a6612..054c8af52f74933a92b00e892318c01fcbb6bc1a 100644
--- a/public_html/deployment/classes/project.class.php
+++ b/public_html/deployment/classes/project.class.php
@@ -155,7 +155,7 @@ class project extends base {
             $sSlack=$this->_aPrjConfig['messenger']['slack'];
             $aConfig['slack']=array('incomingurl'=>$sSlack);
             foreach(array('user', 'icon') as $sKey){
-                if (array_key_exists($sKey, $this->_aConfig['messenger']['slack']['presets'][$sSlack])){
+                if (isset($this->_aConfig['messenger']['slack']['presets'][$sSlack][$sKey])){
                     $aConfig['slack'][$sKey]=$this->_aConfig['messenger']['slack']['presets'][$sSlack][$sKey];
                 }
             }
@@ -825,7 +825,7 @@ class project extends base {
         if ($this->_oVcs) {
             if (!method_exists($this->_oVcs, "cleanupCache")) {
                 // the version control class does not have this method
-                $this->log(__FUNCTION__ . " soory, Methos cleanupCache does not exist in this VCS class.");
+                $this->log(__FUNCTION__ . " sorry, Method cleanupCache does not exist in this VCS class.");
                 return '';
             }
             return $this->_oVcs->cleanupCache($iAge);
@@ -1455,10 +1455,10 @@ class project extends base {
         $this->_aConfig["id"] = $sId;
 
 
-        if ($this->_aConfig['projects']['json']['active']) {
+        if (isset($this->_aConfig['projects']['json']['active']) && $this->_aConfig['projects']['json']['active']) {
             $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
         }
-        if ($this->_aConfig['projects']['ldap']['active']) {
+        if (isset($this->_aConfig['projects']['ldap']['active']) && $this->_aConfig['projects']['ldap']['active']) {
             // TODO: read project after saving it - @see $this->saveConfig()
             $sQuery = '(&(objectclass=hieraSource)(documentIdentifier=' . $sId . '))';
             $aResult = $this->_ldapProjectSearch($sQuery);
@@ -2318,7 +2318,7 @@ class project extends base {
             $sBakFile = $this->_getConfigFile($sId) . ".ok";
             copy($sCfgFile, $sBakFile);
 
-            $bReturn = file_put_contents($sCfgFile, json_encode($aData));
+            $bReturn = file_put_contents($sCfgFile, json_encode($aData, JSON_PRETTY_PRINT));
             $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
         }
         // save in ldap
@@ -2342,7 +2342,7 @@ class project extends base {
 
             require_once("ldap.class.php");
             $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
-            // $oLdapIML->debugOn();
+            //$oLdapIML->debugOn();
             if (!$oLdapIML->DnExists($sDn)) {
                 if ($oLdapIML->objAdd($sDn, $aItem)) {
                     echo 'OK, created in LDAP.<br>';
diff --git a/public_html/deployment/classes/rollout_base.class.php b/public_html/deployment/classes/rollout_base.class.php
index 9df330a8cb3f3facac599a057ef7dd71df55663c..ee86f5de1eb3acea4f935351f1c0918ab9a1d80f 100644
--- a/public_html/deployment/classes/rollout_base.class.php
+++ b/public_html/deployment/classes/rollout_base.class.php
@@ -183,7 +183,7 @@ class rollout_base implements iRolloutplugin{
             
             
             $sMyPlaceholder=(isset($aDefaultValues[$sVarname]) 
-                                ? $aDefaultValues[$sVarname] 
+                                ? htmlentities($aDefaultValues[$sVarname]) 
                                 : (isset($aVarinfos['default']) ? $aVarinfos['default'] : 'N.A.')
                 );
             switch ($aVarinfos['type']) {
diff --git a/public_html/deployment/classes/user.class.php b/public_html/deployment/classes/user.class.php
index e8d0afe61eca50a16a37337cd9c0ec96ed1e5d3f..285834040774a04fd38d294710f4128400e4c4b3 100644
--- a/public_html/deployment/classes/user.class.php
+++ b/public_html/deployment/classes/user.class.php
@@ -201,7 +201,8 @@ class user {
      */
     public function showDenied(){
         return '<div class="alert alert-danger" role="alert">'
-        . ($this->_sUsername ? ' User: '.$this->_sUsername : ''
+        . ($this->_sUsername ? ' User: '.$this->_sUsername : '')
+        . ($this->_sUsername 
             ? t("class-user-error-deny-no-role").'<br>('.$this->_sLastCheckedPermission.')'
             : t("class-user-error-login-required")
         )
diff --git a/public_html/deployment/pages/act_doc.php b/public_html/deployment/pages/act_doc.php
index 040604c5afdf965eab34349b5a9f3684bafeef58..806a54da58e8f17bd31e19ded9bd27429d4ff32f 100644
--- a/public_html/deployment/pages/act_doc.php
+++ b/public_html/deployment/pages/act_doc.php
@@ -12,11 +12,23 @@
 
 require_once("./classes/classinfos.class.php");
 $aClasses = array(
+    "actionlog" => array("name" => "actionLog"),
+    "cache" => array("name" => "AhCache"),
+    "config-replacement" => array("name" => "configreplacement"),
+    "deploy-foreman" => array("name" => "deployForeman"),
+    "foremanapi" => array("name" => "ForemanApi"),
+    "formgen" => array("name" => "formgen"),
+    "htmlguielements" => array("name" => "htmlguielements"),
+    "ldap" => array("name" => "imlldap"),
+    "logger" => array("name" => "logger"),
+    "messenger" => array("name" => "messenger"),
+    "page" => array("name" => "Page"),
     "project" => array("name" => "project"),
     "projectlist" => array("name" => "projectlist"),
-    "actionlog" => array("name" => "Actionlog"),
-    "page" => array("name" => "Page"),
-    "formgen" => array("name" => "formgen"),
+    "rollout_base" => array("name" => "rollout_base"),
+    "user" => array("name" => "user"),
+    "vcs.git" => array("name" => "vcs"),
+
 );
 
 $sOut = '';
diff --git a/public_html/deployment/plugins/rollout/awx/rollout_awx.php b/public_html/deployment/plugins/rollout/awx/rollout_awx.php
index ff12d4c3c4e8280a452afb2924e31a753c75dc2d..2aa41d829b95f3ab65ca52cd68f38e32d80f173b 100644
--- a/public_html/deployment/plugins/rollout/awx/rollout_awx.php
+++ b/public_html/deployment/plugins/rollout/awx/rollout_awx.php
@@ -2,9 +2,9 @@
 
 /**
  * 
- * Rollout plugin - default
+ * Rollout plugin - awx
  * 
- * no action
+ * Run an Https POST request to AWX
  *
  * @author axel
  */
diff --git a/public_html/deployment/plugins/rollout/ssh/rollout_ssh.php b/public_html/deployment/plugins/rollout/ssh/rollout_ssh.php
index 66eaf98c61dc04d48ac07e8b8ba7cdda50def196..822d03756b0b43186e1ff21a0b49d6847c9c066e 100644
--- a/public_html/deployment/plugins/rollout/ssh/rollout_ssh.php
+++ b/public_html/deployment/plugins/rollout/ssh/rollout_ssh.php
@@ -2,9 +2,9 @@
 
 /**
  * 
- * Rollout plugin - default
+ * Rollout plugin - ssh
  * 
- * no action
+ * Run a SSH command on remote targets
  *
  * @author axel
  */
diff --git a/shellscripts/convert_projects_2_rollout-plugins.php b/shellscripts/convert_projects_2_rollout-plugins.php
new file mode 100644
index 0000000000000000000000000000000000000000..48535893c9eea1412a71a1f1d1ca60463ae41b19
--- /dev/null
+++ b/shellscripts/convert_projects_2_rollout-plugins.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * 
+ * CRONJOB
+ * deploy all queued packages
+ * 
+ */
+
+// http://iml:deployment@ci.iml.unibe.ch/deployment/?prj=ci&action=deploy&par3=preview&confirm=1
+
+$sDocroot = (dirname(__dir__)) . "/public_html";
+$processUser = posix_getpwuid(posix_geteuid());
+if ($processUser['name']=="root"){
+    die("Do not start the script as user root\n");
+};
+
+require_once("$sDocroot/deployment/classes/logger.class.php");
+global $oCLog;
+$oCLog = new logger();
+
+require_once("$sDocroot/../config/inc_projects_config.php");
+require_once("$sDocroot/deployment/inc_functions.php");
+require_once("$sDocroot/deployment/classes/project.class.php");
+
+$aSkipped=array();
+$aUntouched=array();
+
+// ----------------------------------------------------------------------
+// FUNCTIONS
+// ----------------------------------------------------------------------
+
+function getUrl($s){
+    return 'https://ci.iml.unibe.ch/deployment/'.$s.'/setup/';
+}
+
+
+// ----------------------------------------------------------------------
+// MAIN
+// ----------------------------------------------------------------------
+
+echo "\n";
+echo "===== IMLDEPLOYMENT - converter for rollout plugins\n";
+echo "\n";
+$oPrj1 = new project();
+
+foreach ($oPrj1->getProjects() as $sPrj) {
+    $oPrj = new project($sPrj);
+
+    echo "----- $sPrj:\n";
+    $aCfg=$oPrj->getConfig();
+
+    // NEXT STEPS:
+    // test if a pluin was set already...
+    if(isset($aCfg['deploy']['enabled_rollout_plugin'])){
+        echo "SKIP: Project uses rollout plugin [".$aCfg['deploy']['enabled_rollout_plugin']."]\n";
+    } else {
+        
+        echo "INFO: No rollout plugin is set - Project needs to be converted...\n";
+        $bSave=false;
+        
+        if (preg_match('/_se$/', $aCfg['label'])){
+            echo "UNTOUCHED: project ending with _se\n";
+            $aUntouched[]=$sPrj.' - SE project - '.getUrl($sPrj);
+            /*
+            if ($aCfg['deploy']['enabled_rollout_plugin']){
+                $bSave=false;
+                echo "  CONFLICT: rollout plugin was set to [".$aCfg['deploy']['enabled_rollout_plugin']."]\n";
+                echo "  \n";
+            }
+             * 
+             */
+        } else {
+            foreach (array_keys($aCfg['phases']) as $sPhase){
+                echo "--- phase $sPhase \n";
+                if ($aCfg['phases'][$sPhase]['hosts']){
+                    $bSave=true;
+                    echo "  TASK: target hosts detected: phases -> $sPhase -> hosts = " . $aCfg['phases'][$sPhase]['hosts'] . "\n";
+                    echo "  - set plugin [ssh] for rollout\n";
+                    $aCfg['deploy']['enabled_rollout_plugin']='ssh';
+                    echo "  - set hosts for ssh plugin phases -> $sPhase -> plugins -> rollout -> ssh -> hosts = ".$aCfg['phases'][$sPhase]['hosts']."\n";
+                    $aCfg['phases'][$sPhase]['plugins']['rollout']['ssh']['hosts']=$aCfg['phases'][$sPhase]['hosts'];
+                }
+            }
+            if(!$bSave){
+                echo "UNTOUCHED: No Deploy host was found.\n";
+                $aUntouched[]=$sPrj.' - no deploy host in any phase - '.getUrl($sPrj);    
+            }
+        }
+        
+        if($bSave){
+            echo "INFO: save new config\n";
+            $aCfg['id']=$sPrj;
+            if ($oPrj->saveConfig($aCfg)) {
+                echo "  OK, config was saved \n";
+            } else {
+                echo "  ERROR: config was NOT saved :-/ \n";
+                die("  Aborting\n\n");
+            }
+        } else {
+            echo "SKIP: do NOT saving config.\n";
+            $aSkipped[]=$sPrj;
+        }
+
+
+
+    }
+        
+
+    echo "\n";
+}
+
+echo "----------------------------------------------------------------------\n";
+echo "processed: ".count($oPrj1->getProjects())."\n";
+echo "skipped  : ".count($aSkipped)."\n";
+echo "untouched: ".count($aUntouched)." (watch them manually):\n";
+print_r($aUntouched);
+echo "done\n";