diff --git a/public_html/deployment/classes/actionlog.class.php b/public_html/deployment/classes/actionlog.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..788ca7198bcbde790c9eecea57333edebbce18b7
--- /dev/null
+++ b/public_html/deployment/classes/actionlog.class.php
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * class to log all project actions, ie. build, deploy etc.
+ *
+ * @author hahn
+ */
+class Actionlog {
+
+    private $_aLoglevels = array("info", "warning", "error", "success"); // array of valid loglevels
+    private $_sIP = false;
+    private $_sUser = false;
+    private $_sProject = false;
+    private $_sCreate = '
+        CREATE TABLE "logs" (
+          `id` INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL  UNIQUE ,
+          `time` DATETIME,
+          `loglevel` TEXT,
+          `ip` TEXT,
+          `user` TEXT,
+          `project` TEXT,
+          `action` TEXT,
+          `message` TEXT
+        )';
+
+    /**
+     * constructor - sets internal environment variables and checks existence 
+     * of the database
+     * @global array $aConfig    settings
+     * @param  string $sProject  project ID
+     */
+    public function __construct($sProject = false) {
+        global $aConfig;
+
+        $this->_dbfile = $aConfig['appRootDir'] . '/database/logs.db';
+        if (!file_exists($this->_dbfile)) {
+            $this->_createDb();
+        }
+
+        $this->_sProject = $sProject;
+        if (isset($_SERVER) && is_array($_SERVER)) {
+            $this->_sIP = $_SERVER["REMOTE_ADDR"];
+            $this->_sUser = $_SERVER["PHP_AUTH_USER"] . "(web)";
+        } else {
+            $this->_sIP = 'local';
+            $this->_sUser = get_current_user() . " (system)";
+        }
+    }
+
+    /**
+     * create sqlite database - called in constructor if the file does not exist
+     */
+    private function _createDb() {
+        return $this->_makeQuery($this->_sCreate);
+    }
+
+    /**
+     * execute a sql statement
+     * @param string $sSql sql statement
+     * @return database object
+     */
+    private function _makeQuery($sSql) {
+        // $this->_log(__FUNCTION__."($sSql)");
+        // echo "<pre>$sSql</pre>";
+        $db = new PDO("sqlite:" . $this->_dbfile);
+        $result = $db->query($sSql);
+        $db = NULL;
+        return $result;
+    }
+
+    /**
+     * add a log message
+     * @param string $sMessage   message
+     * @param string $sAction    project action; i.e. build, deploy, ...
+     * @param string $sLoglevel  loglevel
+     */
+    public function add($sMessage, $sAction = "", $sLoglevel = "info") {
+        if (array_search($sLoglevel, $this->_aLoglevels) === false) {
+            die(__class__ . ": loglevel $sLoglevel is invalid");
+        }
+        $sql = "INSERT INTO `logs` (`time`, `loglevel`, `ip`, `user`, `project` ,`action`, `message`)
+          VALUES(
+            '" . date("Y-m-d H:i:s") . "',
+            '" . $sLoglevel . "',
+            '" . $this->_sIP . "',
+            '" . $this->_sUser . "',
+            '" . $this->_sProject . "',
+            '" . $sAction . "',
+            '" . $sMessage . "'
+          );
+        ";
+        // echo $sql . "<br>";
+        $this->_makeQuery($sql);
+    }
+
+    /**
+     * get log data
+     * @param array $aFilter with the following keys:
+     *   'project' - filter by project; will be mixed with where (see next key)
+     *   'where' - where clausel - part behind "WHERE "
+     *   'order' - order clausel - part behind "ORDER BY "; default is "id DESC" (order by newest entries)
+     *   'limit' - limit clausel - part behind "LIMIT "
+     * @return array
+     */
+    public function getLogs($aFilter=array()) {
+        // var_dump(R::findAll( 'log' ));
+        $aReturn=array();
+        
+        $sSql='SELECT * from logs ';
+        $sWhere=false;
+        if (array_key_exists("where", $aFilter) && $aFilter["where"]){
+            $sWhere.=' WHERE (' . $aFilter["where"]. ') ';
+        }
+        if (array_key_exists("project", $aFilter) && $aFilter["project"]){
+            $sProjectWhere='`project`="'.$aFilter["project"].'"';
+            $sWhere.= $sWhere ? ' AND '. $sProjectWhere : 'WHERE ' . $sProjectWhere;
+        }
+        $sSql.=$sWhere;
+        
+        if (array_key_exists("order", $aFilter) && $aFilter["order"]){
+            $sSql.=' ORDER BY ' . $aFilter["order"];
+        } else {
+            $sSql.=' ORDER BY id DESC ';
+        }
+        if (array_key_exists("limit", $aFilter) && $aFilter["limit"]){
+            $sSql.=' LIMIT ' . $aFilter["limit"];
+        }
+        
+        foreach ($this->_makeQuery($sSql) as $row) {
+            for ($i=0; $i<=7; $i++){
+                unset($row[$i]);
+            }
+            $aReturn[]=$row;
+        }
+        return $aReturn;
+    }
+
+    /**
+     * render html code for a table with logs. The filter will be sent to
+     * getLogs method.
+     * @param array $aFilter with the following keys:
+     *   'project' - filter by project; will be mixed with where (see next key)
+     *   'where' - where clausel - part behind "WHERE "
+     *   'order' - order clausel - part behind "ORDER BY "; default is "id DESC" (order by newest entries)
+     *   'limit' - limit clausel - part behind "LIMIT "
+     * @return string
+     */
+    public function renderLogs($aFilter=array()){
+        $sReturn="";
+        $aData=$this->getLogs($aFilter);
+        if (!count($aData)){
+            $sReturn=t("empty");
+        } else {
+            $sReturn.='<thead><tr>';
+            foreach (array_keys($aData[0]) as $sRow){
+                $sReturn.='<th>'.$sRow.'</th>';
+            }
+            $sReturn.='</tr></thead>';
+            $sReturn.='<tbody>';
+            foreach ($aData as $aRow){
+                $sReturn.='<tr class="loglevel-'.$aRow["loglevel"].'">';
+                foreach ($aRow as $sValue){
+                    $sReturn.='<td>'.$sValue.'</td>';
+                }
+                $sReturn.='</tr>';
+            }
+            $sReturn.='</tbody>';
+            $sReturn='<table class="table">'.$sReturn.'</table>';
+        }
+        
+        $sReturn='<br><hr>'
+                . '<h3>Action-Log</h3><p>Filter: '.print_r($aFilter, true).')</p>'
+                . $sReturn;
+        
+        return $sReturn;
+    }
+}