diff --git a/app.ts b/app.ts
index b11b9cc0108b197e654af6e78c642049021c5aab..f0b42698cf4df86c3d7f6bcce0f91917116da994 100644
--- a/app.ts
+++ b/app.ts
@@ -1,77 +1,70 @@
 import express from 'express'
 import path from 'path'
-import passport from 'passport'
 import morgan from 'morgan'
 import cookieParser from 'cookie-parser'
 import bodyParser from 'body-parser'
-import session from 'express-session'
-import flash from 'express-flash'
-import fileUpload from 'express-fileupload'
-//import helmet from 'helmet'
+import helmet from 'helmet'
 import compression from 'compression'
 
-var env = process.env.NODE_ENV || 'testing'
+const env = process.env.NODE_ENV ?? 'development'
 const config = require('./config/config')[env]
-const lang = 'DE';
+const lang = 'DE'
 
-var app = express()
+const app = express()
 app.set('port', config.app.port)
-app.set('views', __dirname + '/views')
+app.set('views', path.join(__dirname, '/views'))
 app.set('view engine', 'pug')
 
-//app.use(helmet())
+// app.use(helmet())
 app.use(compression())
 app.use(morgan('combined'))
 app.use(cookieParser())
 app.use(bodyParser.json())
-app.use(bodyParser.urlencoded({extended: false}))
+app.use(bodyParser.urlencoded({ extended: false }))
 app.use(express.static(path.join(__dirname, 'public')))
-app.use(session(
-    {
-        resave: true,
-        saveUninitialized: true,
-        //secret: config.app.sessionSecret
-        secret: 'thisisasecret-thisisasecret-thisisasecret'
-    }
-))
-app.use(passport.initialize())
-app.use(passport.session())
-app.use(flash())
-app.use((req, res, next) => {
-    res.locals.errors = req.flash("error")
-    res.locals.successes = req.flash("success")
-    next()
-})
-// enable files upload
-app.use(fileUpload({
-    createParentPath: true,
-    limits: { 
-      fileSize: 1000000 // 1 MB max. file size
-    }
-}))
+
+app.use(
+  helmet.contentSecurityPolicy({
+    useDefaults: true,
+    directives: {
+      'font-src': ["'self'", 'https://use.fontawesome.com'],
+      'img-src': ["'self'", 'https://transfer.hft-stuttgart.de'],
+      'script-src': ["'self'", 'https://code.jquery.com/jquery-3.3.1.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js'],
+      'style-src': ["'self'", 'https://use.fontawesome.com/releases/v5.8.2/css/all.css'],
+      'frame-src': ["'self'"]
+    },
+    reportOnly: true
+  })
+)
+app.use(compression())
+app.use(morgan('combined'))
+app.use(cookieParser())
+app.use(bodyParser.json())
+app.use(bodyParser.urlencoded({ extended: false }))
+app.use(express.static(path.join(__dirname, 'public')))
+
 // caching disabled for every route
 // NOTE: Works in Firefox and Opera. Does not work in Edge
-app.use(function(req, res, next) {
-    res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
-    next()
+app.use(function (req, res, next) {
+  res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
+  next()
 })
-  
-require('./routes/project')(app, lang)
-  
+
+require('./routes/project')(app)
+
 // Handle 404
-app.use(function (req:any, res:any) {
-    res.status(404).render(lang+'/404')
+app.use(function (req: any, res: any) {
+  res.status(404).render(lang + '/404')
 })
-  
+
 // Handle 500 - any server error
-app.use(function (err:any, req:any, res:any, next:any) {
-    console.error(err.stack)
-    res.status(500).render(lang+'/500', {
-      error: err
-    })
+app.use(function (err: any, req: any, res: any, next: any) {
+  console.error(err.stack)
+  res.status(500).render(lang + '/500', {
+    error: err
+  })
 })
-  
+
 app.listen(app.get('port'), function () {
-    console.log('Project Page listening on port ' + app.get('port'))
-    console.log(__dirname)
-})
\ No newline at end of file
+  console.log('Project Page listening on port ' + String(app.get('port')))
+})
diff --git a/config/config.ts b/config/config.ts
index 7fa7d72df0b0ac69ae35728fb1fdd00b4e9c2684..0692d55b0fe58b9d10e6f85d7e04ebf3648172c9 100644
--- a/config/config.ts
+++ b/config/config.ts
@@ -2,34 +2,34 @@ module.exports = {
   development: {
     app: {
       name: 'Project Page Manager',
-      port: process.env.PORT || 8888,
+      port: process.env.PORT ?? 8888,
       sessionSecret: 'thisisasecret-thisisasecret-thisisasecret'
     },
     passport: {
       strategy: 'saml',
       saml: {
-        path: process.env.SAML_PATH || '/saml/SSO',
-        entryPoint: process.env.SAML_ENTRY_POINT || 'saml entry URL',
+        path: process.env.SAML_PATH ?? '/saml/SSO',
+        entryPoint: process.env.SAML_ENTRY_POINT ?? 'saml entry URL',
         issuer: 'saml issuer URL',
         logoutUrl: 'saml Logout URL'
       }
     },
     database: {
-      user: 'usernamedb',          // DB username
-      password: 'passworddb',  // DB password
-      port: 3306,                 // MySQL port
-      dbUser: 'userdb',           // User DB
+      user: 'usernamedb', // DB username
+      password: 'passworddb', // DB password
+      port: 3306, // MySQL port
+      dbUser: 'userdb', // User DB
       host_project: 'localhost', // local
-      dbProject: 'projectdb'     // Project DB
+      dbProject: 'projectdb' // Project DB
     },
     mailer: {
-      host: 'mailhost',  // hostname
-      secureConnection: false,        // TLS requires secureConnection to be false
-      port: 587,                      // port for secure SMTP
+      host: 'mailhost', // hostname
+      secureConnection: false, // TLS requires secureConnection to be false
+      port: 587, // port for secure SMTP
       authUser: 'usernamemail',
       authPass: 'passwordmail',
       tlsCiphers: 'SSLv3',
-      from: 'email_from',
+      from: 'email_from'
     },
     gitlab: {
       token_readWriteProjects: 'putyourtokenhere'
@@ -38,34 +38,34 @@ module.exports = {
   testing: {
     app: {
       name: 'Project Page Manager',
-      port: process.env.PORT || 8888,
+      port: process.env.PORT ?? 8888,
       sessionSecret: 'thisisasecret-thisisasecret-thisisasecret'
     },
     passport: {
       strategy: 'saml',
       saml: {
-        path: process.env.SAML_PATH || '/saml/SSO',
-        entryPoint: process.env.SAML_ENTRY_POINT || 'saml entry URL',
+        path: process.env.SAML_PATH ?? '/saml/SSO',
+        entryPoint: process.env.SAML_ENTRY_POINT ?? 'saml entry URL',
         issuer: 'saml issuer URL',
         logoutUrl: 'saml Logout URL'
       }
     },
     database: {
-      user: 'usernamedb',          // DB username
-      password: 'passworddb',  // DB password
-      port: 3306,                 // MySQL port
-      dbUser: 'userdb',           // User DB
+      user: 'usernamedb', // DB username
+      password: 'passworddb', // DB password
+      port: 3306, // MySQL port
+      dbUser: 'userdb', // User DB
       host_project: 'localhost', // local
-      dbProject: 'projectdb'     // Project DB
+      dbProject: 'projectdb' // Project DB
     },
     mailer: {
-      host: 'mailhost',  // hostname
-      secureConnection: false,        // TLS requires secureConnection to be false
-      port: 587,                      // port for secure SMTP
+      host: 'mailhost', // hostname
+      secureConnection: false, // TLS requires secureConnection to be false
+      port: 587, // port for secure SMTP
       authUser: 'usernamemail',
       authPass: 'passwordmail',
       tlsCiphers: 'SSLv3',
-      from: 'email_from',
+      from: 'email_from'
     },
     gitlab: {
       token_readWriteProjects: 'putyourtokenhere'
diff --git a/config/dbconn.ts b/config/dbconn.ts
index 1073e16ae6956939d60d2f5926362206a0a4dc52..8132d60db9da3d8b1aa1be64cff442ae6e05c42f 100644
--- a/config/dbconn.ts
+++ b/config/dbconn.ts
@@ -1,40 +1,40 @@
 import mysql from 'mysql2'
 
-var env = process.env.NODE_ENV || 'development';
+const env = process.env.NODE_ENV ?? 'development'
 const config = require('./config')[env]
 
 // ==== USER ACOOUNT DB CONNECTION ====
-var userConnection = mysql.createConnection({
-    host: config.database.host,
-    user: config.database.user,
-    password: config.database.password,
-    port: config.database.port,
-    database: config.database.dbUser,
-    multipleStatements: true
+const userConnection = mysql.createConnection({
+  host: config.database.host,
+  user: config.database.user,
+  password: config.database.password,
+  port: config.database.port,
+  database: config.database.dbUser,
+  multipleStatements: true
 })
 
-userConnection.connect(function(err) {
-    if (err) throw err;
+userConnection.connect(function (err) {
+  if (err != null) throw err
 })
-userConnection.query('USE '+config.database.dbUser)
+userConnection.query('USE ' + String(config.database.dbUser))
 
 // ==== PROJECT DB CONNECTION ====
-var projectConnection = mysql.createConnection({
-    host: config.database.host_project,
-    user: config.database.user,
-    password: config.database.password,
-    port: config.database.port,
-    database: config.database.dbProject
+const projectConnection = mysql.createConnection({
+  host: config.database.host_project,
+  user: config.database.user,
+  password: config.database.password,
+  port: config.database.port,
+  database: config.database.dbProject
 })
 
-projectConnection.connect(function(err) {
-    if (err) throw err;
+projectConnection.connect(function (err) {
+  if (err != null) throw err
 })
-projectConnection.query('USE '+config.database.dbProject)
+projectConnection.query('USE ' + String(config.database.dbProject))
 
-var connection = {
-    user: userConnection,
-    project: projectConnection
+const connection = {
+  user: userConnection,
+  project: projectConnection
 }
 
-export = connection
\ No newline at end of file
+export = connection
diff --git a/controller/controller.ts b/controller/controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..34a3e178759167736a5529c4e59d229ae30fd0a3
--- /dev/null
+++ b/controller/controller.ts
@@ -0,0 +1,242 @@
+import helpers from '../functions/helpers'
+import gitlab from '../functions/gitlab'
+import https from 'https'
+
+const dbconn = require('../config/dbconn')
+const lang = 'DE'
+
+const controller = {
+  getAllMailinglists: async function () {
+    try {
+      const rows: any = await dbconn.project.promise().query('CALL getAllLists')
+      console.log(rows)
+      if (rows[0][0]) {
+        return rows[0][0]
+      } else { return null }
+    } catch (err) {
+      console.error(err)
+    }
+  },
+  getProjectOverviewById: async function (projectId: number) {
+    try {
+      const rows: any = await dbconn.project.promise().query('CALL GetProjectInformationByProjectID(' + projectId + ')')
+      if (rows[0][0]) {
+        return rows[0][0]
+      } else { return null }
+    } catch (err) {
+      console.error(err)
+    }
+  },
+  getProjectImagesById: async function (projectId: number) {
+    try {
+      const rows: any = await dbconn.project.promise().query('CALL getImagesByProjectID(' + projectId + ')')
+      if (rows[0][0]) {
+        return rows[0][0]
+      } else { return null }
+    } catch (err) {
+      console.error(err)
+    }
+    return null
+  },
+  showHome: function (res: any) {
+    res.render(lang + '/project/project-simplified')
+  },
+  showMailingList: async function (res: any) {
+    const mailList = await controller.getAllMailinglists()
+    const allMailingLists: any = [] // JSON object
+    if (mailList) {
+      for (let i = 0; i < mailList.length; i++) {
+        // add data to JSON object
+        allMailingLists.push({
+          id: mailList[i].id,
+          name: mailList[i].name,
+          src: mailList[i].src,
+          projectstatus: mailList[i].projectstatus,
+          project_title: mailList[i].project_title,
+          keywords: mailList[i].keywords
+        })
+      }
+    }
+    res.render(lang + '/project/mailinglists', {
+      mailinglists: allMailingLists
+    })
+  },
+  showProjOverview: async function (req: any, res: any, next: any) {
+    const projectId = req.query.projectID
+    const projectOverview = await controller.getProjectOverviewById(projectId)
+
+    if (!projectId || projectOverview.length === 0) {
+      next()
+    } else {
+      const partnerWebsites = helpers.stringToArray(projectOverview[0].partner_website)
+      const partnerNames = helpers.stringToArray(projectOverview[0].partner_name)
+      const awardSites = helpers.stringToArray(projectOverview[0].award_website)
+      const awardNames = helpers.stringToArray(projectOverview[0].award_name)
+      const sponsorWebsites = helpers.stringToArray(projectOverview[0].sponsor_website)
+      const sponsorImgs = helpers.stringToArray(projectOverview[0].sponsor_img)
+      const sponsorNames = helpers.stringToArray(projectOverview[0].sponsor_name)
+
+      const projectImages = await controller.getProjectImagesById(projectId)
+      res.render(lang + '/project/projectOverview', {
+        projectOV: projectOverview,
+        projectImgs: projectImages,
+        partnerWS: partnerWebsites,
+        partnerN: partnerNames,
+        awardWS: awardSites,
+        awardN: awardNames,
+        sponsorWS: sponsorWebsites,
+        sponsorIMG: sponsorImgs,
+        sponsorN: sponsorNames
+      })
+    }
+  },
+  showProjData: async function (req: any, res: any) {
+    const projectArr: any = []
+    let isProject = true
+    let firstId = 0
+    const orderKeyword = req.query.sort
+
+    while (isProject) {
+      const projects: any = await gitlab.getProjects(100, firstId)
+      const projectData = projects.data[0]
+
+      if (projectData.length === 0) {
+        isProject = false
+      } else {
+        for (let i = 0; i < projectData.length; i++) {
+          // M4_LAB logo for all projects that do not have logo
+          if (projectData[i].avatar_url == null) {
+            projectData[i].avatar_url = 'https://m4lab.hft-stuttgart.de/img/body/M4_LAB_LOGO_NO_TEXT.png'
+          }
+          // for all projects that have no description
+          if (projectData[i].description === '') {
+            projectData[i].description = '- no description -'
+          }
+
+          const project = {
+            logo: projectData[i].avatar_url,
+            name: projectData[i].name,
+            weburl: projectData[i].web_url,
+            desc: projectData[i].description,
+            keywords: projectData[i].tag_list,
+            createdAt: projectData[i].created_at,
+            lastUpdatedAt: projectData[i].last_activity_at
+          }
+          projectArr.push(project)
+        }
+        firstId = projectData[projectData.length - 1].id
+      }
+
+      // MLAB-576
+      if (orderKeyword === 'created_at') {
+        projectArr.sort((a: any, b: any) => {
+          const aDate: any = new Date(a.createdAt)
+          const bDate: any = new Date(b.createdAt)
+          return bDate - aDate
+        })
+      } else if (orderKeyword === 'updated_at') {
+        projectArr.sort((a: any, b: any) => {
+          const aDate: any = new Date(a.lastUpdatedAt)
+          const bDate: any = new Date(b.lastUpdatedAt)
+          return bDate - aDate
+        })
+      } else { // default, sorted by name
+        projectArr.sort((a: any, b: any) => {
+          const fa = a.name.toLowerCase()
+          const fb = b.name.toLowerCase()
+
+          if (fa < fb) return -1
+          if (fa > fb) return 1
+          return 0
+        })
+      }
+    }
+
+    res.render(lang + '/project/projectList', {
+      project: projectArr
+    })
+  },
+  showProjInformations: async function (req: any, res: any) {
+    const pagesArr: any = []
+    let isProject = true
+    let firstId = 0
+    const orderKeyword = req.query.sort
+
+    while (isProject) {
+      const projects: any = await gitlab.getProjects(100, firstId)
+      const pagesData = projects.data[1]
+
+      if (pagesData.length === 0) {
+        isProject = false
+      } else {
+        for (let i = 0; i < pagesData.length; i++) {
+          const status = await gitlab.getLatestPipelineStatus(pagesData[i].id)
+          if (status) {
+            // M4_LAB logo for all projects that do not have logo
+            if (pagesData[i].avatar_url == null) {
+              pagesData[i].avatar_url = 'https://m4lab.hft-stuttgart.de/img/body/M4_LAB_LOGO_NO_TEXT.png'
+            }
+            // for all projects that have no description
+            if (pagesData[i].description === '') {
+              pagesData[i].description = '- no description -'
+            }
+            // https://transfer.hft-stuttgart.de/pages/EIGENTUEMER/PROJEKTNAME/
+            pagesData[i].web_url = 'https://transfer.hft-stuttgart.de/pages/' + String(pagesData[i].namespace.path) + '/' + String(pagesData[i].name) + '/'
+            // remove 'website' from tag list
+            const index = pagesData[i].tag_list.indexOf('website')
+            if (index > -1) {
+              pagesData[i].tag_list.splice(index, 1)
+            }
+
+            // fill in pagesArr
+            const pages = {
+              logo: pagesData[i].avatar_url,
+              name: pagesData[i].name,
+              weburl: pagesData[i].web_url,
+              desc: pagesData[i].description,
+              keywords: pagesData[i].tag_list,
+              createdAt: pagesData[i].created_at,
+              lastUpdatedAt: pagesData[i].last_activity_at
+            }
+            https.get(pagesData[i].web_url, function (response: any) {
+              if (response.statusCode >= 200 && response.statusCode <= 299) {
+                pagesArr.push(pages)
+              }
+            })
+          }
+        }
+        firstId = pagesData[pagesData.length - 1].id
+      }
+
+      // MLAB-576
+      if (orderKeyword === 'created_at') {
+        pagesArr.sort((a: any, b: any) => {
+          const aDate: any = new Date(a.createdAt)
+          const bDate: any = new Date(b.createdAt)
+          return bDate - aDate
+        })
+      } else if (orderKeyword === 'updated_at') {
+        pagesArr.sort((a: any, b: any) => {
+          const aDate: any = new Date(a.lastUpdatedAt)
+          const bDate: any = new Date(b.lastUpdatedAt)
+          return bDate - aDate
+        })
+      } else { // default, sorted by name
+        pagesArr.sort((a: any, b: any) => {
+          const fa = a.name.toLowerCase()
+          const fb = b.name.toLowerCase()
+
+          if (fa < fb) return -1
+          if (fa > fb) return 1
+          return 0
+        })
+      }
+    }
+
+    res.render(lang + '/project/pagesList', {
+      pages: pagesArr
+    })
+  }
+}
+
+export = controller
diff --git a/functions/gitlab.ts b/functions/gitlab.ts
index ca5928d4e5d4276aa08019fc472124fbe33c1716..bdff7412247bb3e2d29d1ded7d775363a4237836 100644
--- a/functions/gitlab.ts
+++ b/functions/gitlab.ts
@@ -1,43 +1,44 @@
 import axios from 'axios'
 
-var gitlab = {
-    getProjects: async function(perPage:number, idAfter:number) {
-        try {
-            let projects = await axios({
-                method: 'get',
-                url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects?visibility=public&pagination=keyset&per_page='+perPage+'&order_by=id&sort=asc&id_after='+idAfter
-            })
-            let data = projects.data
-            let reposArr = []
-            let pagesArr = []
-            for(let i = 0; i < data.length; i++){
-                // skip template project
-                if (data[i].name == 'page_basic' || data[i].name == 'generic' || data[i].name == 'simple_raw' || data[i].name == 'simple_thesis') {
-                    continue
-                } else if(data[i].tag_list.includes('website')) {
-                    pagesArr.push(data[i])
-                } else {
-                    reposArr.push(data[i])
-                }
-            }
-            return {
-                error: false,
-                data: [reposArr, pagesArr]}
+const gitlab = {
+  getProjects: async function (perPage: number, idAfter: number) {
+    try {
+      const projects = await axios({
+        method: 'get',
+        url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects?visibility=public&pagination=keyset&per_page=' + String(perPage) + '&order_by=id&sort=asc&id_after=' + String(idAfter)
+      })
+      const data = projects.data
+      const reposArr = []
+      const pagesArr = []
+      for (let i = 0; i < data.length; i++) {
+        // skip template project
+        if (data[i].name === 'page_basic' || data[i].name === 'generic' || data[i].name === 'simple_raw' || data[i].name === 'simple_thesis') {
+          continue
+        } else if (data[i].tag_list.includes('website')) {
+          pagesArr.push(data[i])
+        } else {
+          reposArr.push(data[i])
         }
-        catch (err) {
-            return {
-                error: true,
-                data: err}
-        }
-    },
-    getLatestPipelineStatus: async function(projectId:number) {
-        return axios({
-            method: 'get',
-            url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/'+projectId+'/pipelines'
-        })
-        .then(res => res.data[0].status)
-        .catch(err => console.error(err))
+      }
+      return {
+        error: false,
+        data: [reposArr, pagesArr]
+      }
+    } catch (err) {
+      return {
+        error: true,
+        data: err
+      }
     }
+  },
+  getLatestPipelineStatus: async function (projectId: number) {
+    return await axios({
+      method: 'get',
+      url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/' + String(projectId) + '/pipelines'
+    })
+      .then(res => res.data[0].status)
+      .catch(err => console.error(err))
+  }
 }
 
-export = gitlab
\ No newline at end of file
+export = gitlab
diff --git a/functions/helpers.ts b/functions/helpers.ts
index 1c3451fc00883bf4307ba324dc98f75a7d76b80f..89506026042e8fb2b886a2a974fa3356d7a25c33 100644
--- a/functions/helpers.ts
+++ b/functions/helpers.ts
@@ -1,11 +1,11 @@
-var helpers = {
-    stringToArray: function (input:string){
-        if(input != null){
-            return input.split(',');
-        }else{
-            return null;
-        }
+const helpers = {
+  stringToArray: function (input: string) {
+    if (input != null) {
+      return input.split(',')
+    } else {
+      return null
     }
-};
+  }
+}
 
-export = helpers;
\ No newline at end of file
+export = helpers
diff --git a/functions/methods.ts b/functions/methods.ts
deleted file mode 100644
index f1ad966d7ee6b7cac2f5a2ffa09ca2c5b8d61a7a..0000000000000000000000000000000000000000
--- a/functions/methods.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-const dbconn = require('../config/dbconn');
-
-var methods = {
-    getAllMailinglists: async function() {
-        try {
-            let rows:any = await dbconn.project.promise().query('CALL getAllLists')
-            if (rows[0][0]) {
-                return rows[0][0]
-            } else { return null }
-        } catch (err) {
-            console.error(err)
-        }
-        return null
-    },
-    getProjectOverviewById: async function(projectId:number) {
-        try {
-            let rows:any = await dbconn.project.promise().query('CALL GetProjectInformationByProjectID(' + projectId+ ')')
-            if (rows[0][0]) {
-                return rows[0][0]
-            } else { return null }
-        } catch (err) {
-            console.error(err)
-        }
-        return null
-    },
-    getProjectImagesById: async function(projectId:number) {
-        try {
-            let rows:any = await dbconn.project.promise().query('CALL getImagesByProjectID(' + projectId+ ')')
-            if (rows[0][0]) {
-                return rows[0][0]
-            } else { return null }
-        } catch (err) {
-            console.error(err)
-        }
-        return null
-    }
-};
-
-
-export = methods;
\ No newline at end of file
diff --git a/jest.config.js b/jest.config.js
index 91a2d2c0d311017438880c27890ec8d34e60d25f..758fa1330e87740bfa99095c8a02946ef29213aa 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,4 +1,4 @@
 module.exports = {
   preset: 'ts-jest',
-  testEnvironment: 'node',
-};
\ No newline at end of file
+  testEnvironment: 'node'
+}
diff --git a/public/js/jquery-ui/i18n/datepicker-de.js b/public/js/jquery-ui/i18n/datepicker-de.js
index e2e61d27b6b4bf33c0fd59e9ebf2d307d0337af3..1d7efafaf89f4b563367ace4f38092deb6cb3680 100644
--- a/public/js/jquery-ui/i18n/datepicker-de.js
+++ b/public/js/jquery-ui/i18n/datepicker-de.js
@@ -1,37 +1,34 @@
 /* German initialisation for the jQuery UI date picker plugin. */
 /* Written by Milian Wolff (mail@milianw.de). */
-( function( factory ) {
-	if ( typeof define === "function" && define.amd ) {
+(function (factory) {
+  if (typeof define === 'function' && define.amd) {
+    // AMD. Register as an anonymous module.
+    define(['../widgets/datepicker'], factory)
+  } else {
+    // Browser globals
+    factory(jQuery.datepicker)
+  }
+}(function (datepicker) {
+  datepicker.regional.de = {
+    closeText: 'Schließen',
+    prevText: '&#x3C;Zurück',
+    nextText: 'Vor&#x3E;',
+    currentText: 'Heute',
+    monthNames: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
+      'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
+    monthNamesShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun',
+      'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
+    dayNames: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
+    dayNamesShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
+    dayNamesMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
+    weekHeader: 'KW',
+    dateFormat: 'dd.mm.yy',
+    firstDay: 1,
+    isRTL: false,
+    showMonthAfterYear: false,
+    yearSuffix: ''
+  }
+  datepicker.setDefaults(datepicker.regional.de)
 
-		// AMD. Register as an anonymous module.
-		define( [ "../widgets/datepicker" ], factory );
-	} else {
-
-		// Browser globals
-		factory( jQuery.datepicker );
-	}
-}( function( datepicker ) {
-
-datepicker.regional.de = {
-	closeText: "Schließen",
-	prevText: "&#x3C;Zurück",
-	nextText: "Vor&#x3E;",
-	currentText: "Heute",
-	monthNames: [ "Januar","Februar","März","April","Mai","Juni",
-	"Juli","August","September","Oktober","November","Dezember" ],
-	monthNamesShort: [ "Jan","Feb","Mär","Apr","Mai","Jun",
-	"Jul","Aug","Sep","Okt","Nov","Dez" ],
-	dayNames: [ "Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag" ],
-	dayNamesShort: [ "So","Mo","Di","Mi","Do","Fr","Sa" ],
-	dayNamesMin: [ "So","Mo","Di","Mi","Do","Fr","Sa" ],
-	weekHeader: "KW",
-	dateFormat: "dd.mm.yy",
-	firstDay: 1,
-	isRTL: false,
-	showMonthAfterYear: false,
-	yearSuffix: "" };
-datepicker.setDefaults( datepicker.regional.de );
-
-return datepicker.regional.de;
-
-} ) );
\ No newline at end of file
+  return datepicker.regional.de
+}))
diff --git a/routes/project.ts b/routes/project.ts
index 86bce9b32e7d1a88aaee540d622088fff48a4b2f..64f5d4936452d828db593bce8ceeb5dc860c33b2 100644
--- a/routes/project.ts
+++ b/routes/project.ts
@@ -1,229 +1,31 @@
-//const SamlStrategy = require('passport-saml').Strategy
-import methods from '../functions/methods'
-import gitlab from '../functions/gitlab'
-import helpers from '../functions/helpers'
-import https from 'https'
+import controller from '../controller/controller'
 
-module.exports = function (app:any, lang:string) {
- 
+module.exports = function (app: any) {
   // ======== APP ROUTES - PROJECT ====================
-  
-  app.get('/', function (req:any, res:any) {
-    res.render(lang+'/project/project-simplified')
-  })
-
-  app.get('/mailinglists', async function (req:any, res:any) {
-    let mailList = await methods.getAllMailinglists()
-    if (mailList) {
-      let allMailingLists = []  // JSON object
-      for (let i = 0; i < mailList.length; i++) {
-        // add data to JSON object
-        allMailingLists.push({
-          id: mailList[i].id,
-          name: mailList[i].name,
-          src: mailList[i].src,
-          projectstatus: mailList[i].projectstatus,
-          project_title: mailList[i].project_title,
-          keywords: mailList[i].keywords
-        });
-      }
 
-      res.render(lang+'/project/mailinglists', {
-        //isUserAuthenticated: req.isAuthenticated(),
-        //user: req.user,
-        mailinglists: allMailingLists
-      });
-    } else {
-      res.render(lang+'/project/mailinglists', {
-        //isUserAuthenticated: req.isAuthenticated(),
-        //user: req.user,
-        mailinglists: null
-      })
-    }
+  app.get('/', function (req: any, res: any) {
+    controller.showHome(res)
   })
 
-  app.get('/projectoverview', async function(req:any, res:any){
-    let projectOverview = await methods.getProjectOverviewById(req.query.projectID)
-    if (projectOverview.length > 0) {
-      let partnerWebsites = helpers.stringToArray(projectOverview[0].partner_website)
-      let partnerNames = helpers.stringToArray(projectOverview[0].partner_name)
-      let awardSites = helpers.stringToArray(projectOverview[0].award_website)
-      let awardNames = helpers.stringToArray(projectOverview[0].award_name)
-      let sponsorWebsites = helpers.stringToArray(projectOverview[0].sponsor_website)
-      let sponsorImgs = helpers.stringToArray(projectOverview[0].sponsor_img)
-      let sponsorNames = helpers.stringToArray(projectOverview[0].sponsor_name)
+  app.get('/mailinglists', function (req: any, res: any) {
+    controller.showMailingList(res)
+      .catch(err => console.error(err))
+  })
 
-      let projectImages = await methods.getProjectImagesById(req.query.projectID)
-      res.render(lang+'/project/projectOverview', {
-        //isUserAuthenticated: req.isAuthenticated(),
-        //user: req.user,
-        projectOV: projectOverview,
-        projectImgs: projectImages,
-        partnerWS: partnerWebsites,
-        partnerN: partnerNames,
-        awardWS: awardSites,
-        awardN: awardNames,
-        sponsorWS: sponsorWebsites,
-        sponsorIMG: sponsorImgs,
-        sponsorN: sponsorNames
-      });
-    } else {
-      res.redirect('/')
-    }
+  app.get('/projectoverview', function (req: any, res: any, next: any) {
+    controller.showProjOverview(req, res, next)
+      .catch(err => console.error(err))
   })
 
   // Projektdaten
-  app.get('/projektdaten', async function(req:any, res:any){
-    let projectArr = []
-    let isProject = true
-    let firstId = 0
-    let orderKeyword = req.query.sort
-
-    while (isProject == true) {
-      let projects = await gitlab.getProjects(100, firstId)
-      let projectData = projects.data[0]
-
-      if (projectData.length == 0) {
-        isProject = false
-      }
-      else {
-        for(let i = 0; i < projectData.length; i++){
-          // M4_LAB logo for all projects that do not have logo
-          if (projectData[i].avatar_url == null) {
-            projectData[i].avatar_url = "https://m4lab.hft-stuttgart.de/img/body/M4_LAB_LOGO_NO_TEXT.png"
-          }
-          // for all projects that have no description
-          if (projectData[i].description == "") {
-            projectData[i].description = "- no description -"
-          }
-
-          let project = {
-            logo: projectData[i].avatar_url,
-            name: projectData[i].name,
-            weburl: projectData[i].web_url,
-            desc: projectData[i].description,
-            keywords: projectData[i].tag_list,
-            createdAt: projectData[i].created_at,
-            lastUpdatedAt: projectData[i].last_activity_at
-          }
-          projectArr.push(project)
-        }
-        firstId = projectData[projectData.length-1].id
-      }
-
-      // MLAB-576
-      if (orderKeyword == "created_at") {
-        projectArr.sort((a, b) => {
-          let aDate:any = new Date(a.createdAt)
-          let bDate:any = new Date(b.createdAt)
-          return bDate - aDate
-        });
-      } else if (orderKeyword == "updated_at") {
-        projectArr.sort((a, b) => {
-          let aDate:any = new Date(a.lastUpdatedAt)
-          let bDate:any = new Date(b.lastUpdatedAt)
-          return bDate - aDate
-        });
-      } else { // default, sorted by name
-        projectArr.sort((a, b) => {
-          let fa = a.name.toLowerCase(),
-              fb = b.name.toLowerCase();
-      
-          if (fa < fb) return -1;
-          if (fa > fb) return 1;
-          return 0;
-        });
-      }
-    }
-
-    res.render(lang+'/project/projectList', {
-      project: projectArr
-    })
+  app.get('/projektdaten', function (req: any, res: any) {
+    controller.showProjData(req, res)
+      .catch(err => console.error(err))
   })
 
   // Projektinformationen
-  app.get('/projektinformationen', async function(req:any, res:any){
-    let pagesArr: { logo: any; name: any; weburl: any; desc: any; keywords: any; createdAt: any; lastUpdatedAt: any; }[] = []
-    let isProject = true
-    let firstId = 0
-    let orderKeyword = req.query.sort
-
-    while (isProject == true) {
-      let projects = await gitlab.getProjects(100, firstId)
-      let pagesData = projects.data[1]
-
-      if (pagesData.length == 0) {
-        isProject = false
-      } else {
-        for(let i = 0; i < pagesData.length; i++){
-          let status = await gitlab.getLatestPipelineStatus(pagesData[i].id)
-          if (status) {
-            // M4_LAB logo for all projects that do not have logo
-            if (pagesData[i].avatar_url == null) {
-              pagesData[i].avatar_url = "https://m4lab.hft-stuttgart.de/img/body/M4_LAB_LOGO_NO_TEXT.png"
-            }
-            // for all projects that have no description
-            if (pagesData[i].description == "") {
-              pagesData[i].description = "- no description -"
-            }
-            // https://transfer.hft-stuttgart.de/pages/EIGENTUEMER/PROJEKTNAME/
-            pagesData[i].web_url = "https://transfer.hft-stuttgart.de/pages/"+pagesData[i].namespace.path+"/"+pagesData[i].name+"/"
-            // remove 'website' from tag list
-            let index = pagesData[i].tag_list.indexOf('website')
-            if (index > -1) {
-              pagesData[i].tag_list.splice(index, 1)
-            }
-
-            // fill in pagesArr
-            let pages = {
-              logo: pagesData[i].avatar_url,
-              name: pagesData[i].name,
-              weburl: pagesData[i].web_url,
-              desc: pagesData[i].description,
-              keywords: pagesData[i].tag_list,
-              createdAt: pagesData[i].created_at,
-              lastUpdatedAt: pagesData[i].last_activity_at
-            }
-
-            https.get(pagesData[i].web_url, function (response:any) {
-              if (response.statusCode >= 200 && response.statusCode <= 299) {
-                pagesArr.push(pages)
-              }
-            })
-          }
-        }
-        firstId = pagesData[pagesData.length-1].id
-      }
-
-      // MLAB-576
-      if (orderKeyword == "created_at") {
-        pagesArr.sort((a, b) => {
-          let aDate:any = new Date(a.createdAt)
-          let bDate:any = new Date(b.createdAt)
-          return bDate - aDate
-        });
-      } else if (orderKeyword == "updated_at") {
-        pagesArr.sort((a, b) => {
-          let aDate:any = new Date(a.lastUpdatedAt)
-          let bDate:any = new Date(b.lastUpdatedAt)
-          return bDate - aDate
-        });
-      } else { // default, sorted by name
-        pagesArr.sort((a, b) => {
-          let fa = a.name.toLowerCase(),
-              fb = b.name.toLowerCase();
-      
-          if (fa < fb) return -1;
-          if (fa > fb) return 1;
-          return 0;
-        });
-      }
-
-    }
-
-    res.render(lang+'/project/pagesList', {
-      pages: pagesArr
-    })
+  app.get('/projektinformationen', function (req: any, res: any) {
+    controller.showProjInformations(req, res)
+      .catch(err => console.error(err))
   })
-
-};
\ No newline at end of file
+}
diff --git a/views/DE/project/mailinglists.pug b/views/DE/project/mailinglists.pug
index 66d64e1131ea68586c96ca1f5154c8a16a36dc48..efbf659ce688a6ad06ef029b47b8c2f0963b8c7e 100644
--- a/views/DE/project/mailinglists.pug
+++ b/views/DE/project/mailinglists.pug
@@ -21,7 +21,7 @@ html(lang="de")
             div(class="col-md-12 margin_bottom_30")
                 h2(class="text-center color_708090") <strong>Aktive Mailinglisten</strong>
                 div(class="table-responsive table-borderless")
-                    if !mailinglists
+                    if !mailinglists || !mailinglists.length
                         p There is no active mailing list at the moment
                     else
                         table(class="table table-striped table-bordered table-hover")