diff --git a/client/js/app.js b/client/js/app.js
index dc8c6b4e8774c40cb52f67eb17e5586abc9b9325..d728dda44a7be80d1e4c49bf1452d8967492aba4 100644
--- a/client/js/app.js
+++ b/client/js/app.js
@@ -5,7 +5,6 @@
 import CONSTANTS from './constants'
 
 import Vue from 'vue'
-import VueResource from 'vue-resource'
 import VueClipboards from 'vue-clipboards'
 import VeeValidate from 'vee-validate'
 import { ApolloClient } from 'apollo-client'
@@ -77,7 +76,6 @@ window.graphQL = new ApolloClient({
 // Initialize Vue Modules
 // ====================================
 
-Vue.use(VueResource)
 Vue.use(VueClipboards)
 Vue.use(localization.VueI18Next)
 Vue.use(helpers)
diff --git a/dev/config/tsconfig.json b/dev/config/tsconfig.json
deleted file mode 100644
index 20c43b301e75b462de1f758d6e557e817f1b21d4..0000000000000000000000000000000000000000
--- a/dev/config/tsconfig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "compilerOptions": {
-    "allowJs": true,
-    "alwaysStrict": true,
-    "module": "commonjs",
-    "moduleResolution": "node",
-    "noImplicitAny": true,
-    "preserveConstEnums": true,
-    "removeComments": true,
-    "sourceMap": false,
-    "strictNullChecks": true,
-    "suppressImplicitAnyIndexErrors": true,
-    "target": "es5"
-  },
-  "exclude": [
-    ".fusebox",
-    "data",
-    "node_modules",
-    "repo"
-  ]
-}
diff --git a/dev/fuse/index.js b/dev/fuse/index.js
deleted file mode 100644
index a298fb132492ec1e0bb2c213b2de11979b6514f7..0000000000000000000000000000000000000000
--- a/dev/fuse/index.js
+++ /dev/null
@@ -1,178 +0,0 @@
-'use strict'
-
-/**
- * FUSEBOX
- *
- * Client & Server compiler / bundler / watcher
- */
-
-const Promise = require('bluebird')
-const autoprefixer = require('autoprefixer')
-const colors = require('colors/safe')
-const fsbx = require('fuse-box')
-const fs = require('fs-extra')
-const yargs = require('yargs')
-const yaml = require('js-yaml')
-const path = require('path')
-
-// -------------------------------------------------------
-// PARSE CMD ARGUMENTS
-// -------------------------------------------------------
-
-const opts = yargs
-  .option('d', {
-    alias: 'dev',
-    describe: 'Start in Developer mode',
-    type: 'boolean'
-  })
-  .option('b', {
-    alias: 'build',
-    describe: 'Start in Build mode',
-    type: 'boolean'
-  })
-  .help('h')
-  .alias('h', 'help')
-  .argv
-
-if (opts.dev) {
-  console.info(colors.bgWhite.black(' Starting Wiki.js in DEVELOPER mode... '))
-} else if (opts.build) {
-  console.info(colors.bgWhite.black(' Starting Wiki.js in BUILD mode... '))
-} else {
-  yargs.showHelp()
-  process.exit(0)
-}
-
-// -------------------------------------------------------
-// GET CONFIG
-// -------------------------------------------------------
-
-try {
-  const config = yaml.safeLoad(fs.readFileSync(path.join(process.cwd(), 'dev/config/config.yml'), 'utf8'))
-  global.config = config
-} catch (ex) {
-  console.error(ex)
-  process.exit(1)
-}
-
-// -------------------------------------------------------
-// BUILD VARS
-// -------------------------------------------------------
-
-const ALIASES = {
-  'brace-ext-modelist': 'brace/ext/modelist.js',
-  'simplemde': 'simplemde/dist/simplemde.min.js',
-  'vue': (opts.dev) ? 'vue/dist/vue.js' : 'vue/dist/vue.min.js',
-  'vue-lodash': 'vue-lodash/dist/vue-lodash.min.js',
-  'vue-resource': (opts.dev) ? 'vue-resource/dist/vue-resource.js' : 'vue-resource/dist/vue-resource.es2015.js'
-}
-const SHIMS = {
-  diff2html: {
-    source: '../../node_modules/diff2html/dist/diff2html.min.js',
-    exports: 'Diff2Html'
-  },
-  diff2htmlui: {
-    source: '../../node_modules/diff2html/dist/diff2html-ui.min.js',
-    exports: 'Diff2HtmlUI'
-  }
-}
-
-// -------------------------------------------------------
-// Tasks
-// -------------------------------------------------------
-
-console.info(colors.white('в””в”Ђв”Ђ ') + colors.green('Running tasks...'))
-let tasks = require('./tasks')
-let tasksToRun = []
-
-tasksToRun.push(tasks.cleanFuseboxCache)
-tasksToRun.push(tasks.copySimpleMdeAssets)
-tasksToRun.push(tasks.copyAceModes)
-
-if (opts.build) {
-  tasksToRun.push(tasks.cleanTestResults)
-  tasksToRun.push(tasks.fetchLocalizationResources)
-}
-
-// -------------------------------------------------------
-// FUSEBOX PRODUCER
-// -------------------------------------------------------
-
-const babelrc = fs.readJsonSync('.babelrc')
-const scssChain = [
-  fsbx.SassPlugin({
-    includePaths: ['node_modules'],
-    outputStyle: opts.dev ? 'nested' : 'compressed'
-  }),
-  fsbx.PostCSS([
-    autoprefixer({
-      remove: false,
-      browsers: babelrc.presets[0][1].targets.browsers
-    })
-  ]),
-  fsbx.CSSPlugin(opts.dev ? {} : {
-    group: 'bundle.css',
-    outFile: '../../assets/css/bundle.css',
-    inject: false
-  })
-]
-
-Promise.mapSeries(tasksToRun, fn => fn()).then(() => {
-  let fuse = fsbx.FuseBox.init({
-    homeDir: '../../client',
-    output: '../../assets/js/$name.js',
-    alias: ALIASES,
-    target: 'browser',
-    tsConfig: '../config/tsconfig.json',
-    plugins: [
-      fsbx.EnvPlugin({ NODE_ENV: (opts.dev) ? 'development' : 'production' }),
-      fsbx.VueComponentPlugin({
-        script: fsbx.BabelPlugin(babelrc),
-        template: fsbx.ConsolidatePlugin({
-          engine: 'pug'
-        }),
-        style: scssChain
-      }),
-      scssChain,
-      fsbx.RawPlugin(['.svg']),
-      fsbx.BabelPlugin(babelrc),
-      fsbx.JSONPlugin()
-    ],
-    debug: false,
-    log: true
-  })
-
-  // -------------------------------------------------------
-  // FUSEBOX DEV
-  // -------------------------------------------------------
-
-  if (opts.dev) {
-    fuse.dev({
-      port: 5555,
-      httpServer: false
-    })
-  }
-
-  // -------------------------------------------------------
-  // FUSEBOX BUNDLES
-  // -------------------------------------------------------
-
-  if (opts.dev) {
-    fuse.bundle('libs').shim(SHIMS).instructions('~ index.js')
-    fuse.bundle('app').instructions('!> [index.js]').hmr({ reload: true }).watch()
-  } else {
-    fuse.bundle('bundle.min.js').shim(SHIMS).instructions('> index.js')
-  }
-
-  // -------------------------------------------------------
-  // FUSEBOX RUN
-  // -------------------------------------------------------
-
-  fuse.run().then(() => {
-    console.info(colors.green.bold('\nAssets compilation + bundling completed.'))
-    return true
-  }).catch(err => {
-    console.error(colors.red(' X Bundle compilation failed! ' + err.message))
-    process.exit(1)
-  })
-})
diff --git a/dev/fuse/tasks.js b/dev/fuse/tasks.js
deleted file mode 100644
index 60a2663d10d6087b5162662fd8e83e7294911911..0000000000000000000000000000000000000000
--- a/dev/fuse/tasks.js
+++ /dev/null
@@ -1,125 +0,0 @@
-/* global config */
-
-const Promise = require('bluebird')
-const colors = require('colors/safe')
-const fs = Promise.promisifyAll(require('fs-extra'))
-const path = require('path')
-const uglify = require('uglify-es')
-const request = require('request-promise')
-const yaml = require('js-yaml')
-const _ = require('lodash')
-
-module.exports = {
-  /**
-   * Fetch Localization Resources from Lokalise
-   */
-  async fetchLocalizationResources () {
-    console.info(colors.white('  в””в”Ђв”Ђ ') + colors.green('Fetching latest localization resources...'))
-    let langs = await request({
-      method: 'POST',
-      uri: `${config.lokalise.api}/string/list`,
-      form: {
-        api_token: config.lokalise.key,
-        id: config.lokalise.project
-      },
-      json: true
-    })
-    if (langs && langs.strings && _.isPlainObject(langs.strings)) {
-      _.forIn(langs.strings, (langData, langKey) => {
-        let lang = {}
-        let langTotal = 0
-        langData.forEach(item => {
-          if (item.is_archived === '1' || _.includes(item.key, '::')) { return }
-          let keyParts = item.key.split(':')
-          let keyNamespace = (keyParts.length > 1) ? _.head(keyParts) : 'common'
-          let keyString = _.last(keyParts)
-          _.set(lang, `${keyNamespace}.${keyString}`, item.translation)
-          langTotal++
-        })
-        _.forOwn(lang, (langObject, langNamespace) => {
-          let langYaml = yaml.safeDump(langObject, {
-            indent: 2,
-            sortKeys: true,
-            lineWidth: 2048
-          })
-          fs.outputFileSync(path.join(process.cwd(), `server/locales/${langKey}/${langNamespace}.yml`), langYaml, 'utf8')
-        })
-        console.info(colors.white(`      ${langKey} - ${langTotal} keys written`))
-      })
-    } else {
-      throw new Error('Failed to fetch language list from Lokalise API.')
-    }
-    return true
-  },
-  /**
-   * SimpleMDE
-   */
-  copySimpleMdeAssets () {
-    return fs.accessAsync('./assets/js/simplemde').then(() => {
-      console.info(colors.white('  в””в”Ђв”Ђ ') + colors.magenta('SimpleMDE directory already exists. Task skipped.'))
-      return true
-    }).catch(err => {
-      if (err.code === 'ENOENT') {
-        console.info(colors.white('  в””в”Ђв”Ђ ') + colors.green('Copy + Minify SimpleMDE to assets...'))
-        return fs.copy('./node_modules/simplemde/dist/simplemde.min.js', './assets/js/simplemde/simplemde.min.js')
-      } else {
-        throw err
-      }
-    })
-  },
-  /**
-   * ACE Modes
-   */
-  copyAceModes () {
-    return fs.accessAsync('./assets/js/ace').then(() => {
-      console.info(colors.white('  в””в”Ђв”Ђ ') + colors.magenta('ACE modes directory already exists. Task skipped.'))
-      return true
-    }).catch(err => {
-      if (err.code === 'ENOENT') {
-        console.info(colors.white('  в””в”Ђв”Ђ ') + colors.green('Copy + Minify ACE modes to assets...'))
-        return fs.ensureDirAsync('./assets/js/ace').then(() => {
-          return Promise.join(
-            // Core
-            Promise.all([
-              fs.readFileAsync('./node_modules/brace/index.js', 'utf8'),
-              fs.readFileAsync('./node_modules/brace/ext/modelist.js', 'utf8'),
-              fs.readFileAsync('./node_modules/brace/theme/dawn.js', 'utf8'),
-              fs.readFileAsync('./node_modules/brace/theme/tomorrow_night.js', 'utf8'),
-              fs.readFileAsync('./node_modules/brace/mode/markdown.js', 'utf8')
-            ]).then(items => {
-              console.info(colors.white('      ace.js'))
-              let result = uglify.minify(items.join(';\n'), { output: { 'max_line_len': 1000000 } })
-              return fs.writeFileAsync('./assets/js/ace/ace.js', result.code)
-            }),
-            // Modes
-            fs.readdirAsync('./node_modules/brace/mode').then(modeList => {
-              return Promise.map(modeList, mdFile => {
-                return fs.readFileAsync(path.join('./node_modules/brace/mode', mdFile), 'utf8').then(modeCode => {
-                  console.info(colors.white('      mode-' + mdFile))
-                  let result = uglify.minify(modeCode, { output: { 'max_line_len': 1000000 } })
-                  return fs.writeFileAsync(path.join('./assets/js/ace', 'mode-' + mdFile), result.code)
-                })
-              }, { concurrency: 3 })
-            })
-          )
-        })
-      } else {
-        throw err
-      }
-    })
-  },
-  /**
-   * Delete Fusebox cache
-   */
-  cleanFuseboxCache () {
-    console.info(colors.white('  в””в”Ђв”Ђ ') + colors.green('Clearing fuse-box cache...'))
-    return fs.emptyDirAsync('./.fusebox')
-  },
-  /**
-   * Delete Test Results
-   */
-  cleanTestResults () {
-    console.info(colors.white('  в””в”Ђв”Ђ ') + colors.green('Clearing test results...'))
-    return fs.remove('./test-results')
-  }
-}
diff --git a/dev/tasks/localization.js b/dev/tasks/localization.js
new file mode 100644
index 0000000000000000000000000000000000000000..023ccb386217e07025fd6a9c0cb6e81214d77fff
--- /dev/null
+++ b/dev/tasks/localization.js
@@ -0,0 +1,56 @@
+const Promise = require('bluebird')
+const colors = require('colors/safe')
+const fs = Promise.promisifyAll(require('fs-extra'))
+const path = require('path')
+const request = require('request-promise')
+const yaml = require('js-yaml')
+const _ = require('lodash')
+
+const config = yaml.safeLoad(fs.readFileSync(path.join(process.cwd(), 'dev/config/config.yml'), 'utf8'))
+
+/**
+ * Fetch Localization Resources from Lokalise
+ */
+const fetchLocalizationResources = async () => {
+  console.info(colors.green('Fetching latest localization resources...'))
+  let langs = await request({
+    method: 'POST',
+    uri: `${config.lokalise.api}/string/list`,
+    form: {
+      api_token: config.lokalise.key,
+      id: config.lokalise.project
+    },
+    json: true
+  })
+  if (langs && langs.strings && _.isPlainObject(langs.strings)) {
+    _.forIn(langs.strings, (langData, langKey) => {
+      let lang = {}
+      let langTotal = 0
+      langData.forEach(item => {
+        if (item.is_archived === '1' || _.includes(item.key, '::')) { return }
+        let keyParts = item.key.split(':')
+        let keyNamespace = (keyParts.length > 1) ? _.head(keyParts) : 'common'
+        let keyString = _.last(keyParts)
+        _.set(lang, `${keyNamespace}.${keyString}`, item.translation)
+        langTotal++
+      })
+      _.forOwn(lang, (langObject, langNamespace) => {
+        let langYaml = yaml.safeDump(langObject, {
+          indent: 2,
+          sortKeys: true,
+          lineWidth: 2048
+        })
+        fs.outputFileSync(path.join(process.cwd(), `server/locales/${langKey}/${langNamespace}.yml`), langYaml, 'utf8')
+      })
+      console.info(colors.grey(`в””в”Ђ ${langKey} - ${langTotal} keys written`))
+    })
+  } else {
+    throw new Error('Failed to fetch language list from Lokalise API.')
+  }
+}
+
+try {
+  fetchLocalizationResources()
+} catch (err) {
+  console.error(colors.red(err))
+}
diff --git a/package.json b/package.json
index 85ed408d483391eced301c48f79f484e1fe4b94a..c0da1a62342631479bc83d1803dcddc02befc814 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
     "restart": "node wiki restart",
     "dev": "node wiki dev",
     "build": "webpack --profile --config dev/webpack/webpack.prod.js",
+    "build:locales": "node dev/tasks/localization",
     "watch": "webpack --config dev/webpack/webpack.dev.js",
     "test": "eslint --ext .js,.vue . && jest"
   },
@@ -45,15 +46,14 @@
     "body-parser": "1.18.2",
     "bugsnag": "2.1.3",
     "bull": "3.3.8",
-    "bunyan": "1.8.12",
     "cheerio": "1.0.0-rc.2",
     "child-process-promise": "2.2.1",
     "chokidar": "2.0.0",
     "compression": "1.7.1",
-    "connect-flash": "0.1.1",
     "connect-redis": "3.3.3",
     "cookie-parser": "1.4.3",
     "cors": "2.8.4",
+    "dependency-graph": "0.7.0",
     "diff2html": "2.3.3",
     "dotize": "^0.2.0",
     "execa": "0.9.0",
@@ -75,7 +75,6 @@
     "i18next-node-fs-backend": "1.0.0",
     "image-size": "0.6.2",
     "ioredis": "3.2.2",
-    "jimp": "0.2.28",
     "js-yaml": "3.10.0",
     "jsonwebtoken": "8.1.1",
     "klaw": "2.1.1",
@@ -97,7 +96,7 @@
     "mongodb": "3.0.1",
     "multer": "1.3.0",
     "node-2fa": "1.1.2",
-    "node-graceful": "0.2.3",
+    "nodegit": "0.20.3",
     "ora": "1.3.0",
     "passport": "0.4.0",
     "passport-auth0": "0.6.1",
@@ -127,9 +126,6 @@
     "sequelize": "4.32.2",
     "serve-favicon": "2.4.5",
     "simplemde": "1.11.2",
-    "stream-to-promise": "2.2.0",
-    "tar": "4.3.0",
-    "through2": "2.0.3",
     "uuid": "3.2.1",
     "validator": "9.3.0",
     "validator-as-promised": "1.0.2",
@@ -157,7 +153,6 @@
     "cache-loader": "1.2.0",
     "clean-webpack-plugin": "0.1.18",
     "colors": "1.1.2",
-    "consolidate": "0.15.0",
     "copy-webpack-plugin": "4.3.1",
     "css-loader": "0.28.9",
     "cssnano": "4.0.0-rc.2",
@@ -180,7 +175,6 @@
     "js-cookie": "2.2.0",
     "lodash-webpack-plugin": "0.11.4",
     "name-all-modules-plugin": "1.0.1",
-    "node-dev": "3.1.3",
     "node-sass": "4.7.2",
     "offline-plugin": "4.9.0",
     "postcss-flexbugs-fixes": "3.3.0",
@@ -193,22 +187,15 @@
     "sass-resources-loader": "1.3.1",
     "simple-progress-webpack-plugin": "1.0.4",
     "style-loader": "0.20.1",
-    "svg-sprite-loader": "3.6.2",
     "twemoji-awesome": "1.0.6",
-    "typescript": "2.6.2",
-    "uglify-es": "3.3.9",
     "uglifyjs-webpack-plugin": "1.1.6",
     "vee-validate": "2.0.3",
     "vue": "2.5.13",
     "vue-clipboards": "1.2.1",
     "vue-hot-reload-api": "2.2.4",
     "vue-loader": "13.7.0",
-    "vue-lodash": "1.0.4",
-    "vue-material": "^0.8.1",
-    "vue-resource": "1.3.5",
     "vue-simple-breakpoints": "1.0.3",
     "vue-template-compiler": "2.5.13",
-    "vue-template-es2015-compiler": "1.6.0",
     "vuex": "3.0.1",
     "vuex-persistedstate": "2.4.2",
     "webpack": "3.10.0",
diff --git a/server/extensions/storage/disk.js b/server/extensions/storage/disk.js
new file mode 100644
index 0000000000000000000000000000000000000000..7153933a64ea6b4b04bccdb81c6816f7a85eb1c7
--- /dev/null
+++ b/server/extensions/storage/disk.js
@@ -0,0 +1,8 @@
+module.exports = {
+  activate() {
+
+  },
+  deactivate() {
+
+  }
+}
diff --git a/server/extensions/storage/git.js b/server/extensions/storage/git.js
new file mode 100644
index 0000000000000000000000000000000000000000..7153933a64ea6b4b04bccdb81c6816f7a85eb1c7
--- /dev/null
+++ b/server/extensions/storage/git.js
@@ -0,0 +1,8 @@
+module.exports = {
+  activate() {
+
+  },
+  deactivate() {
+
+  }
+}
diff --git a/server/master.js b/server/master.js
index 0581fbd2e5852f38a21fdafe5f092e9041e07c36..77ca5af6149c827d906de422280e552ff5e98516 100644
--- a/server/master.js
+++ b/server/master.js
@@ -10,9 +10,9 @@ module.exports = async () => {
   wiki.docs = require('./modules/documents').init()
   wiki.git = require('./modules/git').init(false)
   wiki.lang = require('./modules/localization').init()
-  wiki.mark = require('./modules/markdown')
-  wiki.search = require('./modules/search').init()
-  wiki.upl = require('./modules/uploads').init()
+  // wiki.mark = require('./modules/markdown')
+  // wiki.search = require('./modules/search').init()
+  // wiki.upl = require('./modules/uploads').init()
 
   // ----------------------------------------
   // Load modules
@@ -25,7 +25,6 @@ module.exports = async () => {
   const cors = require('cors')
   const express = require('express')
   const favicon = require('serve-favicon')
-  const flash = require('connect-flash')
   const http = require('http')
   const path = require('path')
   const session = require('express-session')
@@ -79,7 +78,6 @@ module.exports = async () => {
     resave: false,
     saveUninitialized: false
   }))
-  app.use(flash())
   app.use(wiki.auth.passport.initialize())
   app.use(wiki.auth.passport.session())
 
diff --git a/yarn.lock b/yarn.lock
index c95ca502df2db16669bec8cf06cf6d17340b2144..a707fa5cb183ffc46d1b4ed97e83bb01bfeb7a8f 100644
Binary files a/yarn.lock and b/yarn.lock differ