diff --git a/backend/.dockerignore b/.dockerignore
similarity index 56%
rename from backend/.dockerignore
rename to .dockerignore
index aaca40b6a51557fb782f4c4b24e46d97de773c32..fb00b3c09226ce7db6d952f2933f56ced7c53450 100644
--- a/backend/.dockerignore
+++ b/.dockerignore
@@ -1,12 +1,15 @@
-.dockerignore
+# Common
+*/.git
 Dockerfile
-db.sqlite3
-__pycache__
+
+# Django
+
+*/db.sqlite3
+*/__pycache__*
 *.pyc
 *.pyo
 *.pyd
-.Python
-env
+*/env*
 pip-log.txt
 pip-delete-this-directory.txt
 .tox
@@ -16,4 +19,8 @@ pip-delete-this-directory.txt
 coverage.xml
 *,cover
 *.log
-.git
+
+
+# node
+*/node_modules
+*/npm-debug.log
diff --git a/.gitignore b/.gitignore
index 111d38d59810b993f6a71dc2c7b947e0939a8e1e..04005159a65f154e523f2f6be8ee5e9e6c839f25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,43 +1,6 @@
-# If you need to exclude files such as those generated by an IDE, use
-# $GIT_DIR/info/exclude or the core.excludesFile configuration variable as
-# described in https://git-scm.com/docs/gitignore
-
-# python specific
-*.egg-info
-*.pot
-*.py[co]
-.tox/
-__pycache__
-MANIFEST
-.coverage
-cache/
-
-# Django specific
-dist/
-docs/_build/
-docs/locale/
-tests/coverage_html/
-tests/.coverage
-build/
-static/
-tests/report/
-*.sqlite3
-env/
-static/
-
-# project specific
-env-grady/
-env/
-scripts/
-*.csv
-.importer*
-
 # operation system
 .DS_Store
 
 # ide specific
 *.sublime-*
 .idea/
-
-# Node specific
-node_modules/
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8fb02b54899d0a570bca8622b67179bed8073272..404998d96a6ab3ddaf18c05d28bc2a053618cc56 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,41 +6,58 @@ stages:
 variables:
         IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
 
-build:
+# ============================= Building section ============================= #
+build_backend:
         image: docker:latest
         stage: build
         script:
                 - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
-                - docker build -t $IMAGE_TAG backend/
+                - docker build -t $IMAGE_TAG .
                 - docker push $IMAGE_TAG
 
-
-.test_template: &test_definition
+# ============================== Testing section ============================= #
+# ----------------------------- Backend subsection --------------------------- #
+.test_template_backend: &test_definition_backend
         stage: test
         image: $IMAGE_TAG
+        before_script:
+                - cd backend/
 
 test_coverage:
-        <<: *test_definition
+        <<: *test_definition_backend
         services:
                 - postgres:9.5
         script:
-                - cd backend/
                 - coverage run manage.py test --noinput
                 - coverage report --skip-covered
+        artifacts:
+                paths:
+                - .coverage/
 
 test_pylint:
-        <<: *test_definition
+        <<: *test_definition_backend
         script:
-                - cd backend/
                 - pylint core || exit 0
 
 test_prospector:
-        <<: *test_definition
+        <<: *test_definition_backend
         script:
-                - cd backend/
                 - prospector --uses django || exit 0
 
+# ----------------------------- Frontend subsection -------------------------- #
+.test_template_frontend: &test_definition_frontend
+        image: node:carbon-alpine
+        stage: test
+        before_script:
+                - cd frontend/
+
+test_frontend:
+        <<: *test_definition_frontend
+        script:
+                - yarn install
+                - yarn test --single-run
 
+# ============================== Staging section ============================= #
 .staging_template: &staging_definition
         stage: staging
         image: docker:latest
diff --git a/backend/Dockerfile b/Dockerfile
similarity index 67%
rename from backend/Dockerfile
rename to Dockerfile
index d56c36bcbe33d64601584bade182c6eb8fdce1e3..acec75a13f543e9177e51379f3f534c70ba76d44 100644
--- a/backend/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,16 @@
 # Build Python files
 FROM python:3.6 as python
-COPY requirements.txt .
+COPY backend/requirements.txt .
 RUN pip install -r requirements.txt
 RUN curl https://gitlab.gwdg.de/snippets/51/raw --output words
 
-# Retrieve noes files
-FROM node:latest as node
-COPY package.json .
-RUN yarn
+FROM node:carbon as node
+
+WORKDIR /app/
+COPY frontend/ .
+
+RUN npm install
+RUN npm run build
 
 # Now fetch other files and build on small image
 FROM python:3.6-alpine
@@ -22,14 +25,11 @@ RUN apk update \
   && apk del build-deps
 
 RUN mkdir -p /usr/share/dict
-RUN mkdir /code
-WORKDIR /code
+WORKDIR /code/backend
 
 COPY . /code
 COPY --from=python /root/.cache /root/.cache
 COPY --from=python /words /usr/share/dict/words
-# TODO this won't be necessarry anymore once merged with development
-# since the node_modules are served form the Project Root there
-COPY --from=node   /node_modules core/static/node_modules
+COPY --from=node /app/dist /code/backend/static
 
 RUN pip install -r requirements.txt && rm -rf /root/.cache
diff --git a/backend/.gitignore b/backend/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..438bae1f35383978b491783079cc5ab16c0546a6
--- /dev/null
+++ b/backend/.gitignore
@@ -0,0 +1,27 @@
+# python specific
+*.egg-info
+*.pot
+*.py[co]
+.tox/
+__pycache__
+MANIFEST
+.coverage
+cache/
+
+# Django specific
+dist/
+docs/_build/
+docs/locale/
+tests/coverage_html/
+tests/.coverage
+build/
+tests/report/
+*.sqlite3
+static/
+
+# project specific
+env-grady/
+env/
+scripts/
+*.csv
+.importer*
diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml
deleted file mode 100644
index f4bf724fa53027d40d834de7c5d669a84aa362f5..0000000000000000000000000000000000000000
--- a/backend/docker-compose.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-version: '3'
-
-services:
-  postgres:
-    image: postgres:9.5
-  web:
-    build: .
-    command:
-      - /bin/sh
-      - -c
-      - |
-        python manage.py collectstatic --ignore node_modules --noinput --clear
-        python manage.py compress --force
-        python manage.py migrate --noinput
-        python manage.py loaddata core/fixtures/testdata-groups.json
-        python manage.py loaddata core/fixtures/testdata-user.json
-        python manage.py loaddata core/fixtures/testdata-core.json
-        gunicorn --bind 0.0.0.0:8000 grady.wsgi:application
-    ports:
-      - "8000:8000"
-    volumes:
-      - /var/www/static:/code/static
-    depends_on:
-      - postgres
diff --git a/backend/package.json b/backend/package.json
deleted file mode 100644
index 6e3d256059fccec3c5191f3df873fc61a8a3819a..0000000000000000000000000000000000000000
--- a/backend/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "name": "grady",
-  "version": "0.4.2",
-  "description": "A new way to correct programming exams",
-  "main": "index.js",
-  "repository": "https://gitlab.gwdg.de/j.michal/grady.git",
-  "author": "Jan Maximilian Michal",
-  "license": "MIT",
-  "dependencies": {
-    "ace-editor-builds": "^1.2.4",
-    "bootstrap": "4.0.0-beta.2",
-    "datatables.net": "^1.10.15",
-    "datatables.net-bs4": "^1.10.15",
-    "popper.js": "^1.12.3"
-  }
-}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d85cfb636e4bbdaba7325592190f96790d8520cb
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,19 @@
+version: '3'
+
+services:
+  postgres:
+    image: postgres:9.5
+  web:
+    build: .
+    command:
+      - /bin/sh
+      - -c
+      - |
+        python manage.py migrate --noinput
+        gunicorn --bind 0.0.0.0:8000 grady.wsgi:application &
+        cd static/ && python -m http.server 8080
+    ports:
+      - "8000:8000"
+      - "8080:8080"
+    depends_on:
+      - postgres