diff --git a/.gitignore b/.gitignore
index 2b083ce9aec60dee499bc227be0e5fa04f61d3c0..e555f5407e61381b8b0b15afedc5027fb1825ae4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,5 @@ nbproject
 /public_html/deployment/pages/act_jstest.php
 /public_html/deployment/classes/html-adminltetest.tpl.php
 /public_html/deployment/adminlte/
-/config/inc_user2projects.php
\ No newline at end of file
+/config/inc_user2projects.php
+/shellscripts/spooler/
\ No newline at end of file
diff --git a/hooks/templates/inc_projects_config.php.erb b/hooks/templates/inc_projects_config.php.erb
index a113ddd6381fa7a7d01ebeb51f056f0db9011457..46c8609da3fbf8c27827041bd3423eb086c2ce9d 100644
--- a/hooks/templates/inc_projects_config.php.erb
+++ b/hooks/templates/inc_projects_config.php.erb
@@ -67,8 +67,8 @@ $aConfig = array(
         'ldap' => array(
             'server'       => '<%= @replace["ldap-url"] %>',
             'port'         => 636,
-            'DnLookupUser' => '<%= @replace["ldap-user"] %>',
-            'PwLookupUser' => '<%= @replace["ldap-password"] %>',
+            'DnLdapUser' => '<%= @replace["ldap-user"] %>',
+            'PwLdapUser' => '<%= @replace["ldap-password"] %>',
             'DnUserNode'   => '<%= @replace["ldap-dn-user"] %>',
             'DnAppNode'    => '<%= @replace["ldap-dn-apps"] %>',
             'debugLevel'   => 0,
diff --git a/public_html/deployment/classes/ldap.class.php b/public_html/deployment/classes/ldap.class.php
index 3dbb621dce8dda67c6e80b0dd0e3f269177483ca..d75e5971af70b0d0fae5d596a3cc3bba6f90c2a7 100644
--- a/public_html/deployment/classes/ldap.class.php
+++ b/public_html/deployment/classes/ldap.class.php
@@ -200,7 +200,41 @@ class imlldap {
     // ----------------------------------------------------------------------
     // ldap highlevel functions
     // ----------------------------------------------------------------------
+    
+    /**
+     * check if a DN already exists; return is true/ false
+     * @param string  $sDn  DN to check
+     * @return boolean
+     */
+    public function DnExists($sDn) {
+        $aData=$this->searchDn($sDn, '(&(objectclass=top))', $aAttributesToGet=array("*"));
+        return is_array($aData);
+    }
+
+    /**
+     * search in ldap directory and get result as array
+     * 
+     * @param string  $sSearchFilter     filter in ldap filter syntax
+     * @param array   $aAttributesToGet  flat array of attributes to fetch
+     * @return array
+     */
+    public function searchDn($sDn, $sSearchFilter, $aAttributesToGet=array("*")) {
+        if (!$this->_ldapBind) {
+            $this->bind($this->_aLdap['DnLdapUser'], $this->_aLdap['PwLdapUser']);
+        }
+    
+        $this->_w(__FUNCTION__ . ' DN = '.$sDn . ' filter = '.$sSearchFilter);
+        
+        $oLdapSearch = ldap_search(
+                $this->_ldapConn, 
+                $sDn, 
+                $sSearchFilter, 
+                $aAttributesToGet
+        );
 
+        $aItems = $oLdapSearch?ldap_get_entries($this->_ldapConn, $oLdapSearch):false;
+        return $aItems;
+    }
     /**
      * search in ldap directory and get result as array
      * 
@@ -208,7 +242,7 @@ class imlldap {
      * @param array   $aAttributesToGet  flat array of attributes to fetch
      * @return array
      */
-    public function search($sSearchFilter, $aAttributesToGet=array("*")) {
+    public function searchUser($sSearchFilter, $aAttributesToGet=array("*")) {
         if (!$this->_ldapBind) {
             $this->bind($this->_aLdap['DnLdapUser'], $this->_aLdap['PwLdapUser']);
         }
@@ -247,7 +281,7 @@ class imlldap {
         }
         $sSearchFilter='(&'.$sSearchFilter.')';
         
-        $aItems = $this->search($sSearchFilter, $aAttributesToGet);
+        $aItems = $this->searchUser($sSearchFilter, $aAttributesToGet);
 
         if(count($aItems)==2){
             $this->_w(__FUNCTION__ . ' OK: I got a single result: ' . print_r($aItems[0],1) );
@@ -307,7 +341,11 @@ class imlldap {
         if (!$this->_ldapBind) {
             $this->bind($this->_aLdap['DnLdapUser'], $this->_aLdap['PwLdapUser']);
         }
-        return ldap_add($this->_ldapConn, $sDn, $aItem);
+        if (!ldap_add($this->_ldapConn, $sDn, $aItem)){
+            $this->_w(__FUNCTION__ . ' failed with er error ' . ldap_error($this->_ldapConn));
+            return false;
+        }
+        return true;
     }
     
     /**
diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php
index 282bcfb66c6f40bdca5fffa068a98095e8280435..0e3ed265974f3fb25b7f59a877babe2696818a5d 100644
--- a/public_html/deployment/classes/project.class.php
+++ b/public_html/deployment/classes/project.class.php
@@ -1101,18 +1101,83 @@ class project extends base {
         $this->_sProcessTempOut = $sNewTempfile;
         return $this->_sProcessTempOut;
     }
+    
+        /**
+         * get projects from ldap; it returns ldap search items with cn as 
+         * array key.
+         * 
+         * @return array
+         */
+        private function _ldapProjectSearch($sSearchFilter) {
+            $aReturn = array();
+            require_once("ldap.class.php");
+            $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
+            // $oLdapIML->debugOn();
+            $aResultsIml = $oLdapIML->searchDn(
+                $this->_aConfig['projects']['ldap']['DnProjects'],
+                $sSearchFilter, 
+                array("*")
+            );
+            if (!$aResultsIml['count']) {
+                return false;
+            }
+            $oLdapIML->close();
+
+            /*
+            unset($aResultsIml['count']);
+            foreach ($aResultsIml as $aItem) {
+                $aReturn[$aItem['cn'][0]] = array(
+                    'dn' => $aItem['dn'],
+                    'cn' => $aItem['cn'][0],
+                    '_description' => $aItem['description'][0],
+                    'title' => $sTitle,
+                    'description' => $sDescription,
+                );
+            }
+            $oLdapIML->close();
+            ksort($aReturn);
+            return $aReturn;
+             * 
+             */
+            return $aResultsIml;
+        }
 
     /**
-     * apply a config
-     * @param array $aConfig
+     * load config of a project
      * @return boolean
      */
     public function setProjectById($sId) {
-        global $aConfig;
+        if ($sId !== preg_replace('/[^a-z0-9\-\_]/i', '', $sId)){
+            echo "ERROR: invalid syntax in project ID: $sId<br>";
+            return false;
+        }
         $this->_aPrjConfig = array();
         $this->_aConfig["id"] = $sId;
 
-        $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
+        
+        if ($this->_aConfig['projects']['json']['active']){
+            $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
+        }
+        if ($this->_aConfig['projects']['ldap']['active']){
+            // TODO: read project after saving it - @see $this->saveConfig()
+            $sQuery='(&(objectclass=hieraSource)(documentIdentifier='.$sId.'))';
+            $aResult=$this->_ldapProjectSearch($sQuery);
+            // echo '<pre>$aResult = ' . print_r($aResult, 1) . '</pre>';
+            if (is_array($aResult) 
+                    && $aResult[0]
+                    && array_key_exists('hieradata',$aResult[0])
+            ){
+                foreach ($aResult[0]['hieradata'] as $sLine){
+                    // echo $sLine.'<br>';
+                    if(preg_match('/^cfg=/', $sLine)){
+                        
+                        // echo $sLine.'<br>';
+                        $this->_aPrjConfig = json_decode(preg_replace('/^cfg=/', '', $sLine), 1);
+                    }
+                }
+            }
+            // return $this->objAdd($sDn, $aItem);
+        }
 
         // $aData=json_decode(file_get_contents($this->_getConfigFile($sId)), true);
         // echo "<pre>" . print_r($aData, true) . "</pre>";
@@ -1871,13 +1936,60 @@ class project extends base {
                 unset($aData[$s]);
         }
 
-        // echo "IST <pre>" . print_r($this->_aPrjConfig, true) . "</pre>"; echo "NEU <pre>" . print_r($aData, true) . "</pre>"; die();
-        // make a backup of a working config
-        $sCfgFile = $this->_getConfigFile($sId);
-        $sBakFile = $this->_getConfigFile($sId) . ".ok";
-        copy($sCfgFile, $sBakFile);
+        // save json file
+        if ($this->_aConfig['projects']['json']['active']){
+            // echo "IST <pre>" . print_r($this->_aPrjConfig, true) . "</pre>"; echo "NEU <pre>" . print_r($aData, true) . "</pre>"; die();
+            // make a backup of a working config
+            $sCfgFile = $this->_getConfigFile($sId);
+            $sBakFile = $this->_getConfigFile($sId) . ".ok";
+            copy($sCfgFile, $sBakFile);
 
-        $bReturn = file_put_contents($sCfgFile, json_encode($aData));
+            $bReturn = file_put_contents($sCfgFile, json_encode($aData));
+            $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
+        }
+        // save in ldap
+        if ($this->_aConfig['projects']['ldap']['active']){
+            // TODO: 
+            echo "TODO: save in LDAP<br><pre>" . print_r($aData, 1) ."</pre>";
+            
+            
+            $sDn='documentIdentifier='.$sId.','.$this->_aConfig['projects']['ldap']['DnProjects'];
+            $aItem=array(
+                'objectClass' => array(
+                    'document',
+                    'hieraSource',
+                    'top',
+                ),
+                'hieraData' => array(
+                    'cfg='.json_encode($aData),
+                    'updated='.date("Y-m-d H:i:s") . ' by ' . $this->oUser->getUsername(),
+                )
+            );
+            
+            require_once("ldap.class.php");
+            $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
+            // $oLdapIML->debugOn();
+            if (!$oLdapIML->DnExists($sDn)){            
+                if ($oLdapIML->objAdd($sDn,$aItem)){
+                    echo 'OK, created in LDAP.<br>';
+                    $bReturn=true;
+                } else {
+                    echo 'ERROR, DN '.$sDn.' was not created in LDAP :-/<br>';
+                    $bReturn=false;
+                }
+            } else {
+                if ($oLdapIML->objUpdate($sDn,$aItem)){
+                    echo 'OK, updated in LDAP.<br>';
+                    $bReturn=true;
+                } else {
+                    echo 'ERROR, DN '.$sDn.' was not updated in LDAP :-/<br>';
+                    $bReturn=false;
+                }
+            }
+            $oLdapIML->close();
+            
+        }
+            
         $this->_logaction(t('finished') . " saveConfig(...)", __FUNCTION__, "success");
         $this->setProjectById($sId);
 
diff --git a/public_html/deployment/classes/userauth.ldap.class.php b/public_html/deployment/classes/userauth.ldap.class.php
index ac3086a23689673d06c2961ef0e51dba50a88933..07c440ad5dcdba27fd6b7fe1548f018b78da33f2 100644
--- a/public_html/deployment/classes/userauth.ldap.class.php
+++ b/public_html/deployment/classes/userauth.ldap.class.php
@@ -1,7 +1,7 @@
 <?php
 
 require_once("userauth.interface.php");
-require_once("ldap.class.php");        
+require_once("ldap.class.php");
 
 /**
  * user authentication :: LDAP
diff --git a/public_html/deployment/main.css b/public_html/deployment/main.css
index 5b576d9adb927ad098103bd2688dac1333a35630..0653462d627f98769c801d94238901eaf1c93f4d 100644
--- a/public_html/deployment/main.css
+++ b/public_html/deployment/main.css
@@ -36,7 +36,7 @@ body{padding-top: 0;}
             border-bottom-left-radius: 0.5em;
 }
 #content{
-    margin: 2em 2% 0;
+    margin: 0 2% 0;
     border-left: 0px solid #ccc;
     padding: 1em;
     box-shadow: 0 0 15px #eee;
@@ -68,6 +68,7 @@ h2.action{
     height: 2.7em; margin: 0 0 1em 0;
     font-size: 250%; 
 }
+/*
 h2.accept{background-image: url("/deployment/images/nuvola64x64/apps/korganizer.png");}
 h2.build{background-image: url("/deployment/images/nuvola64x64/apps/kthememgr.png");}
 h2.cleanup{background-image: url("/deployment/images/nuvola64x64/apps/kasteroids.png");}
@@ -76,6 +77,7 @@ h2.prjhome{background-image: url("/deployment/images/nuvola64x64/apps/kdict.png"
 h2.phase{background-image: url("/deployment/images/nuvola64x64/apps/kreversi.png");}
 h2.setup{background-image: url("/deployment/images/nuvola64x64/apps/kcmsystem.png");}
 h2.login{background-image: url("/deployment/images/nuvola64x64/apps/kgpg.png");}
+*/
 h3{color:#444; margin-top: 3em;}
 h3:first-child{margin-top: 0;}
 
@@ -137,7 +139,7 @@ td.highlight{background:rgba(255,220,50,0.5) !important;}
 
 a.info { border-bottom: 1px dotted; padding-bottom: 2px;}
 a.info:hover { text-decoration: none; background: #fff;}
-a.info>span{ display: none; position: absolute; margin-top: -1em; margin-left: -100px; background: #fff; padding: 0.5em; box-shadow: 0 0 10px #888; text-align: left;
+a.info>span{ display: none; position: absolute; margin-top: -1em; margin-left: -130px; background: #fff; padding: 0.5em; box-shadow: 0 0 10px #888; text-align: left;
              z-index: 100;
 }
 a.info>span.left{margin-left: 0;}