diff --git a/.dbrepo2/deploy b/.dbrepo2/deploy
deleted file mode 100755
index 2cda49aec781a27fc0a36336a6e3990003bb863e..0000000000000000000000000000000000000000
--- a/.dbrepo2/deploy
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-
-# set version
-TAG=latest
-
-# tear everything down
-echo "Removing all data ..."
-/bin/bash teardown
-docker system prune -f --volumes || true
-
-echo "Pulling new images ..."
-docker pull "dbrepo/analyse-service:${TAG}"
-docker pull "dbrepo/authentication-service:${TAG}"
-docker pull "dbrepo/metadata-db:${TAG}"
-docker pull "dbrepo/ui:${TAG}"
-docker pull "dbrepo/ui-proxy:${TAG}"
-docker pull "dbrepo/identifier-service:${TAG}"
-docker pull "dbrepo/container-service:${TAG}"
-docker pull "dbrepo/database-service:${TAG}"
-docker pull "dbrepo/discovery-service:${TAG}"
-docker pull "dbrepo/gateway-service:${TAG}"
-docker pull "dbrepo/query-service:${TAG}"
-docker pull "dbrepo/table-service:${TAG}"
-docker pull "dbrepo/units-service:${TAG}"
-docker pull "dbrepo/broker-service:${TAG}"
-docker pull "dbrepo/metadata-service:${TAG}"
-echo "Pulled new images"
-
-# deploy dbrepo
-echo "Deploy DBRepo ..."
-docker compose -f ./docker-compose.dbrepo2.yml up -d
-
-# clone tuw specific deployment
-git -C "/home/demo/dbrepo-tuw" pull || git clone ssh://git@gitlab.tuwien.ac.at:822/martin.weise/dbrepo-tuw.git "/home/demo/dbrepo-tuw"
-cd /home/demo/dbrepo-tuw && git checkout dev
-
-# build tuw specific deployment
-docker compose -f /home/demo/dbrepo-tuw/docker-compose.dbrepo2.yml build || exit 3
-docker compose -f /home/demo/dbrepo-tuw/docker-compose.dbrepo2.yml up -d || exit 4
-echo "Deployed TU Wien specific deployment"
\ No newline at end of file
diff --git a/.dbrepo2/known_hosts b/.dbrepo2/known_hosts
deleted file mode 100644
index d17a72e2de908c97eb551254d51770e6725332b8..0000000000000000000000000000000000000000
--- a/.dbrepo2/known_hosts
+++ /dev/null
@@ -1,6 +0,0 @@
-gitlab.tuwien.ac.at ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKslN24njaMeH0xyVBO/lzeQ5/X/6UFkiz2qdcWihjT28slO/6pFBAxSzPUTBeVJWxKJgX9N+Hm65S9/Z2521E8Y9F56dcrOgeQBZ4GbLPSbEZIFN/71VL4cOh6tLahNZsAwd6y2Zi5XTAqho31VWfdCZkegZB3dNzLfOuC0t3KpxEAmWus5j8InNYDTBIy6U351/3h3oy32EdLvLpaHP+oy+QFAqXOlcXlKwHTfv9SSchQRLfWzrL4hVvohbCwMDBBvIP8J0WQ9mV95xfcwuipMWP3TksDGbst2MQ6HRXZ+yfie9Vgzg+++AjpHXQCMdalEmedNxCmxbHWYJxFHUV
-gitlab.tuwien.ac.at ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC+2QClFaM3ZNQ6nl3nHkZdFSyNP26uHPzJEUBu9J4yC1ON9GPHb2P3rC//wS819e3LWP4PXb8ug/EyEjWN30MA=
-gitlab.tuwien.ac.at ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILTzOKU3zEYNo1xy8rxZsa8D0/y4EN4oB0E7wgWCkOpZ
-dbrepo2.ec.tuwien.ac.at ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5GFfX4xmYeQdQQL81heBjKb4d1M8xjOjF4lpfNmc3/wyCPtP/dt4r3nkcOW3X14yPximy8BlArsPk4ul14BWNI9yrU5VA1FLlWq9Og6SfMJ1EAUNsePDd3qCpr/ljlydS3kWCVrXD1bNO0kQ3/36e9l64BDvZXyhI3n9DvkPO93n9xJ151IC9IwjnSzJQPghboUDRiYwT2B9wt+uC+k7tTV5tQH5kJk8fEa8nMyHOc8aD2miHubrcQJrYO/fv+vVxVWJKtSdz22wuvFnj8SfGClxbT8cfMo8X+LpIQOH8VYwIZVznuSlnNYOOYO6EGYyRnqud6oz0B5RUbwyeBhtAgZW1C1OXO9DVDLnazzFxJIzwhwyZCPurpLpP7bd6P+oFWy1A7bxIhfvdduEDE80vEOPrBl44TDe6RJR6QILtdUn9rrvcV/kgfj04zkQJjqMvX2pdCpdMIU1Pm+NQ53k3oOap7j9UHnpWX7C3mk76ueQddQxWZUhGsrFUAYSJfus=
-dbrepo2.ec.tuwien.ac.at ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOGTeKw2aKnykIUmvLiBNaGbq3xlSEsnD1M1HiZsPJ9ZtfSV12y9F0yutV4j68Rb+eHbyOxoyVekfl19ODDvXLM=
-dbrepo2.ec.tuwien.ac.at ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPpSoshRRtQBj4ebWeaWoeGr1XFIlx3L+BXV69fafBGr
\ No newline at end of file
diff --git a/.fda-deployment/clean b/.fda-deployment/clean
deleted file mode 100755
index 03506fc6ef3a480eea7269f90c2f8a99209a1bc0..0000000000000000000000000000000000000000
--- a/.fda-deployment/clean
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-docker container stop $(docker container ls -aq) || true
-docker container rm $(docker container ls -aq) || true
-docker volume rm $(docker volume ls -q) || true
diff --git a/.fda-deployment/clean-tmp b/.fda-deployment/clean-tmp
deleted file mode 100755
index ac34df7e9c815917e5908b129f3502c18e97e2f4..0000000000000000000000000000000000000000
--- a/.fda-deployment/clean-tmp
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-FILES=$(cd /tmp && find -exec basename '{}' ';' 2>/dev/null | egrep '^.{32}$' | egrep "^([a-z0-9]+)$")
-for file in $FILES; do
-  rm -f /tmp/$file
-  echo "Removed /tmp/${file}"
-done
\ No newline at end of file
diff --git a/.fda-deployment/crontab b/.fda-deployment/crontab
deleted file mode 100644
index bbc97b1a429e174b4a42e99503e70098f1acb441..0000000000000000000000000000000000000000
--- a/.fda-deployment/crontab
+++ /dev/null
@@ -1,2 +0,0 @@
-0 2 * * *       /usr/bin/make -C /home/rocky/fda-services teardown
-1 2 * * *       /usr/bin/make -C /home/rocky/fda-services run
\ No newline at end of file
diff --git a/.fda-deployment/fda-authentication-service/install_cert b/.fda-deployment/fda-authentication-service/install_cert
deleted file mode 100755
index f52db602f44a1c08cb4cb4e8e8cc6e17e45d190b..0000000000000000000000000000000000000000
--- a/.fda-deployment/fda-authentication-service/install_cert
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/bash
-TMP_CERT_LOCATION="/root/keys"
-TMP_SAML_LOCATION="/root/keys"
-KEY_STORE_LOCATION="/tmp/dbrepo.jks"
-KEY_STORE_PASS="dbrepo"
-CERT_LOCATION="/etc/letsencrypt/live/dbrepo.ossdip.at"
-SAML_KEY="/root/keys/saml_sign.key"
-SAML_PUB="/root/keys/saml_sign.cer"
-TU_SAML_CERT="./fda-authentication-service/rest-service/src/main/resources/saml/tu.crt"
-
-# PLACE
-sudo mkdir -p "${TMP_CERT_LOCATION}"
-sudo mkdir -p "${TMP_SAML_LOCATION}"
-
-# REQUEST
-sudo certbot certonly --standalone --preferred-challenges http -d dbrepo.ossdip.at \
-		-m martin.weise@tuwien.ac.at --agree-tos --keep-until-expiring
-
-# CONVERT PKCS12
-sudo openssl pkcs12 -export -out "${TMP_SAML_LOCATION}/saml.p12" -in "${SAML_PUB}" \
-  -inkey "${SAML_KEY}" -passout "pass:${KEY_STORE_PASS}"
-
-# CONVERT PKCS12
-sudo openssl pkcs12 -export -out "${TMP_CERT_LOCATION}/cert.p12" -in "${CERT_LOCATION}/cert.pem" \
-  -inkey "${CERT_LOCATION}/privkey.pem" -passout "pass:${KEY_STORE_PASS}"
-
-# FIX PERMISSIONS
-sudo chmod -R 644 "${TMP_CERT_LOCATION}"
-sudo chmod -R 644 "${TMP_SAML_LOCATION}"
-
-# IMPORT SSL SIGN PRIVKEY
-sudo keytool -noprompt -importkeystore -deststorepass "${KEY_STORE_PASS}" -destkeypass "${KEY_STORE_PASS}" \
-  -destkeystore "${KEY_STORE_LOCATION}" -srckeystore "${TMP_CERT_LOCATION}/cert.p12" -srcstoretype PKCS12 \
-  -srcstorepass "${KEY_STORE_PASS}" -alias 1 -destalias ssl
-
-# IMPORT SAML MESSAGE SIGN PRIVKEY
-sudo keytool -noprompt -importkeystore -deststorepass "${KEY_STORE_PASS}" -destkeypass "${KEY_STORE_PASS}" \
-  -destkeystore "${KEY_STORE_LOCATION}" -srckeystore "${TMP_SAML_LOCATION}" -srcstoretype PKCS12 \
-  -srcstorepass "${KEY_STORE_PASS}" -alias 1 -destalias saml
-
-# IMPORT METADATA VERIFICATION PUBKEY
-sudo keytool -noprompt -importcert -file "${TU_SAML_CERT}" -storepass "${KEY_STORE_PASS}" \
-  -keystore "${KEY_STORE_LOCATION}" -alias tu
-
-# OWNERSHIP
-sudo chown centos:docker "${TMP_CERT_LOCATION}"
-sudo chown centos:docker "${TMP_SAML_LOCATION}"
-sudo chown centos:docker "${KEY_STORE_LOCATION}"
-
-# TRUST LET'S ENCRYPT
-sudo keytool -noprompt -import -alias letsencrypt -keystore "${KEY_STORE_LOCATION}" -storepass "${KEY_STORE_PASS}" \
-  -file "${CERT_LOCATION}/chain.pem"
diff --git a/.fda-deployment/fda-authentication-service/install_smtp b/.fda-deployment/fda-authentication-service/install_smtp
deleted file mode 100755
index 22b0afaa76093e4c311b2451e365733963b15b49..0000000000000000000000000000000000000000
--- a/.fda-deployment/fda-authentication-service/install_smtp
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-sudo cat /root/smtp.secret >> ./.env
diff --git a/.fda-deployment/fda-ui/install_cert b/.fda-deployment/fda-ui/install_cert
deleted file mode 100755
index 92553123718052ab77978aea4d8ad3a699c0c816..0000000000000000000000000000000000000000
--- a/.fda-deployment/fda-ui/install_cert
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-CA_PATH="/etc/letsencrypt/live/dbrepo.ossdip.at"
-
-sudo certbot certonly --standalone --preferred-challenges http -d dbrepo.ossdip.at --agree-tos --keep-until-expiring
-
-KEY=$(sudo sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' "${CA_PATH}/privkey.pem")
-CERT=$(sudo sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' "${CA_PATH}/cert.pem")
-
-cat << EOF
-UI_KEY="${KEY}"
-UI_CERT="${CERT}"
-EOF
\ No newline at end of file
diff --git a/.fda-deployment/hosts b/.fda-deployment/hosts
deleted file mode 100644
index 40da214c6af6d90f416cca86829a26ae06edec66..0000000000000000000000000000000000000000
--- a/.fda-deployment/hosts
+++ /dev/null
@@ -1,7 +0,0 @@
-# FDA USERDB
-172.28.0.2      fda-userdb-weather-aus
-172.28.0.3      fda-userdb-infection
-172.28.0.4      fda-userdb-air
-172.28.0.5      fda-userdb-u01
-172.28.0.6      fda-userdb-u02
-172.28.0.7      fda-userdb-u03
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index e372ff156bcb23dc9ed7f1706104b725510dcdcf..ae9e683f84116b3457f7a61d93748f2e47c31c2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,7 @@ target/
 !.mvn/wrapper/maven-wrapper.jar
 !**/src/main/**/target/
 !**/src/test/**/target/
-
+dbrepo-*
 # Notebooks
 .jupyter/
 .pytest_cache/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c18ce65e3b9ed6b126c279b57784086a06dc3f0e..1967e4afeacc6e81ad68eca7d0ccb97337f32f3d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,7 +5,6 @@ before_script:
   - "mvn --version"
   - "python3 --version"
   - "df / -h"
-  - "grep -rnw '@Test' | wc -l"
 
 variables:
   HOSTALIASES: ./hosts
@@ -23,76 +22,77 @@ stages:
   - build-backend
   - build-frontend
   - test-backend
+  - test-frontend
   - build-docker
   - release
 
-build-backend-metadata-db:
+build-metadata-db:
   stage: build-backend
   script:
-    - "make build-backend-metadata-db"
+    - "make build-metadata-db"
 
-build-backend-authentication:
+build-authentication-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-authentication"
+    - "make build-authentication-service"
 
-build-backend-identifier:
+build-identifier-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-identifier"
+    - "make build-identifier-service"
 
-build-backend-container:
+build-container-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-container"
+    - "make build-container-service"
 
-build-backend-database:
+build-database-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-database"
+    - "make build-database-service"
 
-build-backend-discovery:
+build-discovery-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-discovery"
+    - "make build-discovery-service"
 
-build-backend-gateway:
+build-gateway-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-gateway"
+    - "make build-gateway-service"
 
-build-backend-query:
+build-query-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-query"
+    - "make build-query-service"
 
-build-backend-table:
+build-table-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-table"
+    - "make build-table-service"
 
-build-backend-metadata:
+build-metadata-service:
   stage: build-backend
   needs:
-    - build-backend-metadata-db
+    - build-metadata-db
   script:
-    - "make build-backend-metadata"
+    - "make build-metadata-service"
 
 build-semantics-service:
   stage: build-backend
@@ -107,7 +107,7 @@ build-analyse-service:
 test-backend-authentication:
   stage: test-backend
   needs:
-    - build-backend-authentication
+    - build-authentication-service
   script:
     - "make test-authentication-service"
     - "cat ./fda-authentication-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -120,10 +120,11 @@ test-backend-authentication:
     reports:
       junit: ./fda-authentication-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
-test-backend-identifier:
+
+test-identifier-service:
   stage: test-backend
   needs:
-    - build-backend-authentication
+    - build-authentication-service
   script:
     - "make test-identifier-service"
     - "cat ./fda-identifier-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -137,10 +138,10 @@ test-backend-identifier:
       junit: ./fda-identifier-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
 
-test-backend-container:
+test-container-service:
   stage: test-backend
   needs:
-    - build-backend-container
+    - build-container-service
   script:
     - "make test-container-service"
     - "cat ./fda-container-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -154,10 +155,10 @@ test-backend-container:
       junit: ./fda-container-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
 
-test-backend-database:
+test-database-service:
   stage: test-backend
   needs:
-    - build-backend-database
+    - build-database-service
   script:
     - "docker pull elasticsearch:7.13.4"
     - "make test-database-service"
@@ -171,11 +172,12 @@ test-backend-database:
     reports:
       junit: ./fda-database-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
+  timeout: 2 hour
 
-test-backend-discovery:
+test-discovery-service:
   stage: test-backend
   needs:
-    - build-backend-discovery
+    - build-discovery-service
   script:
     - "make test-discovery-service"
     - "cat ./fda-discovery-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -189,10 +191,10 @@ test-backend-discovery:
       junit: ./fda-discovery-service/discovery/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
 
-test-backend-query:
+test-query-service:
   stage: test-backend
   needs:
-    - build-backend-query
+    - build-query-service
   script:
     - "make test-query-service"
     - "cat ./fda-query-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -205,11 +207,12 @@ test-backend-query:
     reports:
       junit: ./fda-query-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
+  timeout: 2 hour
 
-test-backend-table:
+test-table-service:
   stage: test-backend
   needs:
-    - build-backend-table
+    - build-table-service
   script:
     - "make test-table-service"
     - "cat ./fda-table-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -223,10 +226,10 @@ test-backend-table:
       junit: ./fda-table-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
 
-test-backend-metadata:
+test-metadata-service:
   stage: test-backend
   needs:
-    - build-backend-metadata
+    - build-metadata-service
   script:
     - "make test-metadata-service"
     - "cat ./fda-metadata-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -240,10 +243,10 @@ test-backend-metadata:
       junit: ./fda-metadata-service/rest-service/target/surefire-reports/TEST-*.xml
   coverage: '/Total.*?([0-9]{1,3})%/'
 
-test-backend-gateway:
+test-gateway-service:
   stage: test-backend
   needs:
-    - build-backend-gateway
+    - build-gateway-service
   script:
     - "make test-gateway-service"
     - "cat ./fda-gateway-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
@@ -289,19 +292,35 @@ test-analyse-service:
       junit: ./fda-analyse-service/report.xml
   coverage: '/TOTAL.*?([0-9]{1,3})%/'
 
+test-frontend:
+  stage: test-frontend
+  needs:
+    - build-frontend
+  script:
+    - "make test-frontend"
+    - "cat ./fda-ui/coverage.txt | grep -o 'Lines[^%]*%'"
+  artifacts:
+    when: always
+    paths:
+      - ./fda-analyse-service/report.xml
+    expire_in: 1 days
+    reports:
+      junit: ./fda-analyse-service/report.xml
+  coverage: '/TOTAL.*?([0-9]{1,3})%/'
+
 build-docker:
   stage: build-docker
   needs:
-    - build-backend-metadata-db
-    - build-backend-authentication
-    - build-backend-identifier
-    - build-backend-container
-    - build-backend-database
-    - build-backend-discovery
-    - build-backend-gateway
-    - build-backend-query
-    - build-backend-table
-    - build-backend-metadata
+    - build-metadata-db
+    - build-authentication-service
+    - build-identifier-service
+    - build-container-service
+    - build-database-service
+    - build-discovery-service
+    - build-gateway-service
+    - build-query-service
+    - build-table-service
+    - build-metadata-service
     - build-semantics-service
     - build-analyse-service
   script:
diff --git a/.gitlab/jacoco2cobertura.py b/.gitlab/jacoco2cobertura.py
deleted file mode 100755
index 76ad75a70583ae4689952ef037ecb241eec48897..0000000000000000000000000000000000000000
--- a/.gitlab/jacoco2cobertura.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env python3
-import sys
-import xml.etree.ElementTree as ET
-import re
-import os.path
-
-# branch-rate="0.0" complexity="0.0" line-rate="1.0"
-# branch="true" hits="1" number="86"
-
-def find_lines(j_package, filename):
-    """Return all <line> elements for a given source file in a package."""
-    lines = list()
-    sourcefiles = j_package.findall("sourcefile")
-    for sourcefile in sourcefiles:
-        if sourcefile.attrib.get("name") == os.path.basename(filename):
-            lines = lines + sourcefile.findall("line")
-    return lines
-
-def line_is_after(jm, start_line):
-    return int(jm.attrib.get('line', 0)) > start_line
-
-def method_lines(jmethod, jmethods, jlines):
-    """Filter the lines from the given set of jlines that apply to the given jmethod."""
-    start_line = int(jmethod.attrib.get('line', 0))
-    larger     = list(int(jm.attrib.get('line', 0)) for jm in jmethods if line_is_after(jm, start_line))
-    end_line   = min(larger) if len(larger) else 99999999
-
-    for jline in jlines:
-        if start_line <= int(jline.attrib['nr']) < end_line:
-            yield jline
-
-def convert_lines(j_lines, into):
-    """Convert the JaCoCo <line> elements into Cobertura <line> elements, add them under the given element."""
-    c_lines = ET.SubElement(into, 'lines')
-    for jline in j_lines:
-        mb = int(jline.attrib['mb'])
-        cb = int(jline.attrib['cb'])
-        ci = int(jline.attrib['ci'])
-
-        cline = ET.SubElement(c_lines, 'line')
-        cline.set('number', jline.attrib['nr'])
-        cline.set('hits', '1' if ci > 0 else '0') # Probably not true but no way to know from JaCoCo XML file
-
-        if mb + cb > 0:
-            percentage = str(int(100 * (float(cb) / (float(cb) + float(mb))))) + '%'
-            cline.set('branch',             'true')
-            cline.set('condition-coverage', percentage + ' (' + str(cb) + '/' + str(cb + mb) + ')')
-
-            cond = ET.SubElement(ET.SubElement(cline, 'conditions'), 'condition')
-            cond.set('number',   '0')
-            cond.set('type',     'jump')
-            cond.set('coverage', percentage)
-        else:
-            cline.set('branch', 'false')
-
-def guess_filename(path_to_class):
-    m = re.match('([^$]*)', path_to_class)
-    return (m.group(1) if m else path_to_class) + '.java'
-
-def add_counters(source, target):
-    target.set('line-rate',   counter(source, 'LINE'))
-    target.set('branch-rate', counter(source, 'BRANCH'))
-    target.set('complexity', counter(source, 'COMPLEXITY', sum))
-
-def fraction(covered, missed):
-    return covered / (covered + missed)
-
-def sum(covered, missed):
-    return covered + missed
-
-def counter(source, type, operation=fraction):
-    cs = source.findall('counter')
-    c = next((ct for ct in cs if ct.attrib.get('type') == type), None)
-
-    if c is not None:
-        covered = float(c.attrib['covered'])
-        missed  = float(c.attrib['missed'])
-
-        return str(operation(covered, missed))
-    else:
-        return '0.0'
-
-def convert_method(j_method, j_lines):
-    c_method = ET.Element('method')
-    c_method.set('name',      j_method.attrib['name'])
-    c_method.set('signature', j_method.attrib['desc'])
-
-    add_counters(j_method, c_method)
-    convert_lines(j_lines, c_method)
-
-    return c_method
-
-def convert_class(j_class, j_package):
-    c_class = ET.Element('class')
-    c_class.set('name',     j_class.attrib['name'].replace('/', '.'))
-    c_class.set('filename', guess_filename(j_class.attrib['name']))
-
-    all_j_lines = list(find_lines(j_package, c_class.attrib['filename']))
-
-    c_methods   = ET.SubElement(c_class, 'methods')
-    all_j_methods = list(j_class.findall('method'))
-    for j_method in all_j_methods:
-        j_method_lines = method_lines(j_method, all_j_methods, all_j_lines)
-        c_methods.append(convert_method(j_method, j_method_lines))
-
-    add_counters(j_class, c_class)
-    convert_lines(all_j_lines, c_class)
-
-    return c_class
-
-def convert_package(j_package):
-    c_package = ET.Element('package')
-    c_package.attrib['name'] = j_package.attrib['name'].replace('/', '.')
-
-    c_classes = ET.SubElement(c_package, 'classes')
-    for j_class in j_package.findall('class'):
-        c_classes.append(convert_class(j_class, j_package))
-
-    add_counters(j_package, c_package)
-
-    return c_package
-
-def convert_root(source, target, source_roots):
-    target.set('timestamp', str(int(source.find('sessioninfo').attrib['start']) / 1000))
-
-    sources     = ET.SubElement(target, 'sources')
-    for s in source_roots:
-        ET.SubElement(sources, 'source').text = s
-
-    packages = ET.SubElement(target, 'packages')
-    for package in source.findall('package'):
-        packages.append(convert_package(package))
-
-    add_counters(source, target)
-
-def jacoco2cobertura(filename, source_roots):
-    if filename == '-':
-        root = ET.fromstring(sys.stdin.read())
-    else:
-        tree = ET.parse(filename)
-        root = tree.getroot()
-
-    into = ET.Element('coverage')
-    convert_root(root, into, source_roots)
-    print(ET.tostring(into, encoding='utf8', method='xml').decode("utf-8"))
-
-if __name__ == '__main__':
-    if len(sys.argv) < 2:
-        print("Usage: cover2cover.py FILENAME [SOURCE_ROOTS]")
-        sys.exit(1)
-
-    filename    = sys.argv[1]
-    source_roots = sys.argv[2:] if 2 < len(sys.argv) else '.'
-
-    jacoco2cobertura(filename, source_roots)
\ No newline at end of file
diff --git a/.gitlab/tests/test_containers.py b/.gitlab/tests/test_containers.py
deleted file mode 100644
index dd4e1a97cc9cd2ea9a3ff9740b8720f600e62a35..0000000000000000000000000000000000000000
--- a/.gitlab/tests/test_containers.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/bin/env python3
-from api_container.api.container_endpoint_api import ContainerEndpointApi
-from api_database.api.database_endpoint_api import DatabaseEndpointApi
-import time
-
-container = ContainerEndpointApi()
-database = DatabaseEndpointApi()
-
-def create_container():
-    response = container.create1({
-        "name": "Pilot Factory Data",
-        "repository": "mariadb",
-        "tag": "10.5"
-    })
-    print("created container with id %d" % response.id)
-    return response
-
-
-def start_container(container_id):
-    response = container.modify({
-        "action": "start"
-    }, container_id)
-    print("... starting")
-    time.sleep(5)
-    print("started container with id %d" % response.id)
-    return response
-
-
-def create_database(container_id, is_public=True):
-    response = database.create({
-        "name": "Pilot Factory Data",
-        "is_public": is_public
-    }, container_id)
-    print("created database with id %d" % response.id)
-    return response
-
-token = ""  # keep
-
-from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi
-from api_authentication.api.user_endpoint_api import UserEndpointApi
-import uuid
-
-authentication = AuthenticationEndpointApi()
-user = UserEndpointApi()
-
-def create_user(username):
-    response = user.register({
-        "username": username,
-        "password": username,
-        "email": username + "@gmail.com"
-    })
-    print("created user with id %d" % response.id)
-    return response
-
-
-def auth_user(username):
-    response = authentication.authenticate_user1({
-        "username": username,
-        "password": username
-    })
-    print("authenticated user with id %d" % response.id)
-    token = response.token
-    container.api_client.default_headers = {"Authorization": "Bearer " + token}
-    database.api_client.default_headers = {"Authorization": "Bearer " + token}
-    return response
-
-
-def find_database(container_id, database_id):
-    response = database.find_by_id(container_id, database_id)
-    print("found database with id %d" % response.id)
-    return response
-
-
-def update_database(container_id, database_id):
-    response = database.update({
-        "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).",
-        "publisher": "Technical University of Vienna",
-        "license": {
-            "identifier": "CC0-1.0",
-            "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode"
-        },
-        "language": "en",
-        "publication_year": 2022
-    }, container_id, database_id)
-    print("updated database with id %d" % response.id)
-    return response
-
-
-def test_containers():
-    username = str(uuid.uuid1()).replace("-", "")
-    uid = create_user(username).id
-    auth_user(username)
-    # container 1
-    cid = create_container().id
-    start_container(cid)
-    dbid = create_database(cid).id
-    update_database(cid, dbid)
diff --git a/.gitlab/tests/test_query.py b/.gitlab/tests/test_query.py
deleted file mode 100644
index 283f311b6554b76393568be0efaf1b44f24077a1..0000000000000000000000000000000000000000
--- a/.gitlab/tests/test_query.py
+++ /dev/null
@@ -1,284 +0,0 @@
-#!/bin/env python3
-
-import time
-import os
-import shutil
-import uuid
-
-from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi
-from api_authentication.api.user_endpoint_api import UserEndpointApi
-from api_container.api.container_endpoint_api import ContainerEndpointApi
-from api_database.api.database_endpoint_api import DatabaseEndpointApi
-from api_table.api.table_endpoint_api import TableEndpointApi
-from api_query.api.table_data_endpoint_api import TableDataEndpointApi
-from api_query.api.query_endpoint_api import QueryEndpointApi
-from api_query.api.table_history_endpoint_api import TableHistoryEndpointApi
-from api_identifier.api.identifier_endpoint_api import IdentifierEndpointApi
-from api_identifier.api.persistence_endpoint_api import PersistenceEndpointApi
-from api_query.api.view_endpoint_api import ViewEndpointApi
-from api_query.rest import ApiException
-
-authentication = AuthenticationEndpointApi()
-user = UserEndpointApi()
-container = ContainerEndpointApi()
-database = DatabaseEndpointApi()
-table = TableEndpointApi()
-query = QueryEndpointApi()
-history = TableHistoryEndpointApi()
-data = TableDataEndpointApi()
-identifier = IdentifierEndpointApi()
-persistence = PersistenceEndpointApi()
-view = ViewEndpointApi()
-
-token = ""  # keep
-
-
-def create_user(username):
-    response = user.register({
-        "username": username,
-        "password": username,
-        "email": username + "@gmail.com"
-    })
-    print("created user with id %d" % response.id)
-    return response
-
-
-def update_password(user_id, password):
-    response = user.update_password({
-        "password": password
-    }, user_id)
-    print("updated password for user with id %d" % user_id)
-    return response
-
-
-def auth_user(username):
-    response = authentication.authenticate_user1({
-        "username": username,
-        "password": username
-    })
-    print("authenticated user with id %d" % response.id)
-    token = response.token
-    container.api_client.default_headers = {"Authorization": "Bearer " + token}
-    database.api_client.default_headers = {"Authorization": "Bearer " + token}
-    table.api_client.default_headers = {"Authorization": "Bearer " + token}
-    data.api_client.default_headers = {"Authorization": "Bearer " + token}
-    query.api_client.default_headers = {"Authorization": "Bearer " + token}
-    identifier.api_client.default_headers = {"Authorization": "Bearer " + token}
-    user.api_client.default_headers = {"Authorization": "Bearer " + token}
-    persistence.api_client.default_headers = {"Authorization": "Bearer " + token}
-    history.api_client.default_headers = {"Authorization": "Bearer " + token}
-    view.api_client.default_headers = {"Authorization": "Bearer " + token}
-    return response
-
-
-def create_container():
-    response = container.create1({
-        "name": "Pilot Factory Data",
-        "repository": "mariadb",
-        "tag": "10.5"
-    })
-    print("created container with id %d" % response.id)
-    return response
-
-
-def start_container(container_id):
-    response = container.modify({
-        "action": "start"
-    }, container_id)
-    print("... starting")
-    time.sleep(5)
-    print("started container with id %d" % response.id)
-    return response
-
-
-def create_database(container_id, is_public=True):
-    response = database.create({
-        "name": "Pilot Factory Data",
-        "is_public": is_public
-    }, container_id)
-    print("created database with id %d" % response.id)
-    return response
-
-
-def find_database(container_id, database_id):
-    response = database.find_by_id(container_id, database_id)
-    print("found database with id %d" % response.id)
-    return response
-
-
-def update_database(container_id, database_id):
-    response = database.update({
-        "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).",
-        "publisher": "Technical University of Vienna",
-        "license": {
-            "identifier": "CC0-1.0",
-            "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode"
-        },
-        "language": "en",
-        "publication_year": 2022
-    }, container_id, database_id)
-    print("updated database with id %d" % response.id)
-    return response
-
-
-def create_table(container_id, database_id, columns=None):
-    if columns is None:
-        columns = [{
-            "name": "Date",
-            "type": "date",
-            "dfid": 1,
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Location",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Parameter",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Interval",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Unit",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Value",
-            "type": "decimal",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Status",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }]
-    response = table.create({
-        "name": "Airquality " + str(uuid.uuid1()),
-        "description": "Airquality in Zürich, Switzerland",
-        "columns": columns
-    }, "Bearer " + token, container_id, database_id)
-    print("created table with id %d" % response.id)
-    return response
-
-
-def find_table(container_id, database_id, table_id):
-    response = table.find_by_id(container_id, database_id, table_id)
-    print("found table with id %d" % response.id)
-    return response
-
-
-def fill_table(container_id, database_id, table_id):
-    response = data.import_csv({
-        "location": "/path/to/data.csv",
-        "quote": "\"",
-        "null_element": "NA"
-        "separator": ",",
-    }, container_id, database_id, table_id)
-    print("filled table with id %d" % table_id)
-    return response
-
-
-def create_query(container_id, database_id, statement, page=0, size=3):
-    response = query.execute({
-        "statement": statement
-    }, container_id, database_id, page=page, size=size)
-    print("executed query with id %d" % response.id)
-    return response
-
-
-def delete_tuple(container_id, database_id, table_id, keys):
-    response = data.delete(keys, container_id, database_id, table_id)
-    print("deleted tuples for table with id %d" % table_id)
-    return response
-
-
-def download_query_data(container_id, database_id, query_id):
-    response = query.export1(container_id, database_id, query_id)
-    print("downloaded query data for query with id %d" % query_id)
-    return response
-
-
-def list_views(container_id, database_id):
-    response = view.find_all(container_id, database_id)
-    print("list views for database with id %d" % database_id)
-    return response
-
-
-def create_view(container_id, database_id, table_name):
-    response = view.create({
-        "name": "Air Quality " + str(uuid.uuid1()),
-        "query": "SELECT `date`, `parameter`, `value` FROM `" + table_name + "` WHERE `date` = '2021-10-02T14:00'",
-        "is_public": True
-    }, container_id, database_id)
-    print("created view with id %d" % response.id)
-    return response
-
-
-def data_view(container_id, database_id, view_id):
-    response = view.data(container_id, database_id, view_id)
-    print("retrieved data for view with id %d" % response.id)
-    return response
-
-
-def test_identifiers():
-    #
-    # create 1 user and 2 containers (public, private)
-    #
-    username = str(uuid.uuid1()).replace("-", "")
-    uid = create_user(username).id
-    auth_user(username)
-    # container 1
-    cid = create_container().id
-    start_container(cid)
-    dbid = create_database(cid).id
-    update_database(cid, dbid)
-    tid = create_table(cid, dbid).id
-    tname = find_table(cid, dbid, tid).internal_name
-    fill_table(cid, dbid, tid)
-    create_query(cid, dbid, "select `id` from `" + tname + "`")
-    create_query(cid, dbid, "select `date` from `" + tname + "`")
-    qid = create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "`").id
-    create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "` order by `date` asc")
-    create_query(cid, dbid, "select t.`date`, t.location, t.status from `" + tname + "` t group by t.`date` order by t.`date` asc")
-    create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "` group by `date`, `location` asc")
-    download_query_data(cid, dbid, qid)
-    # container 2 (=private)
-    cid = create_container().id
-    start_container(cid)
-    dbid = create_database(cid, False).id
-    update_database(cid, dbid)
-    tid = create_table(cid, dbid).id
-    tname = find_table(cid, dbid, tid).internal_name
-    fill_table(cid, dbid, tid)
-    qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id
-    qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id
-    vid = create_view(cid, dbid, tname).id
-    data_view(cid, dbid, vid)
-    list_views(cid, dbid)
-    for i in range(5, 10):
-        delete_tuple(cid, dbid, tid, {
-            "keys": {
-                "id": i
-            }
-        })
-        time.sleep(1)
-    delete_tuple(cid, dbid, tid, {
-        "keys": {
-            "location": "Schimmelstrasse"
-        }
-    })
diff --git a/.junit/hosts b/.junit/hosts
new file mode 100644
index 0000000000000000000000000000000000000000..701ef56fa315ea16163432c842816c946150d97f
--- /dev/null
+++ b/.junit/hosts
@@ -0,0 +1,10 @@
+###########################################################
+#                PLACE IN /etc/hosts                      #
+###########################################################
+
+172.30.0.5	dbrepo-userdb-u01
+172.30.0.6	dbrepo-userdb-u02
+172.30.0.7	dbrepo-userdb-u03
+172.30.0.8	dbrepo-userdb-u04
+172.31.0.2	dbrepo-broker-service
+172.31.0.3	dbrepo-search-service
\ No newline at end of file
diff --git a/.dbrepo2/teardown b/.junit/teardown
similarity index 100%
rename from .dbrepo2/teardown
rename to .junit/teardown
diff --git a/Makefile b/Makefile
index ec1921ff29552a4a0bd432d26a0c4708a4f15c36..a5bce8de2e48b1547e456f13be75256590b415c9 100644
--- a/Makefile
+++ b/Makefile
@@ -4,39 +4,36 @@ TAG ?= latest
 
 all:
 
-clean:
-	bash ./.dbrepo2/clean.sh
-
-build-backend: build-backend-metadata-db build-backend-database build-backend-query build-backend-table build-backend-identifier build-backend-authentication build-backend-container build-backend-discovery build-backend-gateway build-backend-metadata build-analyse-service
+build-backend: build-metadata-db build-database-service build-query-service build-table-service build-identifier-service build-authentication-service build-container-service build-discovery-service build-gateway-service build-metadata-service build-analyse-service
 
-build-backend-metadata-db:
+build-metadata-db:
 	mvn -f ./fda-metadata-db/pom.xml clean install
 
-build-backend-authentication: build-backend-metadata-db
+build-authentication-service: build-metadata-db
 	mvn -f ./fda-authentication-service/pom.xml clean package -DskipTests
 
-build-backend-identifier: build-backend-metadata-db
+build-identifier-service: build-metadata-db
 	mvn -f ./fda-identifier-service/pom.xml clean package -DskipTests
 
-build-backend-table: build-backend-metadata-db
+build-table-service: build-metadata-db
 	mvn -f ./fda-table-service/pom.xml clean package -DskipTests
 
-build-backend-container: build-backend-metadata-db
+build-container-service: build-metadata-db
 	mvn -f ./fda-container-service/pom.xml clean package -DskipTests
 
-build-backend-database: build-backend-metadata-db
+build-database-service: build-metadata-db
 	mvn -f ./fda-database-service/pom.xml clean package -DskipTests
 
-build-backend-discovery: build-backend-metadata-db
+build-discovery-service: build-metadata-db
 	mvn -f ./fda-discovery-service/pom.xml clean package -DskipTests
 
-build-backend-gateway: build-backend-metadata-db
+build-gateway-service: build-metadata-db
 	mvn -f ./fda-gateway-service/pom.xml clean package -DskipTests
 
-build-backend-query: build-backend-metadata-db
+build-query-service: build-metadata-db
 	mvn -f ./fda-query-service/pom.xml clean package -DskipTests
 
-build-backend-metadata: build-backend-metadata-db
+build-metadata-service: build-metadata-db
 	mvn -f ./fda-metadata-service/pom.xml clean package -DskipTests
 
 build-semantics-service:
@@ -150,93 +147,35 @@ release-search:
 release-metadata:
 	docker push "dbrepo/metadata-service:${TAG}"
 
-pull: pull-identifier pull-container pull-search pull-database pull-discovery pull-gateway pull-query pull-table pull-analyse pull-authentication pull-metadata-db pull-ui pull-units pull-broker pull-metadata
-
-pull-analyse:
-	docker pull "dbrepo/analyse-service:${TAG}"
-
-pull-authentication:
-	docker pull "dbrepo/authentication-service:${TAG}"
-
-pull-metadata-db:
-	docker pull "dbrepo/metadata-db:${TAG}"
-
-pull-ui:
-	docker pull "dbrepo/ui:${TAG}"
-
-pull-identifier:
-	docker pull "dbrepo/identifier-service:${TAG}"
-
-pull-container:
-	docker pull "dbrepo/container-service:${TAG}"
-
-pull-database:
-	docker pull "dbrepo/database-service:${TAG}"
-
-pull-discovery:
-	docker pull "dbrepo/discovery-service:${TAG}"
-
-pull-gateway:
-	docker pull "dbrepo/gateway-service:${TAG}"
-
-pull-query:
-	docker pull "dbrepo/query-service:${TAG}"
-
-pull-table:
-	docker pull "dbrepo/table-service:${TAG}"
-
-pull-units:
-	docker pull "dbrepo/semantics-service:${TAG}"
-
-pull-broker:
-	docker pull "dbrepo/broker-service:${TAG}"
-
-pull-metadata:
-	docker pull "dbrepo/metadata-service:${TAG}"
-
-pull-search:
-	docker pull "dbrepo/search-service:${TAG}"
-
 test-backend: test-authentication-service test-container-service test-database-service test-discovery-service test-gateway-service test-query-service test-table-service test-identifier-service test-metadata-service test-semantics-service test-analyse-service
 
-test-authentication-service: build-backend-metadata-db build-backend-authentication
-	docker system prune -f --volumes
+test-authentication-service: clean build-metadata-db build-authentication-service
 	docker pull rabbitmq:3-management-alpine
 	mvn -f ./fda-authentication-service/pom.xml clean test verify
 
-test-identifier-service: build-backend-metadata-db build-backend-identifier
-	docker system prune -f --volumes
+test-identifier-service: clean build-metadata-db build-identifier-service
 	mvn -f ./fda-identifier-service/pom.xml clean test verify
 
-test-container-service: build-backend-metadata-db build-backend-container
-	docker system prune -f --volumes
-	docker pull mysql:8.0
+test-container-service: clean build-metadata-db build-container-service
 	mvn -f ./fda-container-service/pom.xml clean test verify
 
-test-database-service: build-backend-metadata-db build-backend-database
-	docker system prune -f --volumes
+test-database-service: clean build-metadata-db build-database-service
 	docker pull rabbitmq:3-management-alpine
-	docker pull nginx:alpine
 	mvn -f ./fda-database-service/pom.xml clean test verify
 
-test-discovery-service: build-backend-metadata-db build-backend-discovery
-	docker system prune -f --volumes
+test-discovery-service: clean build-metadata-db build-discovery-service
 	mvn -f ./fda-discovery-service/pom.xml clean test verify
 
-test-gateway-service: build-backend-metadata-db build-backend-gateway
-	docker system prune -f --volumes
+test-gateway-service: clean build-metadata-db build-gateway-service
 	mvn -f ./fda-gateway-service/pom.xml clean test verify
 
-test-query-service: build-backend-metadata-db build-backend-query
-	docker system prune -f --volumes
+test-query-service: clean build-metadata-db build-query-service
 	mvn -f ./fda-query-service/pom.xml clean test verify
 
-test-table-service: build-backend-metadata-db build-backend-table
-	docker system prune -f --volumes
+test-table-service: clean build-metadata-db build-table-service
 	mvn -f ./fda-table-service/pom.xml clean test verify
 
-test-metadata-service: build-backend-metadata-db build-backend-metadata
-	docker system prune -f --volumes
+test-metadata-service: clean build-metadata-db build-metadata-service
 	mvn -f ./fda-metadata-service/pom.xml clean test verify
 
 test-semantics-service: build-semantics-service
@@ -245,13 +184,16 @@ test-semantics-service: build-semantics-service
 test-analyse-service: build-analyse-service
 	bash ./fda-analyse-service/test.sh
 
-coverage-frontend: clean build-frontend
+coverage-frontend: build-frontend
 	yarn --cwd ./fda-ui run coverage || true
 
 test-frontend: clean build-frontend
 	yarn --cwd ./fda-ui install
-	docker compose up -d
-	yarn --cwd ./fda-ui run test
+	yarn --cwd ./fda-ui run test:unit || true
+	yarn --cwd ./fda-ui run coverage || true
+
+clean:
+	docker system prune -f --volumes
 
 test-clients:
 	bash ./.gitlab/test.sh
@@ -259,4 +201,4 @@ test-clients:
 test: test-backend test-frontend
 
 teardown:
-	./.dbrepo2/teardown
+	./.junit/teardown
diff --git a/docker-compose.dbrepo1.yml b/docker-compose.dbrepo1.yml
index dfd09f5097236500634958c7072211892968336c..01db36561d40b6d328fade93b271caa6666d750d 100644
--- a/docker-compose.dbrepo1.yml
+++ b/docker-compose.dbrepo1.yml
@@ -31,7 +31,7 @@ networks:
 
 services:
 
-  metadata-db:
+  dbrepo-metadata-db:
     restart: on-failure
     container_name: dbrepo-metadata-db
     hostname: metadata-db
@@ -60,7 +60,7 @@ services:
     logging:
       driver: json-file
 
-  gateway-service:
+  dbrepo-gateway-service:
     restart: on-failure
     container_name: dbrepo-gateway-service
     hostname: gateway-service
@@ -72,12 +72,12 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  database-service:
+  dbrepo-database-service:
     restart: on-failure
     container_name: dbrepo-database-service
     hostname: database-service
@@ -90,16 +90,16 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      container-service:
+      dbrepo-container-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  container-service:
+  dbrepo-container-service:
     restart: on-failure
     container_name: dbrepo-container-service
     hostname: container-service
@@ -111,12 +111,12 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  authentication-service:
+  dbrepo-authentication-service:
     restart: on-failure
     container_name: dbrepo-authentication-service
     hostname: authentication-service
@@ -126,16 +126,16 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  query-service:
+  dbrepo-query-service:
     restart: on-failure
     container_name: dbrepo-query-service
     hostname: query-service
@@ -148,14 +148,14 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      table-service:
+      dbrepo-table-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  table-service:
+  dbrepo-table-service:
     restart: on-failure
     container_name: dbrepo-table-service
     hostname: table-service
@@ -169,16 +169,16 @@ services:
       - /var/run/docker.sock:/var/run/docker.sock
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
-      search-service:
+      dbrepo-search-service:
         condition: service_started
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
     logging:
       driver: json-file
 
-  identifier-service:
+  dbrepo-identifier-service:
     restart: on-failure
     container_name: dbrepo-identifier-service
     hostname: identifier-service
@@ -188,16 +188,16 @@ services:
     env_file:
       - .env
     depends_on:
-      query-service:
+      dbrepo-query-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     logging:
       driver: json-file
 
-  fda-metadata-service:
+  dbrepo-metadata-service:
     restart: on-failure
     container_name: dbrepo-metadata-service
     hostname: metadata-service
@@ -207,12 +207,12 @@ services:
     env_file:
       - .env
     depends_on:
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_started
     logging:
       driver: json-file
 
-  analyse-service:
+  dbrepo-analyse-service:
     restart: on-failure
     container_name: dbrepo-analyse-service
     hostname: analyse-service
@@ -226,12 +226,12 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  semantics-service:
+  dbrepo-semantics-service:
     restart: on-failure
     container_name: dbrepo-semantics-service
     hostname: semantics-service
@@ -244,14 +244,14 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  broker-service:
+  dbrepo-broker-service:
     restart: on-failure
     container_name: dbrepo-broker-service
     hostname: broker-service
@@ -264,14 +264,14 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     volumes:
       - broker-service-data:/var/lib/rabbitmq/
     logging:
       driver: json-file
 
-  search-service:
+  dbrepo-search-service:
     restart: always
     container_name: dbrepo-search-service
     hostname: search-service
@@ -279,7 +279,7 @@ services:
     networks:
       core:
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     ports:
       - 9200:9200
@@ -290,7 +290,7 @@ services:
     logging:
       driver: json-file
 
-  ui:
+  dbrepo-ui:
     restart: on-failure
     container_name: dbrepo-ui
     hostname: ui
@@ -303,9 +303,9 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      identifier-service:
+      dbrepo-identifier-service:
         condition: service_healthy
-      database-service:
+      dbrepo-database-service:
         condition: service_healthy
     logging:
       driver: json-file
diff --git a/docker-compose.dbrepo2.yml b/docker-compose.dbrepo2.yml
index dbd34f265e1c072684a60209978b9304a1b04fd4..7c169dd1cecfd8f1c9674ea6fb5c1be5a738c07c 100644
--- a/docker-compose.dbrepo2.yml
+++ b/docker-compose.dbrepo2.yml
@@ -31,7 +31,7 @@ networks:
 
 services:
 
-  metadata-db:
+  dbrepo-metadata-db:
     restart: on-failure
     container_name: dbrepo-metadata-db
     hostname: metadata-db
@@ -48,7 +48,7 @@ services:
     logging:
       driver: json-file
 
-  discovery-service:
+  dbrepo-discovery-service:
     restart: on-failure
     container_name: dbrepo-discovery-service
     hostname: discovery-service
@@ -60,7 +60,7 @@ services:
     logging:
       driver: json-file
 
-  gateway-service:
+  dbrepo-gateway-service:
     restart: on-failure
     container_name: dbrepo-gateway-service
     hostname: gateway-service
@@ -72,12 +72,12 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  database-service:
+  dbrepo-database-service:
     restart: on-failure
     container_name: dbrepo-database-service
     hostname: database-service
@@ -90,16 +90,16 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      container-service:
+      dbrepo-container-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  container-service:
+  dbrepo-container-service:
     restart: on-failure
     container_name: dbrepo-container-service
     hostname: container-service
@@ -111,12 +111,12 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  authentication-service:
+  dbrepo-authentication-service:
     restart: on-failure
     container_name: dbrepo-authentication-service
     hostname: authentication-service
@@ -126,16 +126,16 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  query-service:
+  dbrepo-query-service:
     restart: on-failure
     container_name: dbrepo-query-service
     hostname: query-service
@@ -148,14 +148,14 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      table-service:
+      dbrepo-table-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  table-service:
+  dbrepo-table-service:
     restart: on-failure
     container_name: dbrepo-table-service
     hostname: table-service
@@ -169,16 +169,16 @@ services:
       - /var/run/docker.sock:/var/run/docker.sock
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
-      search-service:
+      dbrepo-search-service:
         condition: service_started
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
     logging:
       driver: json-file
 
-  identifier-service:
+  dbrepo-identifier-service:
     restart: on-failure
     container_name: dbrepo-identifier-service
     hostname: identifier-service
@@ -188,16 +188,16 @@ services:
     env_file:
       - .env
     depends_on:
-      query-service:
+      dbrepo-query-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     logging:
       driver: json-file
 
-  metadata-service:
+  dbrepo-metadata-service:
     restart: on-failure
     container_name: dbrepo-metadata-service
     hostname: metadata-service
@@ -207,12 +207,12 @@ services:
     env_file:
       - .env
     depends_on:
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_started
     logging:
       driver: json-file
 
-  analyse-service:
+  dbrepo-analyse-service:
     restart: on-failure
     container_name: dbrepo-analyse-service
     hostname: analyse-service
@@ -226,12 +226,12 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  semantics-service:
+  dbrepo-semantics-service:
     restart: on-failure
     container_name: dbrepo-semantics-service
     hostname: semantics-service
@@ -244,14 +244,14 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  broker-service:
+  dbrepo-broker-service:
     restart: on-failure
     container_name: dbrepo-broker-service
     hostname: broker-service
@@ -264,14 +264,14 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     volumes:
       - broker-service-data:/var/lib/rabbitmq/
     logging:
       driver: json-file
 
-  search-service:
+  dbrepo-search-service:
     restart: always
     container_name: dbrepo-search-service
     hostname: search-service
@@ -279,7 +279,7 @@ services:
     networks:
       core:
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     env_file:
       - .env
@@ -288,7 +288,7 @@ services:
     logging:
       driver: json-file
 
-  ui:
+  dbrepo-ui:
     restart: on-failure
     container_name: dbrepo-ui
     hostname: ui
@@ -301,9 +301,9 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      identifier-service:
+      dbrepo-identifier-service:
         condition: service_healthy
-      database-service:
+      dbrepo-database-service:
         condition: service_healthy
     logging:
       driver: json-file
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 78fc30f91141e52b6d647c1e901aba2e987e7ca6..8984baecab55922994fb89672234edc276ec221e 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -31,7 +31,7 @@ networks:
 
 services:
 
-  metadata-db:
+  dbrepo-metadata-db:
     restart: on-failure
     container_name: dbrepo-metadata-db
     hostname: metadata-db
@@ -48,7 +48,7 @@ services:
     logging:
       driver: json-file
 
-  discovery-service:
+  dbrepo-discovery-service:
     restart: on-failure
     container_name: dbrepo-discovery-service
     hostname: discovery-service
@@ -60,7 +60,7 @@ services:
     logging:
       driver: json-file
 
-  gateway-service:
+  dbrepo-gateway-service:
     restart: on-failure
     container_name: dbrepo-gateway-service
     hostname: gateway-service
@@ -72,12 +72,12 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  database-service:
+  dbrepo-database-service:
     restart: on-failure
     container_name: dbrepo-database-service
     hostname: database-service
@@ -90,16 +90,16 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      container-service:
+      dbrepo-container-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  container-service:
+  dbrepo-container-service:
     restart: on-failure
     container_name: dbrepo-container-service
     hostname: container-service
@@ -111,12 +111,12 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  authentication-service:
+  dbrepo-authentication-service:
     restart: on-failure
     container_name: dbrepo-authentication-service
     hostname: authentication-service
@@ -126,16 +126,16 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  query-service:
+  dbrepo-query-service:
     restart: on-failure
     container_name: dbrepo-query-service
     hostname: query-service
@@ -148,14 +148,14 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      table-service:
+      dbrepo-table-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  table-service:
+  dbrepo-table-service:
     restart: on-failure
     container_name: dbrepo-table-service
     hostname: table-service
@@ -169,16 +169,16 @@ services:
       - /var/run/docker.sock:/var/run/docker.sock
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
-      search-service:
+      dbrepo-search-service:
         condition: service_started
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
     logging:
       driver: json-file
 
-  identifier-service:
+  dbrepo-identifier-service:
     restart: on-failure
     container_name: dbrepo-identifier-service
     hostname: identifier-service
@@ -188,16 +188,16 @@ services:
     env_file:
       - .env
     depends_on:
-      query-service:
+      dbrepo-query-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     logging:
       driver: json-file
 
-  metadata-service:
+  dbrepo-metadata-service:
     restart: on-failure
     container_name: dbrepo-metadata-service
     hostname: metadata-service
@@ -207,12 +207,12 @@ services:
     env_file:
       - .env
     depends_on:
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_started
     logging:
       driver: json-file
 
-  analyse-service:
+  dbrepo-analyse-service:
     restart: on-failure
     container_name: dbrepo-analyse-service
     hostname: analyse-service
@@ -226,12 +226,12 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  semantics-service:
+  dbrepo-semantics-service:
     restart: on-failure
     container_name: dbrepo-semantics-service
     hostname: semantics-service
@@ -244,14 +244,14 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  broker-service:
+  dbrepo-broker-service:
     restart: on-failure
     container_name: dbrepo-broker-service
     hostname: broker-service
@@ -263,14 +263,14 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     volumes:
       - broker-service-data:/var/lib/rabbitmq/
     logging:
       driver: json-file
 
-  search-service:
+  dbrepo-search-service:
     restart: always
     container_name: dbrepo-search-service
     hostname: search-service
@@ -278,7 +278,7 @@ services:
     networks:
       core:
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     env_file:
       - .env
@@ -287,7 +287,7 @@ services:
     logging:
       driver: json-file
 
-  ui:
+  dbrepo-ui:
     restart: on-failure
     container_name: dbrepo-ui
     hostname: ui
@@ -302,9 +302,9 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      identifier-service:
+      dbrepo-identifier-service:
         condition: service_healthy
-      database-service:
+      dbrepo-database-service:
         condition: service_healthy
     logging:
       driver: json-file
diff --git a/docker-compose.yml b/docker-compose.yml
index fd864bd166bfed2443e866de714ba9c4ce269c49..955a59d41ca1896c6915aaf8aa4cf3916567f141 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -10,27 +10,26 @@ volumes:
   broker-service-data:
 
 networks:
-  public:
-    name: public
+  userdb:
+    name: userdb
     driver: bridge
     ipam:
       config:
-        - subnet: 172.29.0.0/16
-  userdb:
-    name: userdb
+        - subnet: 172.30.0.0/16
+  public:
+    name: public
     driver: bridge
     ipam:
       config:
-        - subnet: 172.28.0.0/16
+        - subnet: 172.31.0.0/16
   core:
     name: core
     driver: bridge
     ipam:
       config:
-        - subnet: 172.27.0.0/16
+        - subnet: 172.32.0.0/16
 
 services:
-
   fda-metadata-db:
     restart: on-failure
     container_name: dbrepo-metadata-db
diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index be355787b98d46890355f5ddabf7fe1e5c38a86e..c6c927f9b93472b3f544dfae2544ce024375bfb7 100644
--- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -294,7 +294,7 @@ public abstract class BaseUnitTest {
     public final static Long CONTAINER_BROKER_ID = 1L;
     public final static String CONTAINER_BROKER_NAME = "broker-service";
     public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_IP = "172.29.0.2";
+    public final static String CONTAINER_BROKER_IP = "172.31.0.2";
 
     public final static Container CONTAINER_BROKER = Container.builder()
             .id(CONTAINER_BROKER_ID)
diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
index fc15443f9e2a8843a187ccebba2e57a75be38546..37b2ca7d1b18fb9dacc025176e9967fc3c990021 100644
--- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
+++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
@@ -4,7 +4,9 @@ import at.tuwien.entities.container.Container;
 import com.github.dockerjava.api.DockerClient;
 import com.github.dockerjava.api.command.CreateContainerResponse;
 import com.github.dockerjava.api.command.InspectContainerResponse;
+import com.github.dockerjava.api.exception.NotModifiedException;
 import com.github.dockerjava.api.model.HostConfig;
+import com.github.dockerjava.api.model.Network;
 import com.github.dockerjava.api.model.RestartPolicy;
 import com.github.dockerjava.core.DefaultDockerClientConfig;
 import com.github.dockerjava.core.DockerClientBuilder;
@@ -13,6 +15,7 @@ import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
 import com.github.dockerjava.transport.DockerHttpClient;
 import lombok.extern.log4j.Log4j2;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 @Log4j2
@@ -56,7 +59,7 @@ public class DockerConfig {
         final CreateContainerResponse response = dockerClient.createContainerCmd(container.getImage().getRepository() + ":" + container.getImage().getTag())
                 .withHostConfig(hostConfig.withNetworkMode("fda-userdb"))
                 .withName(container.getInternalName())
-                .withIpv4Address("172.28.0.5")
+                .withIpv4Address("172.30.0.5")
                 .withHostName(container.getInternalName())
                 .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather")
                 .exec();
@@ -86,4 +89,59 @@ public class DockerConfig {
         log.debug("container {} was removed", container.getHash());
     }
 
+    public static void removeAllContainers() {
+        dockerClient.listContainersCmd()
+                .withShowAll(true)
+                .exec()
+                .forEach(container -> {
+                    log.info("Delete container {}", Arrays.asList(container.getNames()));
+                    try {
+                        dockerClient.stopContainerCmd(container.getId()).exec();
+                    } catch (NotModifiedException e) {
+                        // ignore
+                    }
+                    dockerClient.removeContainerCmd(container.getId()).exec();
+                });
+        dockerClient.listVolumesCmd()
+                .withDanglingFilter(true)
+                .exec()
+                .getVolumes()
+                .forEach(volume -> {
+                    log.info("Delete volume {}", volume.getName());
+                    try {
+                        dockerClient.removeVolumeCmd(volume.getName()).exec();
+                    } catch (NotModifiedException e) {
+                        // ignore
+                    }
+                });
+    }
+
+    public static void removeAllNetworks() {
+        dockerClient.listNetworksCmd()
+                .exec()
+                .stream()
+                .filter(n -> n.getName().startsWith("fda"))
+                .forEach(network -> {
+                    log.info("Delete network {}", network.getName());
+                    dockerClient.removeNetworkCmd(network.getId()).exec();
+                });
+    }
+
+    public static void createAllNetworks() {
+        dockerClient.createNetworkCmd()
+                .withName("fda-userdb")
+                .withIpam(new Network.Ipam()
+                        .withConfig(new Network.Ipam.Config()
+                                .withSubnet("172.30.0.0/16")))
+                .withEnableIpv6(false)
+                .exec();
+        dockerClient.createNetworkCmd()
+                .withName("fda-public")
+                .withIpam(new Network.Ipam()
+                        .withConfig(new Network.Ipam.Config()
+                                .withSubnet("172.31.0.0/16")))
+                .withEnableIpv6(false)
+                .exec();
+    }
+
 }
diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
index f887b5a86cc45732941fdfa2491c734eb6d8e55c..ba84081446b1d902dad583a0b2c0602a55684ceb 100644
--- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
+++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
@@ -2,6 +2,7 @@ package at.tuwien.service;
 
 import at.tuwien.BaseUnitTest;
 import at.tuwien.api.amqp.CreateUserDto;
+import at.tuwien.config.DockerConfig;
 import at.tuwien.config.RabbitMqConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.dto.AmqpUserBriefDto;
@@ -13,9 +14,7 @@ import com.github.dockerjava.api.exception.NotModifiedException;
 import com.github.dockerjava.api.model.Network;
 import com.github.dockerjava.api.model.PortBinding;
 import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.*;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -56,24 +55,16 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
     @Autowired
     private RabbitMqConfig amqpConfig;
 
+    @BeforeAll
+    public static void beforeAll() {
+        afterAll();
+        DockerConfig.createAllNetworks();
+    }
+
     @BeforeEach
     public void beforeEach() throws InterruptedException {
         afterEach();
-        /* create networks */
-        dockerClient.createNetworkCmd()
-                .withName("fda-userdb")
-                .withIpam(new Network.Ipam()
-                        .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
-                .withEnableIpv6(false)
-                .exec();
-        dockerClient.createNetworkCmd()
-                .withName("fda-public")
-                .withIpam(new Network.Ipam()
-                        .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
-                .withEnableIpv6(false)
-                .exec();
+        DockerConfig.createAllNetworks();
         /* create container */
         final PortBinding binding = PortBinding.parse("15672:15672");
         final CreateContainerResponse response1 = dockerClient.createContainerCmd(IMAGE_BROKER_IMAGE + ":" + IMAGE_BROKER_TAG)
@@ -92,28 +83,14 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
 
     @AfterEach
     public void afterEach() {
-        /* stop containers and remove them */
-        dockerClient.listContainersCmd()
-                .withShowAll(true)
-                .exec()
-                .forEach(container -> {
-                    log.info("Delete container {}", Arrays.asList(container.getNames()));
-                    try {
-                        dockerClient.stopContainerCmd(container.getId()).exec();
-                    } catch (NotModifiedException e) {
-                        // ignore
-                    }
-                    dockerClient.removeContainerCmd(container.getId()).exec();
-                });
-        /* remove networks */
-        dockerClient.listNetworksCmd()
-                .exec()
-                .stream()
-                .filter(n -> n.getName().startsWith("fda"))
-                .forEach(network -> {
-                    log.info("Delete network {}", network.getName());
-                    dockerClient.removeNetworkCmd(network.getId()).exec();
-                });
+        DockerConfig.removeAllContainers();
+        DockerConfig.removeAllNetworks();
+    }
+
+    @AfterAll
+    public static void afterAll() {
+        DockerConfig.removeAllContainers();
+        DockerConfig.removeAllNetworks();
     }
 
     @Test
diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java
index 371ed3450a01c2f2c1803e69797e88e56f87dbc1..c72d988189d61e44b59a33015effb1a69789c94a 100644
--- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java
+++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java
@@ -6,6 +6,7 @@ import at.tuwien.api.user.RoleTypeDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserRolesDto;
 import at.tuwien.config.AuthenticationConfig;
+import at.tuwien.config.DockerConfig;
 import at.tuwien.config.RabbitMqConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.user.RoleType;
@@ -14,8 +15,6 @@ import at.tuwien.exception.*;
 import at.tuwien.repositories.ImageRepository;
 import at.tuwien.repositories.UserRepository;
 import com.github.dockerjava.api.command.CreateContainerResponse;
-import com.github.dockerjava.api.exception.NotModifiedException;
-import com.github.dockerjava.api.model.Network;
 import com.github.dockerjava.api.model.PortBinding;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.*;
@@ -25,13 +24,10 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.dao.DataIntegrityViolationException;
-import org.springframework.dao.DuplicateKeyException;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.web.client.RestTemplate;
 
-import javax.validation.ConstraintViolationException;
-import java.util.Arrays;
 import java.util.List;
 
 import static at.tuwien.config.DockerConfig.*;
@@ -71,57 +67,28 @@ public class UserServiceIntegrationTest extends BaseUnitTest {
     @BeforeAll
     public static void beforeAll() {
         afterAll();
-        /* create networks */
-        dockerClient.createNetworkCmd()
-                .withName("fda-userdb")
-                .withIpam(new Network.Ipam()
-                        .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
-                .withEnableIpv6(false)
-                .exec();
-        dockerClient.createNetworkCmd()
-                .withName("fda-public")
-                .withIpam(new Network.Ipam()
-                        .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
-                .withEnableIpv6(false)
-                .exec();
-    }
-
-    @AfterAll
-    public static void afterAll() {
-        /* remove networks */
-        dockerClient.listNetworksCmd()
-                .exec()
-                .stream()
-                .filter(n -> n.getName().startsWith("fda"))
-                .forEach(network -> {
-                    log.info("Delete network {}", network.getName());
-                    dockerClient.removeNetworkCmd(network.getId()).exec();
-                });
+        DockerConfig.createAllNetworks();
     }
 
     @BeforeEach
     public void beforeEach() {
+        afterEach();
+        DockerConfig.createAllNetworks();
+        /* metadata database */
         imageRepository.save(IMAGE_1);
         userRepository.save(USER_1);
     }
 
     @AfterEach
     public void afterEach() {
-        /* stop containers and remove them */
-        dockerClient.listContainersCmd()
-                .withShowAll(true)
-                .exec()
-                .forEach(container -> {
-                    log.info("Delete container {}", Arrays.asList(container.getNames()));
-                    try {
-                        dockerClient.stopContainerCmd(container.getId()).exec();
-                    } catch (NotModifiedException e) {
-                        // ignore
-                    }
-                    dockerClient.removeContainerCmd(container.getId()).exec();
-                });
+        DockerConfig.removeAllContainers();
+        DockerConfig.removeAllNetworks();
+    }
+
+    @AfterAll
+    public static void afterAll() {
+        DockerConfig.removeAllContainers();
+        DockerConfig.removeAllNetworks();
     }
 
     @Test
diff --git a/fda-authentication-service/rest-service/src/test/resources/application.properties b/fda-authentication-service/rest-service/src/test/resources/application.properties
index b0ccd00eda3328d89ea1cea158719ad810e6712b..d57104b1eaa5bb5e645f82671879ae16d2e2b015 100644
--- a/fda-authentication-service/rest-service/src/test/resources/application.properties
+++ b/fda-authentication-service/rest-service/src/test/resources/application.properties
@@ -25,6 +25,6 @@ spring.rabbitmq.username=guest
 spring.rabbitmq.password=guest
 
 # user
-fda.gateway.endpoint=http://172.29.0.2:15672/api/
+fda.gateway.endpoint=http://172.31.0.2:15672/api/
 fda.mail.verify=true
 fda.token.max=1
\ No newline at end of file
diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index 9dfe9e4b53e3072a2aa40bb88b4820473fb649f4..5c3d11e564d31020f65612052bbe570c212f887d 100644
--- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -5,6 +5,7 @@ import at.tuwien.entities.container.Container;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.ContainerMapper;
+import at.tuwien.service.ContainerService;
 import at.tuwien.service.UserService;
 import at.tuwien.service.impl.ContainerServiceImpl;
 import io.micrometer.core.annotation.Timed;
@@ -34,7 +35,7 @@ public class ContainerEndpoint {
 
     private final UserService userService;
     private final ContainerMapper containerMapper;
-    private final ContainerServiceImpl containerService;
+    private final ContainerService containerService;
 
     @Autowired
     public ContainerEndpoint(UserService userService, ContainerServiceImpl containerService,
@@ -47,9 +48,10 @@ public class ContainerEndpoint {
     @GetMapping
     @Transactional(readOnly = true)
     @Operation(summary = "Find all containers")
-    public ResponseEntity<List<ContainerBriefDto>> findAll(Principal principal) {
-        log.debug("endpoint find all containers, principal={}", principal);
-        final List<Container> containers = containerService.getAll();
+    public ResponseEntity<List<ContainerBriefDto>> findAll(Principal principal,
+                                                           @RequestParam(required = false) Integer limit) {
+        log.debug("endpoint find all containers, principal={}, limit={}", principal, limit);
+        final List<Container> containers = containerService.getAll(limit);
         return ResponseEntity.ok()
                 .body(containers.stream()
                         .map(containerMapper::containerToDatabaseContainerBriefDto)
@@ -95,7 +97,7 @@ public class ContainerEndpoint {
                                                     @Valid @RequestBody ContainerChangeDto changeDto,
                                                     @NotNull Principal principal)
             throws ContainerNotFoundException, ContainerAlreadyRunningException, ContainerAlreadyStoppedException,
-            UserNotFoundException, NotAllowedException {
+            UserNotFoundException, NotAllowedException, DockerClientException {
         log.debug("endpoint modify container, containerId={}, changeDto={}, principal={}", containerId, changeDto, principal);
         final User user = userService.findByUsername(principal.getName());
         final Container container = containerService.find(containerId);
@@ -124,7 +126,7 @@ public class ContainerEndpoint {
     @Operation(summary = "Delete some container", security = @SecurityRequirement(name = "bearerAuth"))
     public ResponseEntity<?> delete(@NotNull @PathVariable("id") Long containerId,
                                     @NotNull Principal principal) throws ContainerNotFoundException,
-            ContainerStillRunningException, ContainerAlreadyRemovedException {
+            ContainerStillRunningException, ContainerAlreadyRemovedException, DockerClientException {
         log.debug("endpoint delete container, containerId={}, principal={}", containerId, principal);
         containerService.remove(containerId);
         return ResponseEntity.status(HttpStatus.ACCEPTED)
diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
index 7f02363385b4618a4d5430694de644ac54e54284..bbb5d2ecba97a1acd2314ce9a9cbb9b16de68e82 100644
--- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
+++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
@@ -10,10 +10,6 @@ import at.tuwien.mapper.ImageMapper;
 import at.tuwien.service.impl.ImageServiceImpl;
 import io.micrometer.core.annotation.Timed;
 import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -46,9 +42,6 @@ public class ImageEndpoint {
     }
 
     @GetMapping
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "200", description = "Found images")
-    })
     @Transactional(readOnly = true)
     @Timed(value = "image.list", description = "Time needed to list the container images")
     @Operation(summary = "Find all images")
@@ -62,10 +55,6 @@ public class ImageEndpoint {
     }
 
     @PostMapping
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "201", description = "Created image"),
-            @ApiResponse(responseCode = "404", description = "Image not found"),
-    })
     @Transactional
     @Timed(value = "image.create", description = "Time needed to create a container image")
     @PreAuthorize("hasRole('ROLE_DEVELOPER')")
@@ -86,10 +75,6 @@ public class ImageEndpoint {
     }
 
     @GetMapping("/{id}")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "200", description = "Found some image"),
-            @ApiResponse(responseCode = "404", description = "Image not found"),
-    })
     @Transactional(readOnly = true)
     @Timed(value = "image.find", description = "Time needed to find a container image")
     @Operation(summary = "Find some image")
@@ -104,10 +89,6 @@ public class ImageEndpoint {
     }
 
     @PutMapping("/{id}")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "202", description = "Updated image"),
-            @ApiResponse(responseCode = "404", description = "Image not found"),
-    })
     @Transactional
     @Timed(value = "image.update", description = "Time needed to update a container image")
     @PreAuthorize("hasRole('DEVELOPER')")
@@ -125,11 +106,6 @@ public class ImageEndpoint {
     }
 
     @DeleteMapping("/{id}")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "200", description = "Deleted image"),
-            @ApiResponse(responseCode = "403", description = "Unable to delete image"),
-            @ApiResponse(responseCode = "404", description = "Image not found"),
-    })
     @Transactional
     @Timed(value = "image.delete", description = "Time needed to delete a container image")
     @PreAuthorize("hasRole('DEVELOPER')")
diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index c22a810fea54b58c45b71cf70b23efcde52ae031..0a59ea1f4519a9212ddabb9f05ed96276fc07441 100644
--- a/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -12,6 +12,7 @@ import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType;
 import at.tuwien.entities.user.RoleType;
 import at.tuwien.entities.user.User;
 import com.github.dockerjava.api.command.InspectContainerResponse;
+import com.github.dockerjava.api.model.HealthCheck;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -284,30 +285,36 @@ public abstract class BaseUnitTest {
 
     public final static Long CONTAINER_1_ID = 1L;
     public final static String CONTAINER_1_HASH = "deadbeef";
-    public final static String CONTAINER_1_NAME = "fda-userdb-u01";
-    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-fda-userdb-u01";
-    public final static String CONTAINER_1_DATABASE = "univie";
-    public final static String CONTAINER_1_IP = "172.28.0.5";
-    public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS);
+    public final static String CONTAINER_1_IP = "172.30.0.5";
+    public final static String CONTAINER_1_NAME = "u01";
+    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
+    public final static Instant CONTAINER_1_CREATED = Instant.now().minus(2, HOURS);
+    public final static Instant CONTAINER_1_UPDATED = Instant.now();
+    public final static HealthCheck CONTAINER_1_HEALTHCHECK = new HealthCheck()
+            .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb"));
+
+    public final static String[] CONTAINER_1_ENV = new String[]{"MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_USER=mariadb",
+            "MARIADB_PASSWORD=mariadb", "MARIADB_DATABASE=weather"};
 
     public final static Container CONTAINER_1 = Container.builder()
             .id(CONTAINER_1_ID)
             .name(CONTAINER_1_NAME)
+            .hash(CONTAINER_1_HASH)
             .internalName(CONTAINER_1_INTERNALNAME)
+            .created(CONTAINER_1_CREATED)
+            .lastModified(CONTAINER_1_UPDATED)
+            .ipAddress(CONTAINER_1_IP)
             .imageId(IMAGE_1_ID)
             .image(IMAGE_1)
-            .hash(CONTAINER_1_HASH)
-            .ipAddress(CONTAINER_1_IP)
-            .created(CONTAINER_1_CREATED)
             .creator(USER_1)
+            .owner(USER_1)
             .build();
 
     public final static Long CONTAINER_2_ID = 2L;
     public final static String CONTAINER_2_HASH = "deadbeef";
-    public final static String CONTAINER_2_NAME = "fda-userdb-u02";
-    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-fda-userdb-u02";
-    public final static String CONTAINER_2_DATABASE = "univie";
-    public final static String CONTAINER_2_IP = "172.28.0.6";
+    public final static String CONTAINER_2_NAME = "u02";
+    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02";
+    public final static String CONTAINER_2_IP = "172.30.0.6";
     public final static Instant CONTAINER_2_CREATED = Instant.now().minus(2, HOURS);
 
     public final static Container CONTAINER_2 = Container.builder()
@@ -324,8 +331,8 @@ public abstract class BaseUnitTest {
 
     public final static Long CONTAINER_3_ID = 3L;
     public final static String CONTAINER_3_HASH = "deadbeef";
-    public final static String CONTAINER_3_NAME = "fda-userdb-u03";
-    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-fda-userdb-u03";
+    public final static String CONTAINER_3_NAME = "u03";
+    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03";
     public final static String CONTAINER_3_DATABASE = "u03";
     public final static String CONTAINER_3_IP = "173.38.0.7";
     public final static Instant CONTAINER_3_CREATED = Instant.now().minus(2, HOURS);
diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java
index 7407254558e316d28a8fbccc878d9b789712cd81..cd82d0b81d9e7befddfea0c1018863fcf7c8670d 100644
--- a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java
+++ b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java
@@ -2,7 +2,7 @@ package at.tuwien.endpoint;
 
 import at.tuwien.BaseUnitTest;
 import at.tuwien.api.container.*;
-import at.tuwien.config.DockerUtil;
+import at.tuwien.config.DockerConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.endpoints.ContainerEndpoint;
 import at.tuwien.entities.container.Container;
@@ -48,7 +48,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     private ContainerEndpoint containerEndpoint;
 
     @Autowired
-    private DockerUtil dockerUtil;
+    private DockerConfig dockerUtil;
 
     @Test
     public void findById_anonymous_succeeds() throws DockerClientException, ContainerNotFoundException,
@@ -142,7 +142,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     @Test
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void delete_developer_succeeds() throws ContainerStillRunningException, ContainerAlreadyRemovedException,
-            ContainerNotFoundException {
+            ContainerNotFoundException, DockerClientException {
 
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
@@ -170,7 +170,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     public void findAll_anonymous_succeeds() {
 
         /* test */
-        findAll_generic(null);
+        findAll_generic(null, null);
     }
 
     @Test
@@ -178,7 +178,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     public void findAll_anonymous2_succeeds() {
 
         /* test */
-        findAll_generic(null);
+        findAll_generic(null, null);
     }
 
     @Test
@@ -190,7 +190,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
                 .thenReturn(Optional.of(USER_1));
 
         /* test */
-        findAll_generic(USER_1_PRINCIPAL);
+        findAll_generic(USER_1_PRINCIPAL, null);
     }
 
     @Test
@@ -202,7 +202,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
                 .thenReturn(Optional.of(USER_2));
 
         /* test */
-        findAll_generic(USER_2_PRINCIPAL);
+        findAll_generic(USER_2_PRINCIPAL, null);
     }
 
     @Test
@@ -214,7 +214,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        findAll_generic(USER_3_PRINCIPAL);
+        findAll_generic(USER_3_PRINCIPAL, null);
     }
 
     @Test
@@ -337,7 +337,8 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void modify_researcherStart_succeeds() throws ContainerAlreadyRunningException,
-            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException {
+            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException,
+            DockerClientException {
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
@@ -367,7 +368,8 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void modify_researcherStop_succeeds() throws ContainerAlreadyRunningException,
-            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException {
+            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException,
+            DockerClientException {
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
@@ -398,7 +400,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     @Test
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void modify_developerForeignStart_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
-            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException {
+            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException {
 
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
@@ -411,7 +413,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     @Test
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void modify_developerForeignStop_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
-            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException {
+            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException {
 
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
@@ -471,7 +473,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     }
 
     public void delete_generic(Long containerId, Container container, Principal principal) throws ContainerNotFoundException,
-            ContainerStillRunningException, ContainerAlreadyRemovedException {
+            ContainerStillRunningException, ContainerAlreadyRemovedException, DockerClientException {
 
         /* mock */
         when(containerService.find(containerId))
@@ -486,14 +488,14 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
         assertNull(response.getBody());
     }
 
-    public void findAll_generic(Principal principal) {
+    public void findAll_generic(Principal principal, Integer limit) {
 
         /* mock */
-        when(containerService.getAll())
+        when(containerService.getAll(limit))
                 .thenReturn(List.of(CONTAINER_1, CONTAINER_2));
 
         /* test */
-        final ResponseEntity<List<ContainerBriefDto>> response = containerEndpoint.findAll(principal);
+        final ResponseEntity<List<ContainerBriefDto>> response = containerEndpoint.findAll(principal, limit);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<ContainerBriefDto> body = response.getBody();
@@ -522,7 +524,8 @@ public class ContainerEndpointUnitTest extends BaseUnitTest {
     }
 
     public void modify_generic(ContainerActionTypeDto data, Long containerId, Container container, Principal principal)
-            throws ContainerAlreadyRunningException, ContainerNotFoundException, ContainerAlreadyStoppedException, UserNotFoundException, NotAllowedException {
+            throws ContainerAlreadyRunningException, ContainerNotFoundException, ContainerAlreadyStoppedException,
+            UserNotFoundException, NotAllowedException, DockerClientException {
         final ContainerChangeDto request = ContainerChangeDto.builder()
                 .action(data)
                 .build();
diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java
index f84ae04db59091c81e86ff91854ff0106cb6bd5e..9ef775d53dde5ee5f99ede094d4a1944dbd7a879 100644
--- a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java
+++ b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java
@@ -1,21 +1,17 @@
 package at.tuwien.endpoint;
 
 import at.tuwien.BaseUnitTest;
-import at.tuwien.api.container.*;
 import at.tuwien.api.container.image.ImageBriefDto;
 import at.tuwien.api.container.image.ImageChangeDto;
 import at.tuwien.api.container.image.ImageCreateDto;
 import at.tuwien.api.container.image.ImageDto;
-import at.tuwien.config.DockerUtil;
+import at.tuwien.config.DockerConfig;
 import at.tuwien.config.ReadyConfig;
-import at.tuwien.endpoints.ContainerEndpoint;
 import at.tuwien.endpoints.ImageEndpoint;
-import at.tuwien.entities.container.Container;
 import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.exception.*;
 import at.tuwien.repository.jpa.ImageRepository;
 import at.tuwien.repository.jpa.UserRepository;
-import at.tuwien.service.impl.ContainerServiceImpl;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -31,7 +27,6 @@ import org.springframework.security.test.context.support.WithAnonymousUser;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
-import javax.ws.rs.NotAllowedException;
 import java.security.Principal;
 import java.util.List;
 import java.util.Optional;
@@ -57,7 +52,7 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     private ImageEndpoint imageEndpoint;
 
     @Autowired
-    private DockerUtil dockerUtil;
+    private DockerConfig dockerUtil;
 
     @Test
     public void findAll_anonymous_succeeds() {
diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
index 8aef59c9fcc56627c6a651a6fe457875abc91932..fd1c316006658919c030f290a359b3a3bdb115fe 100644
--- a/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
+++ b/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
@@ -5,7 +5,6 @@ import at.tuwien.api.container.ContainerCreateRequestDto;
 import at.tuwien.config.DockerUtil;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.container.Container;
-import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.exception.*;
 import at.tuwien.repository.jpa.ContainerRepository;
 import at.tuwien.repository.jpa.ImageRepository;
@@ -66,32 +65,19 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
                 .withName("fda-userdb")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
+                                .withSubnet("172.30.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         dockerClient.createNetworkCmd()
                 .withName("fda-public")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
+                                .withSubnet("172.31.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
 
         /* mock data */
         userRepository.save(USER_1);
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
         imageRepository.save(IMAGE_1);
     }
 
@@ -151,30 +137,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
         final Principal principal = new BasicUserPrincipal(USER_1_USERNAME);
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         containerRepository.save(CONTAINER_1);
 
         /* test */
@@ -221,30 +183,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
             ContainerAlreadyRunningException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
 
@@ -257,30 +195,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
             ContainerAlreadyStoppedException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         dockerUtil.startContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
@@ -293,30 +207,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_startSavedButNotFound_fails() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         containerRepository.save(CONTAINER_1);
 
         /* test */
@@ -329,30 +219,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_removeSavedButNotFound_fails() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         containerRepository.save(CONTAINER_1);
 
         /* test */
@@ -365,77 +231,31 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void getAll_succeeds() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        final Container CONTAINER_2 = Container.builder()
-                .id(CONTAINER_2_ID)
-                .name(CONTAINER_2_NAME)
-                .internalName(CONTAINER_2_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_2_HASH)
-                .ipAddress(CONTAINER_2_IP)
-                .created(CONTAINER_2_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         containerRepository.save(CONTAINER_1);
         containerRepository.save(CONTAINER_2);
 
         /* test */
-        final List<Container> response = containerService.getAll();
+        final List<Container> response = containerService.getAll(null);
         assertEquals(2, response.size());
     }
 
+    @Test
+    public void getAll_limit_succeeds() {
+
+        /* mock */
+        containerRepository.save(CONTAINER_1);
+        containerRepository.save(CONTAINER_2);
+
+        /* test */
+        final List<Container> response = containerService.getAll(1);
+        assertEquals(1, response.size());
+    }
+
     @Test
     public void remove_succeeds() throws DockerClientException, ContainerStillRunningException,
             ContainerNotFoundException, ContainerAlreadyRemovedException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         dockerUtil.stopContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
@@ -457,30 +277,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void remove_stillRunning_fails() throws InterruptedException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         dockerUtil.startContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
@@ -495,30 +291,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_alreadyRunning_fails() throws InterruptedException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         dockerUtil.startContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
@@ -533,30 +305,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_startNotFound_fails() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
 
         /* test */
@@ -569,30 +317,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_alreadyStopped_fails() throws InterruptedException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         dockerUtil.startContainer(CONTAINER_1);
         dockerUtil.stopContainer(CONTAINER_1);
@@ -608,30 +332,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_stopNeverStarted_fails() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
 
@@ -645,30 +345,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void change_stopSavedButNotFound_fails() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         containerRepository.save(CONTAINER_1);
 
         /* test */
@@ -682,30 +358,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
             ContainerNotRunningException {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         dockerUtil.startContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
@@ -731,30 +383,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void inspect_notRunning_fails() {
 
         /* mock */
-        final ContainerImage IMAGE_1 = ContainerImage.builder()
-                .id(IMAGE_1_ID)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .hash(IMAGE_1_HASH)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .dialect(IMAGE_1_DIALECT)
-                .driverClass(IMAGE_1_DRIVER)
-                .compiled(IMAGE_1_BUILT)
-                .size(IMAGE_1_SIZE)
-                .environment(IMAGE_1_ENV)
-                .defaultPort(IMAGE_1_PORT)
-                .build();
-        final Container CONTAINER_1 = Container.builder()
-                .id(CONTAINER_1_ID)
-                .name(CONTAINER_1_NAME)
-                .internalName(CONTAINER_1_INTERNALNAME)
-                .imageId(IMAGE_1_ID)
-                .image(IMAGE_1)
-                .hash(CONTAINER_1_HASH)
-                .ipAddress(CONTAINER_1_IP)
-                .created(CONTAINER_1_CREATED)
-                .build();
-        log.info("Container id {}", CONTAINER_1.getId());
         dockerUtil.createContainer(CONTAINER_1);
         containerRepository.save(CONTAINER_1);
 
diff --git a/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
index 6a7b557780c2eae87d2f4e741358c9cd11272973..1879065a2df2056603679e9d8a505633a702178a 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
@@ -1,5 +1,6 @@
 package at.tuwien.mapper;
 
+import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.entities.database.Database;
 import org.mapstruct.Mapper;
@@ -14,4 +15,10 @@ public interface DatabaseMapper {
     })
     DatabaseDto databaseToDatabaseDto(Database data);
 
+    /* keep */
+    @Mappings({
+            @Mapping(target = "container", ignore = true)
+    })
+    DatabaseBriefDto databaseToDatabaseBriefDto(Database data);
+
 }
diff --git a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java
index 37b8abb7735952160ae69ddb85c748441050a575..df2a6eba16e4bdbefa3a5de7eaff1dea507ed8ad 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java
@@ -9,8 +9,6 @@ import java.util.Optional;
 @Repository
 public interface ContainerRepository extends JpaRepository<Container, Long> {
 
-    Optional<Container> findByHash(String hash);
-
     Optional<Container> findByInternalName(String internalName);
 
 }
diff --git a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..688993ab3ca2e32edeb59b6c66dc838f58333b02
--- /dev/null
+++ b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java
@@ -0,0 +1,10 @@
+package at.tuwien.repository.jpa;
+
+import at.tuwien.entities.database.Database;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface DatabaseRepository extends JpaRepository<Database, Long> {
+
+}
diff --git a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..f76f9976d6de9884579ac242ce616d6c0caf099e
--- /dev/null
+++ b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java
@@ -0,0 +1,10 @@
+package at.tuwien.repository.jpa;
+
+import at.tuwien.entities.identifier.Identifier;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface IdentifierRepository extends JpaRepository<Identifier, Long> {
+
+}
diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java b/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java
index 2528621ed475406bb055f32457420bc116d158e2..26654fc34f51bb974b91036fadeb26eca12a1f55 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java
@@ -56,9 +56,12 @@ public interface ContainerService {
     Container inspect(Long id) throws ContainerNotFoundException, DockerClientException, ContainerNotRunningException;
 
     /**
-     * @return
+     * Retrieve a list of all containers from the metadata database
+     *
+     * @param limit Return at most this amount of results, optional.
+     * @return The list of containers.
      */
-    List<Container> getAll();
+    List<Container> getAll(Integer limit);
 
     /**
      * @param containerId
diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
index 4dc699622912b6ac69c2ab2d2a71246be2ee4c62..9753d9687e7ec0113b00bde7cede4a4d3e41b1e6 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
@@ -22,6 +22,7 @@ import com.github.dockerjava.api.exception.NotModifiedException;
 import com.github.dockerjava.api.model.*;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 import org.springframework.util.SocketUtils;
@@ -31,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.security.Principal;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 @Log4j2
 @Service
@@ -79,7 +81,7 @@ public class ContainerServiceImpl implements ContainerService {
         /* check duplicate */
         final Optional<Container> optional = containerRepository.findByInternalName(container.getInternalName());
         if (optional.isPresent()) {
-            log.error("Failed to create container with internal name {}", container.getInternalName());
+            log.error("Failed to create container with internal name {}, it already exists", container.getInternalName());
             throw new ContainerAlreadyExistsException("Container name already exists");
         }
         /* create the volume */
@@ -212,9 +214,15 @@ public class ContainerServiceImpl implements ContainerService {
     }
 
     @Override
-    @Transactional
-    public List<Container> getAll() {
-        final List<Container> containers = containerRepository.findAll(Sort.by(Sort.Direction.DESC, "created"));
+    @Transactional(readOnly = true)
+    public List<Container> getAll(Integer limit) {
+        final List<Container> containers;
+        if (limit == null) {
+            containers = containerRepository.findAll(Sort.by(Sort.Direction.DESC, "created"));
+        } else {
+            containers = containerRepository.findAll(PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "created")))
+                    .toList();
+        }
         log.info("Found {} containers", containers.size());
         return containers;
     }
diff --git a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index 57820c3a21bde65e110d829e6b7413ba4678768d..bfeb98549b44ad1c38c2dbc84c399aa99f475cf6 100644
--- a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -3,12 +3,9 @@ package at.tuwien.endpoints;
 import at.tuwien.api.database.*;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
-import at.tuwien.entities.identifier.Identifier;
-import at.tuwien.entities.identifier.IdentifierType;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.DatabaseMapper;
-import at.tuwien.mapper.IdentifierMapper;
 import at.tuwien.repository.jpa.DatabaseAccessRepository;
 import at.tuwien.service.*;
 import at.tuwien.service.impl.MariaDbServiceImpl;
@@ -27,7 +24,6 @@ import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import java.security.Principal;
 import java.util.List;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 @Log4j2
@@ -39,27 +35,22 @@ public class DatabaseEndpoint extends AbstractEndpoint {
     private final UserService userService;
     private final AccessService accessService;
     private final DatabaseMapper databaseMapper;
-    private final IdentifierMapper identifierMapper;
     private final MariaDbServiceImpl databaseService;
     private final QueryStoreService queryStoreService;
-    private final IdentifierService identifierService;
     private final MessageQueueService messageQueueService;
     private final DatabaseAccessRepository databaseAccessRepository;
 
     @Autowired
     public DatabaseEndpoint(DatabaseMapper databaseMapper, ContainerService containerService,
                             UserService userService, MariaDbServiceImpl databaseService, QueryStoreService queryStoreService,
-                            IdentifierService identifierService, IdentifierMapper identifierMapper,
                             MessageQueueService messageQueueService, AccessService accessService,
                             DatabaseAccessRepository databaseAccessRepository) {
         super(databaseService, containerService, databaseAccessRepository);
         this.userService = userService;
         this.accessService = accessService;
         this.databaseMapper = databaseMapper;
-        this.identifierMapper = identifierMapper;
         this.databaseService = databaseService;
         this.queryStoreService = queryStoreService;
-        this.identifierService = identifierService;
         this.messageQueueService = messageQueueService;
         this.databaseAccessRepository = databaseAccessRepository;
     }
@@ -71,18 +62,10 @@ public class DatabaseEndpoint extends AbstractEndpoint {
     public ResponseEntity<List<DatabaseBriefDto>> list(@NotNull @PathVariable("id") Long containerId,
                                                        @NotNull Principal principal) {
         log.debug("endpoint list databases, containerId={}, principal={}", containerId, principal);
-        final List<Identifier> identifiers = identifierService.findAll(containerId);
         final List<DatabaseBriefDto> databases = databaseService.findAll(containerId)
                 .stream()
                 .map(databaseMapper::databaseToDatabaseBriefDto)
                 .collect(Collectors.toList());
-        databases.forEach(db -> {
-            final Optional<Identifier> id = identifiers.stream()
-                    .filter(i -> i.getContainerId().equals(containerId) && i.getDatabaseId().equals(containerId) &&
-                            i.getType().equals(IdentifierType.DATABASE))
-                    .findFirst();
-            id.ifPresent(identifier -> db.setIdentifier(identifierMapper.identifierToIdentifierDto(identifier)));
-        });
         log.trace("list databases resulted in databases {}", databases);
         return ResponseEntity.ok(databases);
     }
@@ -175,12 +158,6 @@ public class DatabaseEndpoint extends AbstractEndpoint {
         log.debug("endpoint find database, containerId={}, databaseId={}", containerId, databaseId);
         final Database database = databaseService.findById(containerId, databaseId);
         final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
-        try {
-            final Identifier identifier = identifierService.find(containerId, databaseId, IdentifierType.DATABASE);
-            dto.setIdentifier(identifierMapper.identifierToIdentifierDto(identifier));
-        } catch (IdentifierNotFoundException e) {
-            // ignore
-        }
         if (principal != null && database.getOwner().getUsername().equals(principal.getName())) {
             /* only owner sees the access rights */
             final List<DatabaseAccess> accesses = accessService.list(databaseId);
diff --git a/fda-database-service/rest-service/src/main/resources/init/querystore.sql b/fda-database-service/rest-service/src/main/resources/init/querystore.sql
index c98ce27ecf601053d39820a82810958644e0254f..26fc6e54370ec268fa2cfa683f37c825d7cfa81b 100644
--- a/fda-database-service/rest-service/src/main/resources/init/querystore.sql
+++ b/fda-database-service/rest-service/src/main/resources/init/querystore.sql
@@ -1,5 +1,5 @@
-CREATE SEQUENCE `qs_queries_seq`;
-CREATE TABLE `qs_queries`( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(255) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint);
-CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255))BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash FROM `', name, '` INTO @hash;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash;END
-CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash); SELECT COUNT(*) FROM _tmp INTO @count; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END
-CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash); SELECT COUNT(*) FROM _tmp INTO @count; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END
\ No newline at end of file
+CREATE SEQUENCE `qs_queries_seq`; 
+CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(255) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint );
+CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT) BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash; SET count = @count; END;
+CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END;
+CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END;
\ No newline at end of file
diff --git a/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql b/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql
index 2762d130a0044c439b41c0215b0d87924bc8f072..5580d0fd260b6ba4fddd24b411a6e74467d151d2 100644
--- a/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql
+++ b/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql
@@ -1,6 +1,5 @@
 CREATE SEQUENCE `qs_queries_seq`;
-CREATE TABLE `qs_queries`
-(
+CREATE TABLE `qs_queries` (
     `id`               bigint       not null primary key default nextval(`qs_queries_seq`),
     `created`          datetime     not null             default now(),
     `executed`         datetime     not null             default now(),
@@ -12,13 +11,14 @@ CREATE TABLE `qs_queries`
     `result_hash`      varchar(255),
     `result_number`    bigint
 );
+
 DELIMITER $$
-CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255))
+CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT)
 BEGIN
     DECLARE _sql TEXT;
     SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',',
                   GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name),
-                  ') SEPARATOR \',\'), 256) AS hash FROM `', name, '` INTO @hash;')
+                  ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;')
     FROM `information_schema`.`columns`
     WHERE `table_schema` = DATABASE()
       AND `table_name` = name
@@ -27,15 +27,16 @@ BEGIN
     EXECUTE stmt;
     DEALLOCATE PREPARE stmt;
     SET hash = @hash;
-END $$
+    SET count = @count;
+END; $$
+
 DELIMITER $$
 CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)
 BEGIN
     DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256);
     DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', '');
     DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')');
-    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash);
-    SELECT COUNT(*) FROM _tmp INTO @count;
+    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count);
     IF @hash IS NULL THEN
         INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`,
                                   `result_number`, `executed`)
@@ -49,15 +50,15 @@ BEGIN
         WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
         SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
     END IF;
-END $$
+END; $$
+
 DELIMITER $$
 CREATE
     DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)
 BEGIN
     DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256);
     DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')');
-    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash);
-    SELECT COUNT(*) FROM _tmp INTO @count;
+    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count);
     IF @hash IS NULL THEN
         INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`,
                                   `result_number`, `executed`)
@@ -71,5 +72,6 @@ BEGIN
         WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
         SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
     END IF;
-END $$
+END; $$
+
 DELIMITER ;
\ No newline at end of file
diff --git a/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index 7a1890e25df228c438451cca2ce8efee0a589d53..e32140f007c003e33e6a48b9224080ea216d3d58 100644
--- a/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -50,7 +50,7 @@ public abstract class BaseUnitTest {
             .build();
 
     public final static String GATEWAY_NAME = "fda-gateway-service";
-    public final static String GATEWAY_IP = "172.29.0.3";
+    public final static String GATEWAY_IP = "172.31.0.3";
     public final static String GATEWAY_HOSTNAME = "gateway-service";
     public final static Integer GATEWAY_PORT = 9095;
     public final static String GATEWAY_IMAGE = "nginx";
@@ -58,7 +58,7 @@ public abstract class BaseUnitTest {
 
     public final static String CONTAINER_SEARCH_NAME = "search-mock-service";
     public final static String CONTAINER_SEARCH_INTERNAL_NAME = "search-mock-service";
-    public final static String CONTAINER_SEARCH_IP = "172.29.0.3";
+    public final static String CONTAINER_SEARCH_IP = "172.31.0.3";
     public final static String CONTAINER_SEARCH_REPOSITORY = "elasticsearch";
     public final static String CONTAINER_SEARCH_TAG = "7.13.4";
 
@@ -330,9 +330,9 @@ public abstract class BaseUnitTest {
             .build();
 
     public final static Long CONTAINER_BROKER_ID = 5L;
-    public final static String CONTAINER_BROKER_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_IP = "172.29.0.2";
+    public final static String CONTAINER_BROKER_NAME = "dbrepo-broker-service";
+    public final static String CONTAINER_BROKER_INTERNAL_NAME = "dbrepo-broker-service";
+    public final static String CONTAINER_BROKER_IP = "172.31.0.2";
     public final static String CONTAINER_BROKER_HASH = "deadbeef";
     public final static Instant CONTAINER_BROKER_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_BROKER_HEALTHCHECK = new HealthCheck()
@@ -366,9 +366,9 @@ public abstract class BaseUnitTest {
 
     public final static Long CONTAINER_1_ID = 1L;
     public final static String CONTAINER_1_HASH = "deadbeef";
-    public final static String CONTAINER_1_IP = "172.28.0.5";
-    public final static String CONTAINER_1_NAME = "fda-userdb-u01";
-    public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01";
+    public final static String CONTAINER_1_IP = "172.30.0.5";
+    public final static String CONTAINER_1_NAME = "u01";
+    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
     public final static Instant CONTAINER_1_CREATED = Instant.now().minus(2, HOURS);
     public final static Instant CONTAINER_1_UPDATED = Instant.now();
     public final static HealthCheck CONTAINER_1_HEALTHCHECK = new HealthCheck()
@@ -393,9 +393,9 @@ public abstract class BaseUnitTest {
 
     public final static Long CONTAINER_2_ID = 2L;
     public final static String CONTAINER_2_HASH = "deadbeef";
-    public final static String CONTAINER_2_IP = "172.28.0.6";
-    public final static String CONTAINER_2_NAME = "fda-userdb-u02";
-    public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02";
+    public final static String CONTAINER_2_IP = "172.30.0.6";
+    public final static String CONTAINER_2_NAME = "u02";
+    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02";
     public final static Instant CONTAINER_2_CREATED = Instant.now().minus(2, HOURS);
     public final static Instant CONTAINER_2_UPDATED = Instant.now();
     public final static HealthCheck CONTAINER_2_HEALTHCHECK = new HealthCheck()
@@ -420,9 +420,9 @@ public abstract class BaseUnitTest {
 
     public final static Long CONTAINER_3_ID = 3L;
     public final static String CONTAINER_3_HASH = "deadbeef";
-    public final static String CONTAINER_3_IP = "172.28.0.7";
-    public final static String CONTAINER_3_NAME = "fda-userdb-u03";
-    public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03";
+    public final static String CONTAINER_3_IP = "172.30.0.7";
+    public final static String CONTAINER_3_NAME = "u03";
+    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03";
     public final static Instant CONTAINER_3_CREATED = Instant.now().minus(2, HOURS);
     public final static Instant CONTAINER_3_UPDATED = Instant.now();
     public final static HealthCheck CONTAINER_3_HEALTHCHECK = new HealthCheck()
@@ -447,9 +447,9 @@ public abstract class BaseUnitTest {
 
     public final static Long CONTAINER_4_ID = 4L;
     public final static String CONTAINER_4_HASH = "deadbeef";
-    public final static String CONTAINER_4_IP = "172.28.0.8";
-    public final static String CONTAINER_4_NAME = "fda-userdb-u04";
-    public final static String CONTAINER_4_INTERNALNAME = "fda-userdb-u04";
+    public final static String CONTAINER_4_IP = "172.30.0.8";
+    public final static String CONTAINER_4_NAME = "u04";
+    public final static String CONTAINER_4_INTERNALNAME = "dbrepo-userdb-u04";
     public final static Instant CONTAINER_4_CREATED = Instant.now().minus(2, HOURS);
     public final static Instant CONTAINER_4_UPDATED = Instant.now();
     public final static HealthCheck CONTAINER_4_HEALTHCHECK = new HealthCheck()
@@ -473,7 +473,7 @@ public abstract class BaseUnitTest {
     public final static Long CONTAINER_ELASTIC_ID = 5L;
     public final static String CONTAINER_ELASTIC_NAME = "fda-elastic-service";
     public final static String CONTAINER_ELASTIC_INTERNAL_NAME = "search-mock-service";
-    public final static String CONTAINER_ELASTIC_IP = "172.29.0.3";
+    public final static String CONTAINER_ELASTIC_IP = "172.31.0.3";
     public final static String CONTAINER_ELASTIC_HASH = "deadbeef";
     public final static Instant CONTAINER_ELASTIC_CREATED = Instant.now().minus(1, HOURS);
 
diff --git a/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
index 5340810c86ad9dd7b7cd93a7e7d874cdb31d2c2e..7c55429c92d2f748d706cc990843b0f86883929e 100644
--- a/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
+++ b/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
@@ -157,14 +157,14 @@ public class DockerConfig extends BaseUnitTest {
                 .withName("fda-userdb")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
+                                .withSubnet("172.30.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         dockerClient.createNetworkCmd()
                 .withName("fda-public")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
+                                .withSubnet("172.31.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
     }
diff --git a/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
index 4808082aff0dbaadbd9cf296306c3be6a3b62759..61cbf30d0255572bc1ca4d62ec5df76672aa478c 100644
--- a/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
+++ b/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
@@ -143,49 +143,67 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @Test
     public void list_anonymousPublic_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), null);
     }
 
     @Test
     @WithAnonymousUser
     public void list_anonymous2Public_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), null);
     }
 
     @Test
     public void list_anonymousPrivate_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_1_PUBLIC);
+
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_2), null);
+        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null);
     }
 
     @Test
     @WithAnonymousUser
     public void list_anonymous2Private_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_1_PUBLIC);
+
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_2), null);
+        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null);
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void list_researcherPublic_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
 
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_1_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void list_researcherPublicWithIdentifiers_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
@@ -193,13 +211,16 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
                 .thenReturn(List.of(IDENTIFIER_1));
 
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_1_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void list_researcherPrivate_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
@@ -212,18 +233,24 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void list_researcherPublicForeignContainer_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
 
         /* test */
-        list_generic(CONTAINER_2_ID, CONTAINER_2, List.of(DATABASE_1), USER_1_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void list_researcherPrivateForeignContainer_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
@@ -236,18 +263,24 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void list_developerPublic_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
                 .thenReturn(Optional.of(USER_2));
 
         /* test */
-        list_generic(CONTAINER_2_ID, CONTAINER_2, List.of(DATABASE_1), USER_2_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_2_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void list_developerPrivate_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
                 .thenReturn(Optional.of(USER_2));
@@ -260,66 +293,84 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void list_developerPublicForeignContainer_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
                 .thenReturn(Optional.of(USER_2));
 
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_2_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_2_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void list_developerPrivateForeignContainer_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_1_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
                 .thenReturn(Optional.of(USER_2));
 
         /* test */
-        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_2), USER_2_PRINCIPAL);
+        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_2_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
     public void list_dataStewardPublic_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_1), USER_3_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_3_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
     public void list_dataStewardPrivate_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_1_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_2), USER_3_PRINCIPAL);
+        list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_3_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
     public void list_dataStewardPublicForeignContainer_succeeds() {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        list_generic(CONTAINER_2_ID, CONTAINER_2, List.of(DATABASE_1), USER_3_PRINCIPAL);
+        list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_3_PRINCIPAL);
     }
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
     public void list_dataStewardPrivateForeignContainer_succeeds() {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
@@ -497,8 +548,11 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void findById_researcherPublic_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL);
+        findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -506,6 +560,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     public void findById_researcherPublicForeignDatabase_succeeds() throws AccessDeniedException,
             DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
     }
@@ -514,6 +571,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
     public void findById_researcherPrivate_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_PRINCIPAL);
     }
@@ -523,6 +583,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     public void findById_researcherPrivateForeignDatabase_succeeds() throws AccessDeniedException,
             DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_PRINCIPAL);
     }
@@ -532,6 +595,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     public void findById_developerPublicForeignDatabase_succeeds() throws AccessDeniedException,
             DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL);
     }
@@ -540,6 +606,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
     public void findById_developerPrivate_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_2_PRINCIPAL);
     }
@@ -548,6 +617,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
     public void findById_dataStewardPublic_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_PRINCIPAL);
     }
@@ -557,8 +629,11 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     public void findById_dataStewardPublicForeignDatabase_succeeds() throws AccessDeniedException,
             DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertTrue(DATABASE_3_PUBLIC);
+
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, USER_3_PRINCIPAL);
+        findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_PRINCIPAL);
     }
 
     @Test
@@ -566,6 +641,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     public void findById_dataStewardPrivateForeignDatabase_succeeds() throws AccessDeniedException,
             DatabaseNotFoundException {
 
+        /* pre-condition */
+        assertFalse(DATABASE_2_PUBLIC);
+
         /* test */
         findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_3_PRINCIPAL);
     }
diff --git a/fda-database-service/rest-service/src/test/resources/application.properties b/fda-database-service/rest-service/src/test/resources/application.properties
index 33b8c25e25a0fe7db1a47bc8349d3d31e834e179..ddfddd8b33f6b4807c1047703d873571b4f89c24 100644
--- a/fda-database-service/rest-service/src/test/resources/application.properties
+++ b/fda-database-service/rest-service/src/test/resources/application.properties
@@ -22,8 +22,8 @@ logging.level.root=error
 logging.level.at.tuwien.=info
 
 # rabbitmq
-fda.gateway.endpoint=http://broker-service:15672
-spring.rabbitmq.host=broker-service
+fda.gateway.endpoint=http://dbrepo-broker-service:15672
+spring.rabbitmq.host=dbrepo-broker-service
 
 # elastic
 fda.elastic.endpoint=search-mock-service:9200
\ No newline at end of file
diff --git a/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf b/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf
index f4ada65dc83ba0cb149a1136ef36bbaf87fff513..6604865024d8e32d66f23a8f49fd0bca5e2c3e70 100644
--- a/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf
+++ b/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf
@@ -39,7 +39,7 @@ http {
             proxy_set_header        X-Real-IP $remote_addr;
             proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_set_header        X-Forwarded-Proto $scheme;
-            proxy_pass              http://broker-service:15672;
+            proxy_pass              http://dbrepo-broker-service:15672;
             proxy_read_timeout      90;
         }
     }
diff --git a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
index 26aca837e2aa6721fbf29c42bd0cdb6336bd11db..f986f7577245bb0161e9d5d046da92fd22e40012 100644
--- a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
+++ b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
@@ -85,6 +85,7 @@ public interface DatabaseMapper {
             @Mapping(target = "id", source = "id"),
             @Mapping(target = "engine", source = "container.image", qualifiedByName = "engineMapping"),
             @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"),
+            @Mapping(target = "container", ignore = true),
     })
     DatabaseBriefDto databaseToDatabaseBriefDto(Database data);
 
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
index c8a6ff55aa0d1bd132e4980faf983eed383fa230..e48292d75310ad48545ef11501778970e166fe6e 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.container;
 
+import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.api.user.UserBriefDto;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -36,6 +37,9 @@ public class ContainerBriefDto {
     @Schema(example = "air-quality")
     private String internalName;
 
+    @org.springframework.data.annotation.Transient
+    private DatabaseBriefDto database;
+
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
     private Instant created;
 }
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java
index 699889b1c14ae5b0dea7b269859a75f7d5ec0b41..d91f7ce74dfda4a4ef483c774ab25f3b8f7e763e 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java
@@ -1,6 +1,7 @@
 package at.tuwien.api.database;
 
 import at.tuwien.api.container.ContainerBriefDto;
+import at.tuwien.api.identifier.IdentifierBriefDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.UserBriefDto;
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -30,7 +31,7 @@ public class DatabaseBriefDto {
     @Schema(example = "Air Quality in Austria")
     private String description;
 
-    private IdentifierDto identifier;
+    private IdentifierBriefDto identifier;
 
     @JsonProperty("is_public")
     @Schema(example = "true")
@@ -39,11 +40,10 @@ public class DatabaseBriefDto {
     @Schema(example = "mariadb:10.5")
     private String engine;
 
+    @ToString.Exclude
     @org.springframework.data.annotation.Transient
     private ContainerBriefDto container;
 
-    private UserBriefDto creator;
-
     @Schema(example = "2020-08-04 11:12:00")
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
     private Instant created;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad0910407b22e7c89f9e9f10a18e622a475e6cf7
--- /dev/null
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java
@@ -0,0 +1,28 @@
+
+package at.tuwien.api.identifier;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+@Data
+@Getter
+@Setter
+@Builder
+public class CreatorBriefDto {
+
+    @NotBlank
+    @Schema(example = "Josiah")
+    private String firstname;
+
+    @NotBlank
+    @Schema(example = "Carberry")
+    private String lastname;
+
+    @Schema(example = "Wesleyan University")
+    private String affiliation;
+
+}
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
index a3e816be75a185466c64e6c91b86a5318e072771..c17feec05c19de48c19767e6cf083a8a7a8d01d8 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
@@ -12,6 +12,7 @@ import lombok.Setter;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import java.time.Instant;
+import java.util.List;
 
 @Data
 @Getter
@@ -43,6 +44,24 @@ public class IdentifierBriefDto {
     @NotNull
     private IdentifierTypeDto type;
 
+    @NotNull
+    @Schema(example = "everyone")
+    private VisibilityTypeDto visibility;
+
+    @Schema(example = "10.1038/nphys1170")
+    private String doi;
+
+    @Schema(example = "TU Wien")
+    private String publisher;
+
+    @NotNull
+    @JsonProperty("publication_year")
+    @Schema(example = "2022")
+    private Integer publicationYear;
+
+    @NotNull
+    private List<CreatorBriefDto> creators;
+
     @JsonIgnore
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
     private Instant created;
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java
index 90a49b81b8ff9b4d7606ccab40af547aa8850e55..a3233d71357167b90055506402e4d873f59a3c5c 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java
@@ -5,16 +5,15 @@ import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.identifier.Identifier;
 import at.tuwien.entities.user.User;
 import lombok.*;
-import net.sf.jsqlparser.statement.select.FromItem;
-import org.hibernate.annotations.GenericGenerator;
-import org.hibernate.annotations.SQLDelete;
-import org.hibernate.annotations.Where;
+import org.hibernate.annotations.*;
 import org.springframework.data.annotation.CreatedDate;
 import org.springframework.data.annotation.LastModifiedDate;
-import org.springframework.data.elasticsearch.annotations.Document;
 import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import java.io.Serializable;
 import java.time.Instant;
 import java.util.List;
 
@@ -28,7 +27,7 @@ import java.util.List;
 @javax.persistence.Table(name = "mdb_databases", uniqueConstraints = {
         @UniqueConstraint(columnNames = {"id", "internalName"})
 })
-public class Database {
+public class Database implements Serializable {
 
     @Id
     @EqualsAndHashCode.Include
@@ -73,6 +72,13 @@ public class Database {
     })
     private User contact;
 
+    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+    @JoinColumnsOrFormulas({
+            @JoinColumnOrFormula(formula = @JoinFormula(value = "'DATABASE'", referencedColumnName = "identifier_type")),
+            @JoinColumnOrFormula(column = @JoinColumn(name = "id", referencedColumnName = "dbid", insertable = false, updatable = false)),
+    })
+    private Identifier identifier;
+
     @ToString.Exclude
     @org.springframework.data.annotation.Transient
     @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java
index f75494670fbd8f6c1e3b9dced505028d1b9c2507..09e85f03b7267363bfdda8411642351703cdc61a 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java
@@ -1,5 +1,6 @@
 package at.tuwien.entities.database;
 
+import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.user.User;
 import lombok.*;
 import net.sf.jsqlparser.statement.select.FromItem;
@@ -11,6 +12,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
 import java.time.Instant;
+import java.util.List;
 
 @Data
 @Entity
@@ -82,6 +84,21 @@ public class View {
         return this.getInternalName().equals(name);
     }
 
+    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
+    @JoinTable(name = "mdb_view_columns",
+            joinColumns = {
+                    @JoinColumn(name = "vid", referencedColumnName = "id", insertable = false, updatable = false),
+                    @JoinColumn(name = "vcid", referencedColumnName = "vcid", insertable = false, updatable = false),
+                    @JoinColumn(name = "vdbid", referencedColumnName = "vdbid", insertable = false, updatable = false)
+            },
+            inverseJoinColumns = {
+                    @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false),
+                    @JoinColumn(name = "ctid", referencedColumnName = "tid", insertable = false, updatable = false),
+                    @JoinColumn(name = "cdbid", referencedColumnName = "cdbid", insertable = false, updatable = false)
+            })
+    @OrderColumn(name = "position")
+    private List<TableColumn> columns;
+
     @Column(nullable = false, updatable = false)
     @CreatedDate
     private Instant created;
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java
index a6385bb9088b4e703a479f229213141401839b76..95ffd29e5907c9585f1f64402e396dc5d24065d1 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java
@@ -3,19 +3,16 @@ package at.tuwien.entities.identifier;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.LanguageType;
 import at.tuwien.entities.database.License;
-import at.tuwien.entities.user.Token;
 import at.tuwien.entities.user.User;
 import lombok.*;
 import org.hibernate.annotations.GenericGenerator;
-import org.hibernate.annotations.SQLDelete;
-import org.hibernate.annotations.Where;
 import org.springframework.data.annotation.CreatedDate;
 import org.springframework.data.annotation.LastModifiedDate;
-import org.springframework.data.elasticsearch.annotations.Document;
 import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
 import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
 import java.time.Instant;
 import java.util.List;
 
@@ -29,7 +26,7 @@ import java.util.List;
 @javax.persistence.Table(name = "mdb_identifiers", uniqueConstraints = {
         @UniqueConstraint(columnNames = {"qid", "cid", "dbid"})
 })
-public class Identifier {
+public class Identifier implements Serializable {
 
     @Id
     @EqualsAndHashCode.Include
diff --git a/fda-metadata-db/querystore/src/main/java/at/tuwien/querystore/Query.java b/fda-metadata-db/querystore/src/main/java/at/tuwien/querystore/Query.java
index 8df1ced8691c05bb429a5aa56c0d2553c5b843af..f589913ec36b76fdc99fe90dff41b3ecae5d060f 100644
--- a/fda-metadata-db/querystore/src/main/java/at/tuwien/querystore/Query.java
+++ b/fda-metadata-db/querystore/src/main/java/at/tuwien/querystore/Query.java
@@ -62,6 +62,9 @@ public class Query implements Serializable {
     @CreatedDate
     private Instant created;
 
+    @javax.persistence.Column(nullable = false, updatable = false)
+    private Instant executed;
+
     @javax.persistence.Column(nullable = false)
     private String createdBy;
 
diff --git a/fda-metadata-db/setup-schema.sql b/fda-metadata-db/setup-schema.sql
index 60b5f3cf502cdadf42d6f7a6e52177e2fb72c37d..8e45d7012c076f0e130117564ae5386f17efa88e 100644
--- a/fda-metadata-db/setup-schema.sql
+++ b/fda-metadata-db/setup-schema.sql
@@ -341,7 +341,22 @@ CREATE TABLE IF NOT EXISTS mdb_view
     created_by    bigint       NOT NULL,
     FOREIGN KEY (created_by) REFERENCES mdb_users (UserID),
     FOREIGN KEY (vdbid) REFERENCES mdb_databases (id),
-    PRIMARY KEY (id, vdbid)
+    PRIMARY KEY (id, vcid, vdbid)
+) WITH SYSTEM VERSIONING;
+
+CREATE TABLE mdb_view_columns
+(
+    id               BIGINT  NOT NULL AUTO_INCREMENT,
+    cid              BIGINT  NOT NULL,
+    ctid             BIGINT  NOT NULL,
+    cdbid            BIGINT  NOT NULL,
+    vid              BIGINT  NOT NULL,
+    vcid             BIGINT  NOT NULL,
+    vdbid            BIGINT  NOT NULL,
+    position         INTEGER NULL,
+    PRIMARY KEY (id),
+    FOREIGN KEY (vid, vcid, vdbid) REFERENCES mdb_view (id, vcid, vdbid),
+    FOREIGN KEY (cid, cdbid, ctid) REFERENCES mdb_columns (ID, cDBID, tID)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS mdb_identifiers
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java
index 263c3ff8629a4d1d1bd191ee57e49632f9baa427..33a9c761a6ebd7d6ffd065362c5db011faf9483f 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java
@@ -53,7 +53,7 @@ public class ExportEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Missing data export permission");
         }
         final HttpHeaders headers = new HttpHeaders();
-        final ExportResource resource = queryService.findAll(containerId, databaseId, tableId, timestamp, principal);
+        final ExportResource resource = queryService.tableFindAll(containerId, databaseId, tableId, timestamp, principal);
         headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
         log.trace("export table resulted in resource {}", resource);
         return ResponseEntity.ok()
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java
index 05db9d96edbec6859fe89bd718f38e4bf5dca9da..6f4faa2b4197be398b573ea68f76eddc8c42ab8b 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java
@@ -108,6 +108,32 @@ public class QueryEndpoint extends AbstractEndpoint {
                 .body(result);
     }
 
+    @GetMapping("/{queryId}/data/count")
+    @Transactional(readOnly = true)
+    @Timed(value = "query.reexecute.count", description = "Time needed to re-execute a query")
+    @Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth"))
+    public ResponseEntity<Long> reExecuteCount(@NotNull @PathVariable("id") Long containerId,
+                                                    @NotNull @PathVariable("databaseId") Long databaseId,
+                                                    @NotNull @PathVariable("queryId") Long queryId,
+                                                    Principal principal)
+            throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
+            QueryMalformedException, TableMalformedException, ColumnParseException, NotAllowedException,
+            DatabaseConnectionException, UserNotFoundException {
+        log.debug("endpoint re-execute query count, containerId={}, databaseId={}, queryId={}, principal={}",
+                containerId, databaseId, queryId, principal);
+        /* check */
+        if (!hasQueryPermission(containerId, databaseId, queryId, "QUERY_RE_EXECUTE", principal)) {
+            log.error("Missing re-execute query permission");
+            throw new NotAllowedException("Missing re-execute query permission");
+        }
+        /* execute */
+        final Query query = storeService.findOne(containerId, databaseId, queryId, principal);
+        final Long result = queryService.reExecuteCount(containerId, databaseId, query, principal);
+        log.trace("re-execute query count resulted in result {}", result);
+        return ResponseEntity.status(HttpStatus.ACCEPTED)
+                .body(result);
+    }
+
     @GetMapping("/{queryId}/export")
     @Transactional(readOnly = true)
     @Timed(value = "query.export", description = "Time needed to export query data")
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java
index a1d1e8648268418e1c0efa75efa2faa8379106a5..277e622b6273f66827b116972b8498e30b20dc43 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java
@@ -14,7 +14,6 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpHeaders;
 import org.springframework.http.ResponseEntity;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -148,7 +147,7 @@ public class TableDataEndpoint extends AbstractEndpoint {
                                                  @RequestParam(required = false) String sortColumn)
             throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException,
             ImageNotSupportedException, TableMalformedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
+            NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
         log.debug("endpoint find table data, containerId={}, databaseId={}, tableId={}, principal={}, timestamp={}, page={}, size={}, sortDirection={}, sortColumn={}",
                 containerId, databaseId, tableId, principal, timestamp, page, size, sortDirection, sortColumn);
         /* check */
@@ -157,17 +156,35 @@ public class TableDataEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Missing data view permission");
         }
         validateDataParams(page, size, sortDirection, sortColumn);
-        /* find */
-        final Long count = queryService.count(containerId, databaseId, tableId, timestamp, principal);
-        log.debug("find table data has produced {} tuples", count);
-        final HttpHeaders headers = new HttpHeaders();
-        headers.set("FDA-COUNT", count.toString());
-        final QueryResultDto response = queryService.findAll(containerId, databaseId, tableId, timestamp, page, size, principal);
+        final QueryResultDto response = queryService.tableFindAll(containerId, databaseId, tableId, timestamp, page, size, principal);
         log.trace("find table data resulted in result {}", response);
         return ResponseEntity.ok()
-                .headers(headers)
                 .body(response);
     }
 
+    @GetMapping("/count")
+    @Timed(value = "data.all.count", description = "Time needed to get count of all data from a table")
+    @Operation(summary = "Find data", security = @SecurityRequirement(name = "bearerAuth"))
+    public ResponseEntity<Long> getCount(@NotNull @PathVariable("id") Long containerId,
+                                                 @NotNull @PathVariable("databaseId") Long databaseId,
+                                                 @NotNull @PathVariable("tableId") Long tableId,
+                                                 @NotNull Principal principal,
+                                                 @RequestParam(required = false) Instant timestamp)
+            throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException,
+            ImageNotSupportedException, TableMalformedException, PaginationException, ContainerNotFoundException,
+            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
+        log.debug("endpoint find table data, containerId={}, databaseId={}, tableId={}, principal={}, timestamp={}",
+                containerId, databaseId, tableId, principal, timestamp);
+        /* check */
+        if (!hasTablePermission(containerId, databaseId, tableId, "DATA_VIEW", principal)) {
+            log.error("Missing data view permission");
+            throw new NotAllowedException("Missing data view permission");
+        }
+        /* find */
+        final Long count = queryService.tableCount(containerId, databaseId, tableId, timestamp, principal);
+        log.debug("table data count is {} tuples", count);
+        return ResponseEntity.ok()
+                .body(count);
+    }
 
 }
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java
index 244280cac6a6a35723526a9aef867d187e1d9a7c..b5b2bf6954025a38f46c79de4b489067324b0945 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java
@@ -92,7 +92,8 @@ public class ViewEndpoint extends AbstractEndpoint {
         }
         final Database database = databaseService.find(containerId, databaseId);
         log.trace("create view for database {}", database);
-        final View view = viewService.create(containerId, databaseId, data, principal);
+        final View view;
+        view = viewService.create(containerId, databaseId, data, principal);
         final ViewBriefDto dto = viewMapper.viewToViewBriefDto(view);
         log.trace("create view resulted in view {}", dto);
         return ResponseEntity.status(HttpStatus.CREATED)
@@ -154,7 +155,7 @@ public class ViewEndpoint extends AbstractEndpoint {
                                                @RequestParam(required = false) Long size)
             throws DatabaseNotFoundException, NotAllowedException, ViewNotFoundException, PaginationException,
             QueryStoreException, DatabaseConnectionException, TableMalformedException, QueryMalformedException,
-            ImageNotSupportedException, ColumnParseException, UserNotFoundException, ContainerNotFoundException {
+            ImageNotSupportedException, ColumnParseException, UserNotFoundException, ContainerNotFoundException, ViewMalformedException {
         log.debug("endpoint find view data, containerId={}, databaseId={}, viewId={}, principal={}, page={}, size={}",
                 containerId, databaseId, viewId, principal, page, size);
         /* check */
@@ -167,12 +168,37 @@ public class ViewEndpoint extends AbstractEndpoint {
         final Database database = databaseService.find(containerId, databaseId);
         log.trace("find view data for database {}", database);
         final View view = viewService.findById(databaseId, viewId, principal);
-        final ExecuteStatementDto statement = ExecuteStatementDto.builder()
-                .statement(view.getQuery())
-                .build();
-        log.trace("find view execute statement {}", statement);
-        final QueryResultDto result = queryService.execute(containerId, databaseId, statement, principal, page, size,
-                null, null);
+        final QueryResultDto result = queryService.viewFindAll(containerId, databaseId, view, page, size, principal);
+        log.trace("execute view {}", view);
+        log.trace("find view data resulted in result {}", result);
+        return ResponseEntity.ok()
+                .body(result);
+    }
+
+    @GetMapping("/{viewId}/data/count")
+    @Transactional(readOnly = true)
+    @Timed(value = "view.data.count", description = "Time needed to retrieve data count from a view")
+    @Operation(summary = "Find view data count", security = @SecurityRequirement(name = "bearerAuth"))
+    public ResponseEntity<Long> count(@NotNull @PathVariable("id") Long containerId,
+                                               @NotNull @PathVariable("databaseId") Long databaseId,
+                                               @NotNull @PathVariable("viewId") Long viewId,
+                                               Principal principal)
+            throws DatabaseNotFoundException, NotAllowedException, ViewNotFoundException, PaginationException,
+            QueryStoreException, DatabaseConnectionException, TableMalformedException, QueryMalformedException,
+            ImageNotSupportedException, ColumnParseException, UserNotFoundException, ContainerNotFoundException, ViewMalformedException {
+        log.debug("endpoint find view data count, containerId={}, databaseId={}, viewId={}, principal={}",
+                containerId, databaseId, viewId, principal);
+        /* check */
+        if (!hasDatabasePermission(containerId, databaseId, "DATA_VIEW", principal)) {
+            log.error("Missing view data in view permission");
+            throw new NotAllowedException("Missing view data in view permission");
+        }
+        /* find */
+        final Database database = databaseService.find(containerId, databaseId);
+        log.trace("find view data for database {}", database);
+        final View view = viewService.findById(databaseId, viewId, principal);
+        final Long result = queryService.viewCount(containerId, databaseId, view, principal);
+        log.trace("execute view {}", view);
         log.trace("find view data resulted in result {}", result);
         return ResponseEntity.ok()
                 .body(result);
diff --git a/fda-query-service/rest-service/src/main/resources/application-local.yml b/fda-query-service/rest-service/src/main/resources/application-local.yml
index 8e36da9b7be6e9aa2e1ba5aee7d69ab244f1cd24..9451262fbd588419c058cfa6f760a81500a7b1e6 100644
--- a/fda-query-service/rest-service/src/main/resources/application-local.yml
+++ b/fda-query-service/rest-service/src/main/resources/application-local.yml
@@ -32,7 +32,7 @@ logging:
   pattern.console: "%d %highlight(%-5level) %msg%n"
   level:
     root: warn
-    at.tuwien.: info
+    at.tuwien.: trace
     org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug
 eureka:
   instance.hostname: query-service
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index 1849e0135109af8a1511450953369e1193a10133..f68fbda5959a9386a81d5e51d2f2e29ff59a95ad 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -300,12 +300,22 @@ public abstract class BaseUnitTest {
             .tag(IMAGE_ELASTIC_TAG)
             .build();
 
+    public final static Long IMAGE_PROXY_ID = 4L;
+    public final static String IMAGE_PROXY_REPOSITORY = "nginx";
+    public final static String IMAGE_PROXY_TAG = "latest";
+
+    public final static ContainerImage IMAGE_PROXY = ContainerImage.builder()
+            .id(IMAGE_PROXY_ID)
+            .repository(IMAGE_PROXY_REPOSITORY)
+            .tag(IMAGE_PROXY_TAG)
+            .build();
+
     public final static Long CONTAINER_1_ID = 1L;
     public final static String CONTAINER_1_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
     public final static String CONTAINER_1_NAME = "u01";
-    public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01";
-    public final static String CONTAINER_1_IP = "172.28.0.5";
+    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
+    public final static String CONTAINER_1_IP = "172.30.0.5";
     public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS);
     public final static String[] CONTAINER_1_ENV = new String[]{"MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb",
             "MARIADB_DATABASE=weather"};
@@ -328,8 +338,8 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_2_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_1;
     public final static String CONTAINER_2_NAME = "u02";
-    public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02";
-    public final static String CONTAINER_2_IP = "172.28.0.6";
+    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02";
+    public final static String CONTAINER_2_IP = "172.30.0.6";
     public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS);
     public final static String[] CONTAINER_2_ENV = new String[]{"MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb",
             "MARIADB_DATABASE=zoo"};
@@ -352,8 +362,8 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_3_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_1;
     public final static String CONTAINER_3_NAME = "u03";
-    public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03";
-    public final static String CONTAINER_3_IP = "172.28.0.7";
+    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03";
+    public final static String CONTAINER_3_IP = "172.30.0.7";
     public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_3_HEALTHCHECK = new HealthCheck()
             .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb"));
@@ -373,8 +383,8 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_4_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_4_IMAGE = IMAGE_1;
     public final static String CONTAINER_4_NAME = "u04";
-    public final static String CONTAINER_4_INTERNALNAME = "fda-userdb-u04";
-    public final static String CONTAINER_4_IP = "172.28.0.8";
+    public final static String CONTAINER_4_INTERNALNAME = "dbrepo-userdb-u04";
+    public final static String CONTAINER_4_IP = "172.30.0.8";
     public final static Instant CONTAINER_4_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_4_HEALTHCHECK = new HealthCheck()
             .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb"));
@@ -394,9 +404,9 @@ public abstract class BaseUnitTest {
             .build();
 
     public final static Long CONTAINER_BROKER_ID = 5L;
-    public final static String CONTAINER_BROKER_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_IP = "172.29.0.2";
+    public final static String CONTAINER_BROKER_NAME = "dbrepo-broker-service";
+    public final static String CONTAINER_BROKER_INTERNAL_NAME = "dbrepo-broker-service";
+    public final static String CONTAINER_BROKER_IP = "172.31.0.2";
     public final static String CONTAINER_BROKER_HASH = "deadbeef";
     public final static Instant CONTAINER_BROKER_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_BROKER_HEALTHCHECK = new HealthCheck()
@@ -418,7 +428,7 @@ public abstract class BaseUnitTest {
     public final static Long CONTAINER_ELASTIC_ID = 6L;
     public final static String CONTAINER_ELASTIC_NAME = "fda-elastic-service";
     public final static String CONTAINER_ELASTIC_INTERNAL_NAME = "search-mock-service";
-    public final static String CONTAINER_ELASTIC_IP = "172.29.0.3";
+    public final static String CONTAINER_ELASTIC_IP = "172.31.0.3";
     public final static String CONTAINER_ELASTIC_HASH = "deadbeef";
     public final static Instant CONTAINER_ELASTIC_CREATED = Instant.now().minus(1, HOURS);
 
@@ -434,6 +444,28 @@ public abstract class BaseUnitTest {
             .creator(USER_1)
             .build();
 
+    public final static Long CONTAINER_PROXY_ID = 7L;
+    public final static String CONTAINER_PROXY_NAME = "dbrepo-proxy";
+    public final static String CONTAINER_PROXY_INTERNAL_NAME = "dbrepo-proxy";
+    public final static String CONTAINER_PROXY_IP = "172.31.0.4";
+    public final static String CONTAINER_PROXY_HASH = "deadbeef";
+    public final static Instant CONTAINER_PROXY_CREATED = Instant.now().minus(1, HOURS);
+    public final static String[] CONTAINER_PROXY_ENV = new String[]{};
+    public final static HealthCheck CONTAINER_PROXY_HEALTHCHECK = new HealthCheck()
+            .withTest(List.of("CMD", "service", "nginx", "status"));
+
+    public final static Container CONTAINER_PROXY = Container.builder()
+            .id(CONTAINER_PROXY_ID)
+            .name(CONTAINER_PROXY_NAME)
+            .internalName(CONTAINER_PROXY_INTERNAL_NAME)
+            .imageId(IMAGE_PROXY_ID)
+            .image(IMAGE_PROXY)
+            .hash(CONTAINER_PROXY_HASH)
+            .ipAddress(CONTAINER_PROXY_IP)
+            .created(CONTAINER_PROXY_CREATED)
+            .creator(USER_1)
+            .build();
+
     public final static Long DATABASE_1_ID = 1L;
     public final static String DATABASE_1_NAME = "Weather";
     public final static String DATABASE_1_INTERNALNAME = "weather";
@@ -997,9 +1029,10 @@ public abstract class BaseUnitTest {
     public final static String QUERY_1_DOI = "1111/1";
     public final static Long QUERY_1_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long QUERY_1_DATABASE_ID = DATABASE_1_ID;
+    public final static Long QUERY_1_RESULT_NUMBER = 2L;
     public final static String QUERY_1_QUERY_HASH = "a3b8ac39e38167d14cf3a9c20a69e4b6954d049525390b973a2c23064953a992";
     public final static String QUERY_1_RESULT_HASH = "8358c8ade4849d2094ab5bb29127afdae57e6bb5acb1db7af603813d406c467a";
-    public final static Instant QUERY_1_CREATED = Instant.now();
+    public final static Instant QUERY_1_CREATED = Instant.ofEpochSecond(1677648377);
     public final static Instant QUERY_1_EXECUTION = Instant.now();
     public final static Boolean QUERY_1_PERSISTED = false;
 
@@ -1008,9 +1041,12 @@ public abstract class BaseUnitTest {
             .query(QUERY_1_STATEMENT)
             .queryHash(QUERY_1_QUERY_HASH)
             .resultHash(QUERY_1_RESULT_HASH)
+            .resultNumber(QUERY_1_RESULT_NUMBER)
             .created(QUERY_1_CREATED)
             .createdBy(USER_1_USERNAME)
             .isPersisted(QUERY_1_PERSISTED)
+            .executed(QUERY_1_EXECUTION)
+            .created(QUERY_1_CREATED)
             .build();
 
     public final static QueryDto QUERY_1_DTO = QueryDto.builder()
@@ -1044,6 +1080,7 @@ public abstract class BaseUnitTest {
     public final static String QUERY_2_QUERY_HASH = "a2d2dd94ebc7653bb5a3b55dd8ed5e91d3d13c225c6855a1eb4eb7ca14c36ced";
     public final static Long QUERY_2_CONTAINER_ID = CONTAINER_2_ID;
     public final static Long QUERY_2_DATABASE_ID = DATABASE_2_ID;
+    public final static Long QUERY_2_RESULT_NUMBER = 2L;
     public final static String QUERY_2_RESULT_HASH = "ff3f7cbe1b96d296957f6e39e55b8b1b577fa3d205d4795af99594cfd20cb80d";
     public final static Instant QUERY_2_CREATED = Instant.now().minus(2, MINUTES);
     public final static Instant QUERY_2_EXECUTION = Instant.now().minus(1, MINUTES);
@@ -1054,9 +1091,12 @@ public abstract class BaseUnitTest {
             .query(QUERY_2_STATEMENT)
             .queryHash(QUERY_2_QUERY_HASH)
             .resultHash(QUERY_2_RESULT_HASH)
+            .resultNumber(QUERY_2_RESULT_NUMBER)
             .created(QUERY_2_CREATED)
             .createdBy(USER_1_USERNAME)
             .isPersisted(QUERY_2_PERSISTED)
+            .created(QUERY_2_CREATED)
+            .executed(QUERY_2_EXECUTION)
             .build();
 
     public final static List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder()
@@ -2122,6 +2162,20 @@ public abstract class BaseUnitTest {
             .creator(USER_1)
             .build();
 
+    public final static Table TABLE_4_NOCOLS = Table.builder()
+            .id(TABLE_4_ID)
+            .created(Instant.now())
+            .internalName(TABLE_4_INTERNALNAME)
+            .description(TABLE_4_DESCRIPTION)
+            .name(TABLE_4_NAME)
+            .lastModified(TABLE_4_LAST_MODIFIED)
+            .tdbid(DATABASE_1_ID)
+            .queueName(TABLE_4_QUEUE_NAME)
+            .routingKey(TABLE_4_ROUTING_KEY)
+            .columns(List.of())
+            .creator(USER_1)
+            .build();
+
     public final static List<TableColumn> TABLE_5_COLUMNS = List.of(TableColumn.builder()
                     .id(COLUMN_5_1_ID)
                     .ordinalPosition(COLUMN_5_1_ORDINALPOS)
@@ -2255,6 +2309,20 @@ public abstract class BaseUnitTest {
             .creator(USER_1)
             .build();
 
+    public final static Table TABLE_7_NOCOLS = Table.builder()
+            .id(TABLE_7_ID)
+            .created(Instant.now())
+            .internalName(TABLE_7_INTERNAL_NAME)
+            .description(TABLE_7_DESCRIPTION)
+            .name(TABLE_7_NAME)
+            .lastModified(TABLE_7_LAST_MODIFIED)
+            .tdbid(DATABASE_1_ID)
+            .queueName(TABLE_7_QUEUE_NAME)
+            .routingKey(TABLE_7_ROUTING_KEY)
+            .columns(List.of())
+            .creator(USER_1)
+            .build();
+
     public final static Long VIEW_1_ID = 1L;
     public final static Boolean VIEW_1_INITIAL_VIEW = false;
     public final static String VIEW_1_NAME = "JUnit";
@@ -2379,8 +2447,8 @@ public abstract class BaseUnitTest {
             .exchangeName(DATABASE_1_EXCHANGE)
             .creator(USER_1)
             .owner(USER_1)
-            .tables(List.of()) /* TABLE_1, TABLE_2, TABLE_3 */
-            .views(List.of())
+            .tables(List.of(TABLE_1, TABLE_2, TABLE_3, TABLE_7))
+            .views(List.of(VIEW_1))
             .build();
 
     public final static Database DATABASE_2 = Database.builder()
@@ -2414,7 +2482,6 @@ public abstract class BaseUnitTest {
             .build();
 
     public final static Long QUERY_1_RESULT_ID = 1L;
-    public final static Long QUERY_1_RESULT_NUMBER = 2L;
     public final static List<Map<String, Object>> QUERY_1_RESULT_RESULT = List.of(
             new HashMap<>() {{
                 put("location", "Albury");
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java
index eac19243984f0eb4936c6121ade14f9b9ece160f..bf3df721bafd91903a06bc74726a6347a1a293e5 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java
@@ -5,7 +5,6 @@ import at.tuwien.config.H2Utils;
 import at.tuwien.config.IndexConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.gateway.AuthenticationServiceGateway;
-import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.UserRepository;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
@@ -46,9 +45,6 @@ public class AuthTokenFilterTest extends BaseUnitTest {
     @MockBean
     private UserRepository userRepository;
 
-    @MockBean
-    private RabbitMqListenerImpl rabbitMqListener;
-
     @MockBean
     private AuthenticationServiceGateway authenticationServiceGateway;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
index 2f03e666f19c250ae0afe19f3bdc548586e2acc3..f91219b29e5831a008e39cc3656d47d9bbdcf6e0 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java
@@ -90,12 +90,16 @@ public class DockerConfig extends BaseUnitTest {
         final HostConfig hostConfig1;
         final String network = (container.getInternalName().contains("userdb") ? "fda-userdb" : "fda-public");
         if (bind == null) {
+            log.trace("map standard binding /tmp:/tmp");
             hostConfig1 = hostConfig.withNetworkMode(network)
                     .withBinds(Bind.parse("/tmp:/tmp"));
         } else {
-            hostConfig1 = hostConfig.withNetworkMode(network).withBinds(Bind.parse(bind), Bind.parse("/tmp:/tmp"));
+            log.trace("map non-standard binding {}, /tmp:/tmp", bind);
+            hostConfig1 = hostConfig.withNetworkMode(network)
+                    .withBinds(Bind.parse(bind), Bind.parse("/tmp:/tmp"));
         }
         if (port != null) {
+            log.trace("map port binding {}:{}", port, port);
             hostConfig1.withPortBindings(PortBinding.parse(port + ":" + port));
         }
         final CreateContainerCmd cmd = dockerClient.createContainerCmd(container.getImage().getRepository() + ":" + container.getImage().getTag())
@@ -158,14 +162,14 @@ public class DockerConfig extends BaseUnitTest {
                 .withName("fda-userdb")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
+                                .withSubnet("172.30.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         dockerClient.createNetworkCmd()
                 .withName("fda-public")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
+                                .withSubnet("172.31.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
     }
@@ -191,6 +195,9 @@ public class DockerConfig extends BaseUnitTest {
             case 5:
                 log.debug("container with id {} has a health check config", containerId);
                 return CONTAINER_BROKER_HEALTHCHECK;
+            case 7:
+                log.debug("container with id {} has a health check config", containerId);
+                return CONTAINER_PROXY_HEALTHCHECK;
         }
         log.trace("container with id {} does not have a healthcheck config", containerId);
         return null;
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java b/fda-query-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java
index 076c1b05ccacc15ff2a66d188f118663c5207e54..8d00a9e77e0cb7674bdfd13d5d348244a08e0f92 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java
@@ -18,12 +18,44 @@ public class MariaDbConfig {
         final String jdbc = "jdbc:mariadb://" + hostname + "/" + database;
         log.trace("connect to database {}", jdbc);
         final Connection connection = DriverManager.getConnection(jdbc, "root", "mariadb");
-        final Statement statement = connection.createStatement();
-        statement.execute("INSERT INTO qs_queries (created_by, query, query_normalized, is_persisted, query_hash, result_hash, result_number) " +
-                "VALUES ('" + username + "', '" + query.getQuery() + "', '" + query.getQuery() + "', true, '" + query.getQueryHash() + "', '" + query.getResultHash() + "', " + query.getResultNumber() + ")");
+        final PreparedStatement prepareStatement = connection.prepareStatement("INSERT INTO qs_queries (created_by, query, query_normalized, is_persisted, query_hash, result_hash, result_number, created, executed) VALUES (?,?,?,?,?,?,?,?,?)");
+        prepareStatement.setString(1, username);
+        prepareStatement.setString(2, query.getQuery());
+        prepareStatement.setString(3, query.getQuery());
+        prepareStatement.setBoolean(4, query.getIsPersisted());
+        prepareStatement.setString(5, query.getQueryHash());
+        prepareStatement.setString(6, query.getResultHash());
+        prepareStatement.setLong(7, query.getResultNumber());
+        prepareStatement.setTimestamp(8, Timestamp.from(query.getCreated()));
+        prepareStatement.setTimestamp(9, Timestamp.from(query.getExecuted()));
+        log.trace("prepared statement: {}", prepareStatement);
+        prepareStatement.executeUpdate();
         connection.close();
     }
 
+    public static List<Map<String, Object>> listQueryStore(String hostname, String database) throws SQLException {
+        final String jdbc = "jdbc:mariadb://" + hostname + "/" + database;
+        log.trace("connect to database {}", jdbc);
+        final Connection connection = DriverManager.getConnection(jdbc, "root", "mariadb");
+        final Statement statement = connection.createStatement();
+        final ResultSet result = statement.executeQuery("SELECT created_by, query, query_normalized, is_persisted, query_hash, result_hash, result_number, created, executed FROM qs_queries");
+        final List<Map<String, Object>> rows = new LinkedList<>();
+        while (result.next()) {
+            rows.add(new HashMap<>() {{
+                put("created_by", result.getString(1));
+                put("query", result.getString(2));
+                put("query_normalized", result.getString(3));
+                put("is_persisted", result.getBoolean(4));
+                put("query_hash", result.getString(5));
+                put("result_hash", result.getString(6));
+                put("result_number", result.getLong(7));
+                put("created", result.getTimestamp(8));
+                put("executed", result.getTimestamp(9));
+            }});
+        }
+        return rows;
+    }
+
     public static List<Map<String, String>> selectQuery(String hostname, String database, String query, String... columns)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + hostname + "/" + database;
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java b/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java
index 0ee03e69ad4e85d2f54c09488fb5bf94265946d6..72ef54c966d37a7f92566228f9e00cbf6f8643a1 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java
@@ -33,7 +33,7 @@ public class RabbitMqConfig {
 
     public List<ConsumerDto> findAllConsumers() throws IOException {
         log.trace("gateway broker find all consumers");
-        final URI findUri = URI.create("http://broker-service:15672/api/consumers/%2F");
+        final URI findUri = URI.create("http://dbrepo-broker-service:15672/api/consumers/%2F");
         final ResponseEntity<List<ConsumerDto>> response = restTemplate.exchange(findUri, HttpMethod.GET,
                 new HttpEntity<>(null, getHeaders()), new ParameterizedTypeReference<>() {
                 });
@@ -52,7 +52,7 @@ public class RabbitMqConfig {
             }
         }
         for (Map.Entry<String, Integer> consumer : consumers.entrySet()) {
-            log.debug("queue {} has {} consumers", consumer.getKey(), consumer.getValue());
+            log.trace("queue {} has {} consumers", consumer.getKey(), consumer.getValue());
         }
         return response.getBody();
     }
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java
index 6e5062cff9ea8ef90689cb4bbb5873ce789ef58e..f5126e08b48fb31b936fd2e56d4ab8ff7bd3f685 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java
@@ -7,6 +7,8 @@ import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.DatabaseAccessRepository;
 import at.tuwien.repository.jpa.TableRepository;
@@ -49,9 +51,14 @@ public class ExportEndpointUnitTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private QueryService queryService;
 
@@ -240,7 +247,7 @@ public class ExportEndpointUnitTest extends BaseUnitTest {
         }
         when(tableRepository.find(containerId, databaseId, tableId))
                 .thenReturn(Optional.of(TABLE_1));
-        when(queryService.findAll(containerId, databaseId, tableId, timestamp, principal))
+        when(queryService.tableFindAll(containerId, databaseId, tableId, timestamp, principal))
                 .thenReturn(resource);
 
         /* test */
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java
index 7b1e9ade2c5e6b276207d2ebcc714da4b95cd464..8f315d2b404e95c7e0675ef36e13f6d9a88b0485 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java
@@ -10,6 +10,8 @@ import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.ContainerRepository;
 import at.tuwien.repository.jpa.DatabaseAccessRepository;
@@ -52,9 +54,14 @@ public class QueryEndpointUnitTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private DatabaseAccessRepository databaseAccessRepository;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java
index f323836cf21f413ec01d6ae0374c52915e966e64..42782640bde805393dcf28bc3e735c5e9ecd1461 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java
@@ -9,6 +9,8 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.querystore.Query;
 import at.tuwien.repository.jpa.IdentifierRepository;
@@ -51,9 +53,14 @@ public class StoreEndpointUnitTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @Autowired
     private StoreEndpoint storeEndpoint;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java
index 7766c2d041d25fcd9fa6c20be8c2c0f374e74a78..4cf2392ed0a94319043e7738151d0c86123b7cf7 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java
@@ -11,6 +11,8 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.service.AccessService;
 import at.tuwien.service.DatabaseService;
@@ -18,8 +20,10 @@ import at.tuwien.service.TableService;
 import at.tuwien.service.impl.QueryServiceImpl;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -29,6 +33,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.security.Principal;
 import java.time.Instant;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -44,9 +49,14 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private QueryServiceImpl queryService;
 
@@ -65,490 +75,299 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
     @Autowired
     private TableDataEndpoint dataEndpoint;
 
-    @Test
-    public void import_publicAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, null,
-                    null, null);
-        });
-    }
-
-    @Test
-    public void import_publicRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_publicWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_publicWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException,
-            NotAllowedException, TableMalformedException, DatabaseConnectionException, QueryMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void import_publicOwner_succeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException,
-            ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_publicAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                    null, TABLE_1_CSV_DTO, null);
-        });
-    }
-
-    @Test
-    public void insert_publicRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void insert_publicWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void insert_publicWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_publicOwner_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_publicOwnerDataNull_succeeds() throws UserNotFoundException, TableNotFoundException,
-            NotAllowedException, TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException,
-            ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void getAll_publicAnonymous_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                null, null, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicRead_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicWriteOwn_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicWriteAll_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicOwner_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicAnonymousPageNull_fails() {
-        final Long page = null;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousSizeNull_fails() {
-        final Long page = 1L;
-        final Long size = null;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousPageNegative_fails() {
-        final Long page = -1L;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousSizeZero_fails() {
-        final Long page = 0L;
-        final Long size = 0L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousSizeNegative_fails() {
-        final Long page = 0L;
-        final Long size = -1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    /* ################################################################################################### */
-    /* ## PRIVATE DATABASES                                                                             ## */
-    /* ################################################################################################### */
-
-    @Test
-    public void import_privateAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, null, null, null);
+    public static Stream<Arguments> import_fails_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        DATABASE_1,
+                        TABLE_1_ID, TABLE_1, null, null, null),
+                Arguments.arguments("public read", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        DATABASE_1, TABLE_1_ID,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("public write-own", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        DATABASE_1, TABLE_1_ID,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("private anonymous", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        DATABASE_2, TABLE_1_ID, TABLE_1, null, null, null),
+                Arguments.arguments("private read", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("private write-own", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("import_fails_parameters")
+    public <T extends Throwable> void import_fails(String test, Class<T> expectedException, Long containerId,
+                                                   Long databaseId, Database database, Long tableId, Table table,
+                                                   String username, DatabaseAccess access, Principal principal) {
+
+        /* test */
+        assertThrows(expectedException, () -> {
+            generic_import(containerId, databaseId, database, tableId, table, username, access, principal);
         });
     }
 
-    @Test
-    public void import_privateRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL);
+    public static Stream<Arguments> import_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1,
+                        USER_2_USERNAME, DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1,
+                        USER_1_USERNAME, DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("import_succeeds_parameters")
+    public void import_succeeds(String test, Long containerId, Long databaseId, Database database, Long tableId,
+                                Table table, String username, DatabaseAccess access, Principal principal) throws UserNotFoundException, TableNotFoundException, NotAllowedException, TableMalformedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
+
+        /* test */
+        generic_import(containerId, databaseId, database, tableId, table, username, access, principal);
+    }
+
+    public static Stream<Arguments> insert_fails_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        TABLE_1_ID,
+                        DATABASE_1, TABLE_1, USER_2_USERNAME, null, TABLE_1_CSV_DTO, null),
+                Arguments.arguments("public read", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("public write-own", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("private anonymous", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME, null,
+                        TABLE_1_CSV_DTO, null),
+                Arguments.arguments("private read", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("private write-own", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("insert_fails_parameters")
+    public <T extends Throwable> void insert_fails(String test, Class<T> expectedException, Long containerId,
+                                                   Long databaseId, Long tableId, Database database, Table table,
+                                                   String username, DatabaseAccess access, TableCsvDto data,
+                                                   Principal principal) {
+
+        /* test */
+        assertThrows(expectedException, () -> {
+            generic_insert(containerId, databaseId, tableId, database, table, username, access, data, principal);
         });
     }
 
-    @Test
-    public void import_privateWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_privateWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException,
-            NotAllowedException, TableMalformedException, DatabaseConnectionException, QueryMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void import_privateOwner_succeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException,
-            ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_privateAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    null, TABLE_1_CSV_DTO, null);
-        });
-    }
-
-    @Test
-    public void insert_privateRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void insert_privateWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void insert_privateWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_privateOwner_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_privateOwnerDataNull_succeeds() throws UserNotFoundException, TableNotFoundException,
+    public static Stream<Arguments> insert_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL),
+                Arguments.arguments("public owner, data null", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL),
+                Arguments.arguments("private owner, data null", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2
+                        , TABLE_1, USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("insert_succeeds_parameters")
+    public void insert_succeeds(String test, Long containerId, Long databaseId, Long tableId, Database database,
+                                Table table, String username, DatabaseAccess access, TableCsvDto data,
+                                Principal principal) throws UserNotFoundException, TableNotFoundException,
             NotAllowedException, TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException,
             ImageNotSupportedException, ContainerNotFoundException {
 
         /* test */
-        generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void getAll_privateAnonymous_succeeds() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, null,
-                    null, null, null, null, null, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_privateRead_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateWriteOwn_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateWriteAll_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateOwner_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateReadPageNull_fails() {
-        final Long page = null;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_privateReadSizeNull_fails() {
-        final Long page = 1L;
-        final Long size = null;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_privateReadPageNegative_fails() {
-        final Long page = -1L;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
+        generic_insert(containerId, databaseId, tableId, database, table, username, access, data, principal);
+    }
+
+    public static Stream<Arguments> getAll_fails_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous page null", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, null, 1L, null, null),
+                Arguments.arguments("public anonymous size null", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, 1L, null, null, null),
+                Arguments.arguments("public anonymous page negative", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, -1L, 1L, null, null),
+                Arguments.arguments("public anonymous size zero", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, 0L, 0L, null, null),
+                Arguments.arguments("public anonymous size negative", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, 0L, -1L, null, null),
+                Arguments.arguments("private anonymous", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, null, null, null, null,
+                        null, null, null, null),
+                Arguments.arguments("private read, page null", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, null, 1L, null, null),
+                Arguments.arguments("private read, size null", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, 1L, null, null, null),
+                Arguments.arguments("private read, page negative", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, -1L, 1L, null, null),
+                Arguments.arguments("private read, size zero", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, 0L, 0L, null, null),
+                Arguments.arguments("private read, size negative", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, 0L, -1L, null, null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getAll_fails_parameters")
+    public <T extends Throwable> void getAll_fails(String test, Class<T> expectedException, Long containerId,
+                                                   Long databaseId, Long tableId, Database database, Table table,
+                                                   String username, DatabaseAccess access, Principal principal,
+                                                   Instant timestamp, Long page, Long size, SortType sortDirection,
+                                                   String sortColumn) {
+
+        /* test */
+        assertThrows(expectedException, () -> {
+            generic_getAll(containerId, databaseId, tableId, database, table, username, access, principal, timestamp,
+                    page, size, sortDirection, sortColumn);
         });
     }
 
-    @Test
-    public void getAll_privateReadSizeZero_fails() {
-        final Long page = 0L;
-        final Long size = 0L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
+    public static Stream<Arguments> getAll_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null,
+                        null, null, null, null, null),
+                Arguments.arguments("public read", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("public write-own", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private read", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private write-own", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getAll_succeeds_parameters")
+    public void getAll_succeeds(String test, Long containerId, Long databaseId, Long tableId, Database database,
+                                Table table, String username, DatabaseAccess access, Principal principal,
+                                Instant timestamp, Long page, Long size, SortType sortDirection, String sortColumn) throws UserNotFoundException, TableNotFoundException, QueryStoreException, SortException, TableMalformedException, NotAllowedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException {
+
+        /* test */
+        generic_getAll(containerId, databaseId, tableId, database, table, username, access, principal, timestamp,
+                page, size, sortDirection, sortColumn);
+    }
+
+    public static Stream<Arguments> getCount_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null),
+                Arguments.arguments("public read", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("public write-own", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null),
+                Arguments.arguments("private read", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("private write-own", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getAll_succeeds_parameters")
+    public void getCount_succeeds(String test, Long containerId, Long databaseId, Long tableId, Database database,
+                                Table table, String username, DatabaseAccess access, Principal principal,
+                                Instant timestamp) throws UserNotFoundException, TableNotFoundException, QueryStoreException, SortException, TableMalformedException, NotAllowedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException {
+
+        /* test */
+        generic_getCount(containerId, databaseId, tableId, database, table, username, access, principal, timestamp);
     }
 
-    @Test
-    public void getAll_privateReadSizeNegative_fails() {
-        final Long page = 0L;
-        final Long size = -1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
-    }
 
     /* ################################################################################################### */
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
     public void generic_import(Long containerId, Long databaseId, Database database, Long tableId, Table table,
-                               String username, DatabaseAccess access, Principal principal)
-            throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException,
-            TableMalformedException, DatabaseConnectionException, QueryMalformedException, ImageNotSupportedException,
-            ContainerNotFoundException {
-        final ImportDto request = ImportDto.builder()
-                .location("test:csv/csv_01.csv")
-                .build();
+                               String username, DatabaseAccess access, Principal principal) throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException, TableMalformedException, DatabaseConnectionException, QueryMalformedException, ImageNotSupportedException, ContainerNotFoundException {
+        final ImportDto request = ImportDto.builder().location("test:csv/csv_01.csv").build();
 
         /* mock */
-        when(databaseService.find(containerId, databaseId))
-                .thenReturn(database);
-        when(tableService.find(containerId, databaseId, tableId))
-                .thenReturn(table);
-        when(accessService.find(databaseId, username))
-                .thenReturn(access);
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
 
         /* test */
-        final ResponseEntity<?> response = dataEndpoint.importCsv(containerId, databaseId, tableId, request,
-                principal);
+        final ResponseEntity<?> response = dataEndpoint.importCsv(containerId, databaseId, tableId, request, principal);
         assertNotNull(response);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
     public void generic_insert(Long containerId, Long databaseId, Long tableId, Database database, Table table,
-                               String username, DatabaseAccess access, TableCsvDto data, Principal principal)
-            throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException,
-            TableMalformedException, DatabaseConnectionException, ImageNotSupportedException,
-            ContainerNotFoundException {
+                               String username, DatabaseAccess access, TableCsvDto data, Principal principal) throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException, TableMalformedException, DatabaseConnectionException, ImageNotSupportedException, ContainerNotFoundException {
 
         /* mock */
-        when(databaseService.find(containerId, databaseId))
-                .thenReturn(database);
-        when(tableService.find(containerId, databaseId, tableId))
-                .thenReturn(table);
-        when(accessService.find(databaseId, username))
-                .thenReturn(access);
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
 
         /* test */
         final ResponseEntity<?> response = dataEndpoint.insert(containerId, databaseId, tableId, data, principal);
@@ -558,23 +377,17 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
 
     public void generic_getAll(Long containerId, Long databaseId, Long tableId, Database database, Table table,
                                String username, DatabaseAccess access, Principal principal, Instant timestamp,
-                               Long page, Long size, SortType sortDirection, String sortColumn)
-            throws UserNotFoundException, TableMalformedException, NotAllowedException, PaginationException,
-            TableNotFoundException, QueryStoreException, SortException, DatabaseConnectionException,
-            QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
+                               Long page, Long size, SortType sortDirection, String sortColumn) throws UserNotFoundException, TableMalformedException, NotAllowedException, PaginationException, TableNotFoundException, QueryStoreException, SortException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
 
         /* mock */
-        when(databaseService.find(containerId, databaseId))
-                .thenReturn(database);
-        when(tableService.find(containerId, databaseId, tableId))
-                .thenReturn(table);
-        when(accessService.find(databaseId, username))
-                .thenReturn(access);
-        when(queryService.findAll(containerId, databaseId, tableId, timestamp, page, size, principal))
-                .thenReturn(QUERY_1_RESULT_DTO);
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
+        when(queryService.tableFindAll(containerId, databaseId, tableId, timestamp, page, size, principal)).thenReturn(QUERY_1_RESULT_DTO);
 
         /* test */
-        final ResponseEntity<QueryResultDto> response = dataEndpoint.getAll(containerId, databaseId, tableId, principal, timestamp, page, size, sortDirection, sortColumn);
+        final ResponseEntity<QueryResultDto> response = dataEndpoint.getAll(containerId, databaseId, tableId,
+                principal, timestamp, page, size, sortDirection, sortColumn);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         assertEquals(QUERY_1_RESULT_ID, response.getBody().getId());
@@ -582,4 +395,21 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
         assertEquals(QUERY_1_RESULT_RESULT, response.getBody().getResult());
     }
 
+    public void generic_getCount(Long containerId, Long databaseId, Long tableId, Database database, Table table,
+                               String username, DatabaseAccess access, Principal principal, Instant timestamp) throws UserNotFoundException, TableMalformedException, NotAllowedException, PaginationException, TableNotFoundException, QueryStoreException, SortException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
+
+        /* mock */
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
+        when(queryService.tableCount(containerId, databaseId, tableId, timestamp, principal)).thenReturn(QUERY_1_RESULT_NUMBER);
+
+        /* test */
+        final ResponseEntity<Long> response = dataEndpoint.getCount(containerId, databaseId, tableId,
+                principal, timestamp);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertEquals(QUERY_1_RESULT_NUMBER, response.getBody());
+    }
+
 }
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java
index a06089955e982a0ae2862c283330e95b001e07d1..9a649b2e39f4a8978ebdf5b490f8aa70eab8c11d 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java
@@ -9,6 +9,8 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.DatabaseAccessRepository;
 import at.tuwien.service.DatabaseService;
@@ -48,9 +50,14 @@ public class TableHistoryEndpointUnitTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private QueryService queryService;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
index 379a1ea8d90083ec46fdaf8f20a9f70efc309db3..5cf4aadd98085ace3f9bfe569c5d9e0a063c9103 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
@@ -11,6 +11,8 @@ import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.service.AccessService;
 import at.tuwien.service.DatabaseService;
@@ -50,9 +52,14 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private QueryService queryService;
 
@@ -314,7 +321,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicAnonymous_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, null, null, null);
@@ -325,7 +332,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicAnonymous2_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, null, null, null);
@@ -336,7 +343,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicRead_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_READ_ACCESS);
@@ -347,7 +354,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicWriteOwn_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_WRITE_OWN_ACCESS);
@@ -358,7 +365,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicWriteAll_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_WRITE_ALL_ACCESS);
@@ -369,7 +376,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicOwner_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_1_WRITE_ALL_ACCESS);
@@ -380,7 +387,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateResearcher_succeeds() throws UserNotFoundException, QueryStoreException,
             NotAllowedException, DatabaseConnectionException, TableMalformedException, QueryMalformedException,
             ColumnParseException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException,
-            PaginationException, ViewNotFoundException {
+            PaginationException, ViewNotFoundException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_4_ID, DATABASE_2, USER_1_USERNAME, USER_1_PRINCIPAL, null);
@@ -563,7 +570,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateAnonymous_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, null, null, null);
@@ -573,7 +580,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateRead_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_2_READ_ACCESS);
@@ -583,7 +590,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateWriteOwn_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_2_WRITE_OWN_ACCESS);
@@ -593,7 +600,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateWriteAll_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_2_WRITE_ALL_ACCESS);
@@ -603,7 +610,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateOwner_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_2_WRITE_ALL_ACCESS);
@@ -735,7 +742,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
                                 Principal principal, DatabaseAccess access) throws DatabaseNotFoundException,
             UserNotFoundException, NotAllowedException, ViewNotFoundException, DatabaseConnectionException,
             QueryMalformedException, QueryStoreException, TableMalformedException, ColumnParseException,
-            ImageNotSupportedException, ContainerNotFoundException, PaginationException {
+            ImageNotSupportedException, ContainerNotFoundException, PaginationException, ViewMalformedException {
         final ExecuteStatementDto statement = ExecuteStatementDto.builder()
                 .statement(VIEW_1_QUERY)
                 .build();
@@ -756,7 +763,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
         }
         when(viewService.findById(databaseId, viewId, principal))
                 .thenReturn(VIEW_1);
-        when(queryService.execute(containerId, databaseId, statement, principal, page, size, null, null))
+        when(queryService.viewFindAll(containerId, databaseId, VIEW_1, page, size, principal))
                 .thenReturn(QUERY_1_RESULT_DTO);
 
         /* test */
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java
deleted file mode 100644
index 1ddaac142af69e4b7dfab255160e6cd6a1f87618..0000000000000000000000000000000000000000
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package at.tuwien.listener;
-
-import at.tuwien.BaseUnitTest;
-import at.tuwien.api.amqp.ConsumerDto;
-import at.tuwien.config.*;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.BrokerServiceGateway;
-import at.tuwien.listener.impl.RabbitMqListenerImpl;
-import at.tuwien.repository.jpa.*;
-import com.rabbitmq.client.BuiltinExchangeType;
-import com.rabbitmq.client.Channel;
-import lombok.extern.log4j.Log4j2;
-import org.junit.Rule;
-import org.junit.jupiter.api.*;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.rules.Timeout;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import java.io.IOException;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.when;
-
-
-@Log4j2
-@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class RabbitMqListenerIntegrationTest extends BaseUnitTest {
-
-    @MockBean
-    private ReadyConfig readyConfig;
-
-    @MockBean
-    private IndexConfig indexConfig;
-
-    @MockBean
-    private BrokerServiceGateway brokerServiceGateway;
-
-    @Autowired
-    private Channel channel;
-
-    @Autowired
-    private ImageRepository imageRepository;
-
-    @Autowired
-    private ContainerRepository containerRepository;
-
-    @Autowired
-    private DatabaseRepository databaseRepository;
-
-    @Autowired
-    private TableRepository tableRepository;
-
-    @Autowired
-    private RabbitMqListenerImpl rabbitMqListener;
-
-    @Autowired
-    private TableColumnRepository tableColumnRepository;
-
-    @Autowired
-    private H2Utils h2Utils;
-
-    @Autowired
-    private RabbitMqConfig rabbitMqConfig;
-
-    @Autowired
-    private AmqpConfig amqpConfig;
-
-    @Rule
-    public Timeout globalTimeout = Timeout.seconds(60);
-
-    @BeforeAll
-    public static void beforeAll() throws InterruptedException {
-        afterAll();
-        DockerConfig.createAllNetworks();
-        DockerConfig.createContainer(null, CONTAINER_BROKER, 15672, CONTAINER_BROKER_ENV);
-        DockerConfig.startContainer(CONTAINER_BROKER);
-    }
-
-    @AfterAll
-    public static void afterAll() {
-        DockerConfig.removeAllContainers();
-        DockerConfig.removeAllNetworks();
-    }
-
-    @BeforeEach
-    public void beforeEach() {
-        /* metadata database */
-        h2Utils.runScript("schema.sql");
-        imageRepository.save(IMAGE_1);
-        containerRepository.save(CONTAINER_1);
-        DATABASE_1.setTables(List.of());
-        databaseRepository.save(DATABASE_1);
-        DATABASE_1.setTables(List.of(TABLE_1, TABLE_2, TABLE_3));
-        tableRepository.save(TABLE_1_NOCOLS);
-        tableRepository.save(TABLE_2_NOCOLS);
-        tableRepository.save(TABLE_3_NOCOLS);
-    }
-
-    @Test
-    public void updateConsumers_succeeds() throws AmqpException, IOException, InterruptedException {
-
-        /* mock */
-        channel.exchangeDeclare(DATABASE_1_EXCHANGE, BuiltinExchangeType.FANOUT);
-        channel.queueDeclare(TABLE_1_QUEUE_NAME, true, false, false, null);
-        channel.queueBind(TABLE_1_QUEUE_NAME, DATABASE_1_EXCHANGE, TABLE_1_ROUTING_KEY);
-        channel.queueDeclare(TABLE_2_QUEUE_NAME, true, false, false, null);
-        channel.queueBind(TABLE_2_QUEUE_NAME, DATABASE_1_EXCHANGE, TABLE_2_ROUTING_KEY);
-        channel.queueDeclare(TABLE_3_QUEUE_NAME, true, false, false, null);
-        channel.queueBind(TABLE_3_QUEUE_NAME, DATABASE_1_EXCHANGE, TABLE_3_ROUTING_KEY);
-        when(brokerServiceGateway.findAllConsumers())
-                .thenReturn(List.of());
-
-        /* pre-condition */
-        assertEquals(0, rabbitMqConfig.findAllConsumers().size());
-        assertEquals(2, amqpConfig.getAmqpConsumers());
-
-        /* test */
-        rabbitMqListener.updateConsumers();
-        Thread.sleep(10 * 1000);
-        final List<ConsumerDto> response = rabbitMqConfig.findAllConsumers();
-        assertEquals(6, response.size());
-        assertEquals(2, (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_1_QUEUE_NAME)).count());
-        assertEquals(2, (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_2_QUEUE_NAME)).count());
-        assertEquals(2, (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_3_QUEUE_NAME)).count());
-    }
-
-}
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java
index d8d59487f6392de975b5fc300306202c604da683..bd9644c6f5f834ccaea2249225afde6e27ec392a 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java
@@ -7,6 +7,8 @@ import at.tuwien.config.DockerConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.View;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.elastic.ViewIdxRepository;
 import at.tuwien.repository.jpa.*;
@@ -16,6 +18,7 @@ import lombok.extern.log4j.Log4j2;
 import org.junit.Rule;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.rules.Timeout;
@@ -45,9 +48,14 @@ public class ViewIdxRepositoryIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private UserRepository userRepository;
 
@@ -87,6 +95,12 @@ public class ViewIdxRepositoryIntegrationTest extends BaseUnitTest {
         DockerConfig.removeAllNetworks();
     }
 
+    @BeforeEach
+    public void beforeEach() {
+        DATABASE_1.setTables(List.of(TABLE_1, TABLE_2, TABLE_3, TABLE_7));
+        DATABASE_1.setViews(List.of(VIEW_1));
+    }
+
     @Test
     public void save_succeeds() throws UserNotFoundException, DatabaseConnectionException, ViewMalformedException,
             QueryMalformedException, DatabaseNotFoundException {
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java
index 4000a1559936d4cdfc754f3707f21cc9f439c85e..eddcffdc8e9e12dc638394e60ef7849286f684c0 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java
@@ -5,6 +5,8 @@ import at.tuwien.config.H2Utils;
 import at.tuwien.config.IndexConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.View;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.*;
 import com.rabbitmq.client.Channel;
@@ -36,9 +38,14 @@ public class ViewRepositoryIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private IndexConfig indexConfig;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
index 29d3e0f2d8ebf9c89d4c6ff2c234f7a0048dd473..ba53952bab69043e081cd65e2cd7c7d8d1a9c62f 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
@@ -5,6 +5,8 @@ import at.tuwien.config.IndexConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.container.Container;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.*;
 import com.rabbitmq.client.Channel;
@@ -35,9 +37,14 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @Autowired
     private ImageRepository imageRepository;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java
index df11edcd6e4c9e0d93da5f1f7ade3da0dd44360a..817208e3e13c4306ea5154cdd2ea39db186ccca7 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java
@@ -10,6 +10,8 @@ import at.tuwien.config.IndexConfig;
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.querystore.Query;
 import at.tuwien.repository.jpa.*;
@@ -56,9 +58,14 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private DatabaseRepository databaseRepository;
 
@@ -79,12 +86,10 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
     private final static String BIND_ZOO = new File("./src/test/resources/zoo").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d";
 
     @BeforeAll
-    public static void beforeAll() throws InterruptedException {
+    public static void beforeAll() {
         afterAll();
         /* create network */
         DockerConfig.createAllNetworks();
-        DockerConfig.createContainer(null, CONTAINER_BROKER, 15672, CONTAINER_BROKER_ENV);
-        DockerConfig.startContainer(CONTAINER_BROKER);
     }
 
     @AfterAll
@@ -133,7 +138,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        final QueryResultDto result = queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(),
+        final QueryResultDto result = queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(),
                 null, null, USER_1_PRINCIPAL);
         assertEquals(3, result.getResult().size());
         assertEquals(BigInteger.valueOf(1L), result.getResult().get(0).get(COLUMN_1_1_INTERNAL_NAME));
@@ -169,7 +174,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -187,24 +192,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
 
         /* test */
         assertThrows(TableNotFoundException.class, () -> {
-            queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void selectAll_noDatabase_fails() throws InterruptedException {
-        final Long page = 0L;
-        final Long size = 10L;
-
-        /* mock */
-        DockerConfig.createContainer(BIND_WEATHER, CONTAINER_1, CONTAINER_1_ENV);
-        DockerConfig.startContainer(CONTAINER_1);
-        when(databaseRepository.findByContainerIdAndDatabaseId(CONTAINER_1_ID, DATABASE_1_ID))
-                .thenReturn(Optional.empty());
-
-        /* test */
-        assertThrows(DatabaseNotFoundException.class, () -> {
-            queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
+            queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
         });
     }
 
@@ -282,7 +270,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -300,8 +288,8 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -434,7 +422,9 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .query("SELECT `location`, `lat`, `lng` FROM `weather_location` WHERE `location` = \"Vienna\"")
                 .queryHash(QUERY_1_QUERY_HASH)
                 .resultHash(null)
+                .resultNumber(0L)
                 .created(QUERY_1_CREATED)
+                .executed(QUERY_1_EXECUTION)
                 .createdBy(USER_1_USERNAME)
                 .isPersisted(true)
                 .build();
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
index 0fe3b659ef0ec5d9e7ceee04e6e7344a021f5f64..acfe952c722a1a36fd6fe50338cf49335e4c6699 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
@@ -2,12 +2,12 @@ package at.tuwien.service;
 
 import at.tuwien.BaseUnitTest;
 import at.tuwien.amqp.RabbitMqConsumer;
+import at.tuwien.api.amqp.ConsumerDto;
 import at.tuwien.api.database.table.TableCsvDto;
-import at.tuwien.config.AmqpConfig;
-import at.tuwien.config.DockerConfig;
-import at.tuwien.config.IndexConfig;
-import at.tuwien.config.ReadyConfig;
+import at.tuwien.config.*;
 import at.tuwien.exception.AmqpException;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.DatabaseRepository;
 import at.tuwien.repository.jpa.TableRepository;
@@ -27,9 +27,12 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -53,15 +56,23 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    @MockBean
+    private RabbitMqConsumer rabbitMqConsumer;
+
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
     @MockBean
-    private RabbitMqConsumer rabbitMqConsumer;
+    private BrokerServiceGateway brokerServiceGateway;
 
     @Autowired
     private AmqpConfig amqpConfig;
 
+    @Autowired
+    private RabbitMqConfig rabbitMqConfig;
+
     @Autowired
     private Channel channel;
 
@@ -79,7 +90,7 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
         DockerConfig.createAllNetworks();
         DockerConfig.createContainer(BIND, CONTAINER_1, CONTAINER_1_ENV);
         DockerConfig.startContainer(CONTAINER_1);
-        DockerConfig.createContainer(null, CONTAINER_BROKER, CONTAINER_BROKER_ENV);
+        DockerConfig.createContainer(null, CONTAINER_BROKER, 15672, CONTAINER_BROKER_ENV);
         DockerConfig.startContainer(CONTAINER_BROKER);
     }
 
@@ -187,4 +198,18 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
         channel.basicPublish(DATABASE_1_EXCHANGE, TABLE_1_ROUTING_KEY, basicProperties, objectMapper.writeValueAsBytes(TABLE_1_CSV_DTO));
     }
 
+    @Test
+    public void restore_succeeds() throws AmqpException, IOException, InterruptedException {
+
+        /* mock */
+        when(tableRepository.findAll())
+                .thenReturn(List.of(TABLE_1));
+
+        /* test */
+        messageQueueService.restore();
+        Thread.sleep(5 * 1000);
+        final List<ConsumerDto> response = rabbitMqConfig.findAllConsumers();
+        assertEquals(amqpConfig.getAmqpConsumers(), (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_1_QUEUE_NAME)).count());
+    }
+
 }
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java
index 17e9cb979bc2eaecb2480ba558bbafb540b219ef..eb694845ebf851da701cce168c4f36a7178b1ae2 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java
@@ -9,6 +9,8 @@ import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.exception.*;
 import at.tuwien.entities.database.Database;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.querystore.Query;
 import at.tuwien.repository.jpa.*;
@@ -29,6 +31,7 @@ import java.sql.SQLException;
 import java.util.List;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
+import java.util.Map;
 import java.util.Optional;
 
 import static java.time.temporal.ChronoUnit.HOURS;
@@ -51,9 +54,14 @@ public class StoreServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private TableRepository tableRepository;
 
@@ -93,9 +101,11 @@ public class StoreServiceIntegrationTest extends BaseUnitTest {
     }
 
     @BeforeEach
-    public void beforeEach() throws InterruptedException, SQLException {
+    public void beforeEach() throws InterruptedException {
         afterEach();
+        /* create networks */
         DockerConfig.createAllNetworks();
+        /* create containers */
         DockerConfig.createContainer(BIND, CONTAINER_1, CONTAINER_1_ENV);
         DockerConfig.startContainer(CONTAINER_1);
         /* metadata database */
@@ -136,6 +146,7 @@ public class StoreServiceIntegrationTest extends BaseUnitTest {
         when(databaseRepository.findByContainerIdAndDatabaseId(CONTAINER_1_ID, DATABASE_1_ID))
                 .thenReturn(Optional.of(DATABASE_1));
         MariaDbConfig.insertQueryStore(CONTAINER_1_INTERNALNAME, DATABASE_1_INTERNALNAME, QUERY_1, USER_1_USERNAME);
+        MariaDbConfig.insertQueryStore(CONTAINER_1_INTERNALNAME, DATABASE_1_INTERNALNAME, QUERY_2, USER_1_USERNAME);
 
         /* test */
         final List<Query> queries = storeService.findAll(CONTAINER_1_ID, DATABASE_1_ID, true, USER_1_PRINCIPAL);
@@ -366,7 +377,7 @@ public class StoreServiceIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    public void findOne_notFound_fails() {
+    public void findOne_notFound_fails() throws SQLException {
         final Principal principal = new BasicUserPrincipal(USER_1_USERNAME);
 
         /* mock */
@@ -375,8 +386,23 @@ public class StoreServiceIntegrationTest extends BaseUnitTest {
 
         /* test */
         assertThrows(QueryNotFoundException.class, () -> {
-            storeService.findOne(CONTAINER_1_ID, DATABASE_1_ID, QUERY_2_ID, principal);
+            storeService.findOne(CONTAINER_1_ID, DATABASE_1_ID, 9999L, principal);
         });
     }
 
+    @Test
+    public void deleteStaleQueries_succeeds() throws QueryStoreException, ImageNotSupportedException, SQLException {
+
+        /* mock */
+        MariaDbConfig.insertQueryStore(CONTAINER_1_INTERNALNAME, DATABASE_1_INTERNALNAME, QUERY_1, USER_1_USERNAME);
+        MariaDbConfig.insertQueryStore(CONTAINER_1_INTERNALNAME, DATABASE_1_INTERNALNAME, QUERY_2, USER_1_USERNAME);
+        when(databaseRepository.findAll())
+                .thenReturn(List.of(DATABASE_1));
+
+        /* test */
+        storeService.deleteStaleQueries();
+        final List<Map<String, Object>> response = MariaDbConfig.listQueryStore(CONTAINER_1_INTERNALNAME, DATABASE_1_INTERNALNAME);
+        assertEquals(1, response.size());
+    }
+
 }
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
index 14b294520f0cf4d6ba88f1d45f87b36eb47744d4..58f28e951351115b091d8a8240a6bf75e993638f 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
@@ -8,6 +8,8 @@ import at.tuwien.config.IndexConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.ContainerRepository;
 import at.tuwien.repository.jpa.DatabaseRepository;
@@ -50,9 +52,14 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private TableRepository tableRepository;
 
@@ -74,9 +81,13 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
     final static String BIND = new File("./src/test/resources/weather").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d";
 
     @BeforeAll
-    public static void beforeAll() {
+    public static void beforeAll() throws InterruptedException {
         afterAll();
+        /* create networks */
         DockerConfig.createAllNetworks();
+        /* start containers */
+        DockerConfig.createContainer(BIND, CONTAINER_1, CONTAINER_1_ENV);
+        DockerConfig.startContainer(CONTAINER_1);
     }
 
     @AfterAll
@@ -86,22 +97,20 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
     }
 
     @BeforeEach
-    public void beforeEach() throws InterruptedException {
-        afterEach();
-        DockerConfig.createContainer(BIND, CONTAINER_1, CONTAINER_1_ENV);
-        DockerConfig.startContainer(CONTAINER_1);
-        h2Utils.runScript("schema.sql");
+    public void beforeEach() {
         /* metadata db */
+        h2Utils.runScript("schema.sql");
         imageRepository.save(IMAGE_1);
         containerRepository.save(CONTAINER_1);
+        tableRepository.save(TABLE_1_NOCOLS);
+        tableRepository.save(TABLE_2_NOCOLS);
+        tableRepository.save(TABLE_3_NOCOLS);
+        tableRepository.save(TABLE_7_NOCOLS);
+        DATABASE_1.setTables(List.of());
+        DATABASE_1.setViews(List.of());
         databaseRepository.save(DATABASE_1);
     }
 
-    @AfterEach
-    public void afterEach() {
-        DockerConfig.removeAllContainers();
-    }
-
     @Test
     public void findHistory_anonymous_succeeds() throws UserNotFoundException, TableNotFoundException,
             QueryStoreException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException {
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
index 69ce154d9fa9b65765110ba1a27d9468903f3df7..4a523c0a2325d56636b7519368b06a0027e39f25 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
@@ -5,6 +5,8 @@ import at.tuwien.config.IndexConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
+import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.jpa.*;
 import com.rabbitmq.client.Channel;
@@ -39,9 +41,14 @@ public class TableServiceUnitTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexInitializer;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @Autowired
     private TableService tableService;
 
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
index d827ec5bfa4e153f6c22f27e0bb77ee7702ab329..c2cf5c3008a214fa63ec571c527e9248ec7c256a 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
@@ -9,13 +9,10 @@ import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.View;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.elastic.ViewIdxRepository;
 import at.tuwien.repository.jpa.*;
-import com.github.dockerjava.api.command.CreateContainerResponse;
-import com.github.dockerjava.api.exception.NotModifiedException;
-import com.github.dockerjava.api.model.Bind;
-import com.github.dockerjava.api.model.Network;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.AfterAll;
@@ -30,12 +27,10 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.File;
 import java.sql.SQLException;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
-import static at.tuwien.config.DockerConfig.*;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
@@ -60,9 +55,14 @@ public class ViewServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private ViewIdxRepository viewIdxRepository;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private DatabaseRepository databaseRepository;
 
diff --git a/fda-query-service/rest-service/src/test/resources/application.properties b/fda-query-service/rest-service/src/test/resources/application.properties
index aac636db158551adcc6c17b6dc229f68a96bdd69..4eea490a9199d7e0155b1f33cf3500a5e1f2863f 100644
--- a/fda-query-service/rest-service/src/test/resources/application.properties
+++ b/fda-query-service/rest-service/src/test/resources/application.properties
@@ -19,12 +19,14 @@ spring.jpa.show-sql=false
 
 # additional logging
 logging.level.root=error
-logging.level.at.tuwien.=info
+logging.level.at.tuwien.=trace
 
 # broker service
-spring.rabbitmq.host=broker-service
+spring.rabbitmq.host=dbrepo-broker-service
 spring.rabbitmq.username=guest
 spring.rabbitmq.password=guest
 
 # search service
-fda.elastic.endpoint=search-mock-service:9200
\ No newline at end of file
+fda.consumers=2
+fda.gateway.endpoint: http://localhost:15672
+fda.elastic.endpoint=dbrepo-search-service:9200
\ No newline at end of file
diff --git a/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv b/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv
deleted file mode 100644
index 9bfb33891d9c10db7cd04ba1cf8d32ddc1dcde96..0000000000000000000000000000000000000000
--- a/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv
+++ /dev/null
@@ -1,3 +0,0 @@
-1,2008-12-01,Albury,13.4,0.6
-2,2008-12-02,Albury,7.4,0
-3,2008-12-03,Albury,12.9,0
\ No newline at end of file
diff --git a/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java b/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java
index 8a5bc1c3f10f354b0cf1bd850ed208419bb147e3..e8f0b9c364dd7c2166cc605c71572c8efc305e6f 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java
@@ -5,5 +5,6 @@ import at.tuwien.api.amqp.ConsumerDto;
 import java.util.List;
 
 public interface BrokerServiceGateway {
+
     List<ConsumerDto> findAllConsumers();
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java b/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java
index 16afe426ad48f3bc7733fd86f1140e886319261f..4629fbe4ccb3c567001e215a25d0c1182d78c472 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java
@@ -7,7 +7,9 @@ import at.tuwien.gateway.BrokerServiceGateway;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.binary.Base64;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
 import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.core.env.Environment;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
@@ -17,6 +19,7 @@ import org.springframework.web.client.RestTemplate;
 
 import java.net.URI;
 import java.nio.charset.Charset;
+import java.util.Arrays;
 import java.util.List;
 
 @Slf4j
@@ -26,20 +29,30 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway {
     private final AmqpConfig amqpConfig;
     private final RestTemplate restTemplate;
     private final GatewayConfig gatewayConfig;
+    private final Environment environment;
 
     private final static String VIRTUAL_SERVER = "%2F";
 
     @Autowired
-    public BrokerServiceGatewayImpl(AmqpConfig amqpConfig, RestTemplate restTemplate, GatewayConfig gatewayConfig) {
+    public BrokerServiceGatewayImpl(AmqpConfig amqpConfig, RestTemplate restTemplate, GatewayConfig gatewayConfig,
+                                    Environment environment) {
         this.amqpConfig = amqpConfig;
         this.restTemplate = restTemplate;
         this.gatewayConfig = gatewayConfig;
+        this.environment = environment;
     }
 
     @Override
     public List<ConsumerDto> findAllConsumers() {
+        final StringBuilder urlBuilder = new StringBuilder(gatewayConfig.getGatewayEndpoint())
+                .append("/api");
+        if (Arrays.stream(environment.getActiveProfiles()).noneMatch(p -> p.equals("junit"))) {
+            urlBuilder.append("/broker");
+        }
+        urlBuilder.append("/consumers/")
+                .append(VIRTUAL_SERVER);
         log.trace("gateway broker find all consumers, virtual server={}", VIRTUAL_SERVER);
-        final URI findUri = URI.create(gatewayConfig.getGatewayEndpoint() + "/api/broker/consumers/" + VIRTUAL_SERVER);
+        final URI findUri = URI.create(urlBuilder.toString());
         final ResponseEntity<List<ConsumerDto>> response = restTemplate.exchange(findUri, HttpMethod.GET,
                 new HttpEntity<>(null, getHeaders()), new ParameterizedTypeReference<>() {
                 });
diff --git a/fda-query-service/services/src/main/java/at/tuwien/listener/DatabaseListener.java b/fda-query-service/services/src/main/java/at/tuwien/listener/DatabaseListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..10adef889b3ef66eb2f7c37b1a806d2d7f1ed9bb
--- /dev/null
+++ b/fda-query-service/services/src/main/java/at/tuwien/listener/DatabaseListener.java
@@ -0,0 +1,17 @@
+package at.tuwien.listener;
+
+import at.tuwien.exception.ImageNotSupportedException;
+import at.tuwien.exception.QueryStoreException;
+import org.springframework.scheduling.annotation.Scheduled;
+
+public interface DatabaseListener {
+
+    /**
+     * Deletes stale queries that have not been persisted within 24 hours.
+     *
+     * @throws QueryStoreException        The query store raised some exception.
+     * @throws ImageNotSupportedException The image is not supported by the service.
+     */
+    @Scheduled
+    void deleteStaleQueries() throws QueryStoreException, ImageNotSupportedException;
+}
diff --git a/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java b/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java
index ebdc5a473931d742f7199067a78468947ee4c597..4b8b1872272eb7375d408b1029fbf18c0a9be93d 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java
@@ -1,4 +1,15 @@
 package at.tuwien.listener;
 
+import at.tuwien.exception.AmqpException;
+import org.springframework.scheduling.annotation.Scheduled;
+
 public interface MessageQueueListener {
+
+    /**
+     * Restores the consumers up to the configured limit.
+     *
+     * @throws AmqpException The consumer could not be created.
+     */
+    @Scheduled(fixedDelay = 5000)
+    void updateConsumers() throws AmqpException;
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/listener/impl/MariadbListenerImpl.java b/fda-query-service/services/src/main/java/at/tuwien/listener/impl/MariadbListenerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..412b1f6ee5d6b7351678d8cb3154ed26dd2e4475
--- /dev/null
+++ b/fda-query-service/services/src/main/java/at/tuwien/listener/impl/MariadbListenerImpl.java
@@ -0,0 +1,29 @@
+package at.tuwien.listener.impl;
+
+import at.tuwien.exception.ImageNotSupportedException;
+import at.tuwien.exception.QueryStoreException;
+import at.tuwien.listener.DatabaseListener;
+import at.tuwien.service.StoreService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class MariadbListenerImpl implements DatabaseListener {
+
+    private final StoreService storeService;
+
+    @Autowired
+    public MariadbListenerImpl(StoreService storeService) {
+        this.storeService = storeService;
+    }
+
+    @Override
+    @Scheduled(cron = "0 0 2 * * *" /* at 2am, non-standard CRON syntax */)
+    @Transactional(readOnly = true)
+    public void deleteStaleQueries() throws QueryStoreException, ImageNotSupportedException {
+        storeService.deleteStaleQueries();
+    }
+
+}
diff --git a/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java b/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java
index 1423461dd1d7d5a13a0b031e4ca49039283155a8..6e3670a70a74c12db7f2844968ad10272c682859 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java
@@ -1,57 +1,28 @@
 package at.tuwien.listener.impl;
 
-import at.tuwien.api.amqp.ConsumerDto;
-import at.tuwien.config.AmqpConfig;
-import at.tuwien.entities.database.table.Table;
 import at.tuwien.exception.AmqpException;
-import at.tuwien.gateway.BrokerServiceGateway;
 import at.tuwien.listener.MessageQueueListener;
 import at.tuwien.service.MessageQueueService;
-import at.tuwien.service.TableService;
 import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.io.IOException;
-import java.util.List;
-
 @Log4j2
 @Service
 public class RabbitMqListenerImpl implements MessageQueueListener {
 
-    private final AmqpConfig amqpConfig;
-    private final TableService tableService;
     private final MessageQueueService messageQueueService;
-    private final BrokerServiceGateway brokerServiceGateway;
 
-    @Autowired
-    public RabbitMqListenerImpl(AmqpConfig amqpConfig, TableService tableService,
-                                MessageQueueService messageQueueService, BrokerServiceGateway brokerServiceGateway) {
-        this.amqpConfig = amqpConfig;
-        this.tableService = tableService;
+    public RabbitMqListenerImpl(MessageQueueService messageQueueService) {
         this.messageQueueService = messageQueueService;
-        this.brokerServiceGateway = brokerServiceGateway;
     }
 
+    @Override
     @Scheduled(fixedDelay = 5000)
     @Transactional(readOnly = true)
     public void updateConsumers() throws AmqpException {
-        final List<Table> tables = tableService.findAll();
-        final List<ConsumerDto> consumers = brokerServiceGateway.findAllConsumers();
-        for (Table table : tables) {
-            final long consumerCount = consumers.stream().filter(c -> c.getQueue().getName().equals(table.getQueueName())).count();
-            if (consumerCount >= amqpConfig.getAmqpConsumers()) {
-                log.trace("listener table with name {} already has {} consumers (max. {})", table.getName(),
-                        consumerCount, amqpConfig.getAmqpConsumers());
-                continue;
-            }
-            log.debug("table with id {} has {} consumers, but needs {} in total", table.getId(), consumerCount,
-                    amqpConfig.getAmqpConsumers());
-            messageQueueService.createConsumer(table.getQueueName(), table.getDatabase().getContainer().getId(),
-                    table.getDatabase().getId(), table.getId());
-        }
+        messageQueueService.restore();
     }
 
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c49211efb805355ea851c87dcbf340474f2d64f
--- /dev/null
+++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
@@ -0,0 +1,15 @@
+package at.tuwien.mapper;
+
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.entities.container.Container;
+import org.mapstruct.Mapper;
+
+@Mapper(componentModel = "spring")
+public interface ContainerMapper {
+
+    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ContainerMapper.class);
+
+    /* keep */
+    ContainerDto containerToContainerDto(Container data);
+
+}
diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java
index c3ccb209f52eec7b406fc461e189e194298d80fb..d85aaa7553b825ee12715bc4e8bb2a1176e865e1 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java
@@ -6,6 +6,7 @@ import at.tuwien.api.database.table.TableCsvDto;
 import at.tuwien.api.database.table.TableCsvUpdateDto;
 import at.tuwien.api.database.table.TableHistoryDto;
 import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.View;
 import at.tuwien.entities.database.table.columns.TableColumnType;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.QueryStoreException;
@@ -542,16 +543,19 @@ public interface QueryMapper {
         statement.append(";");
         try {
             final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
-            log.trace("mapped update query {} to prepared statement {}", statement, pstmt);
             for (Map.Entry<String, Object> entry : data.getData().entrySet()) {
                 if (entry.getValue() == null) {
                     log.trace("entry is null, preparing null");
                     pstmt.setNull(i++, Types.NULL);
+                } else if (entry.getValue().equals(true) || entry.getValue().equals(false)) {
+                    log.trace("entry is not null, preparing boolean");
+                    pstmt.setBoolean(i++, Boolean.parseBoolean(String.valueOf(entry.getValue())));
                 } else {
                     log.trace("entry is not null, preparing string");
                     pstmt.setString(i++, String.valueOf(entry.getValue()));
                 }
             }
+            log.trace("mapped update query {} to prepared statement {}", statement, pstmt);
             return pstmt;
         } catch (SQLException e) {
             log.error("failed to prepare statement {}, reason: {}", statement, e.getMessage());
@@ -570,8 +574,8 @@ public interface QueryMapper {
         return selection.toString();
     }
 
-    default PreparedStatement tableToRawCountAllQuery(Connection connection, Table table, Instant timestamp)
-            throws ImageNotSupportedException, QueryMalformedException {
+    default String tableToRawCountAllQuery(Table table, Instant timestamp)
+            throws ImageNotSupportedException {
         log.trace("mapping table to raw count query, table={}, timestamp={}", table, timestamp);
         /* check image */
         if (!table.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) {
@@ -582,25 +586,35 @@ public interface QueryMapper {
             log.trace("timestamp is null, setting it to now");
             timestamp = Instant.now();
         }
+        return columnsToRawCountAllQuery(table.getInternalName(), timestamp);
+    }
+
+    default String viewToRawCountAllQuery(View view)
+            throws ImageNotSupportedException {
+        log.trace("mapping table to raw count query, view={}", view);
+        /* check image */
+        if (!view.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) {
+            log.error("Currently only MariaDB is supported");
+            throw new ImageNotSupportedException("Image not supported.");
+        }
+        return columnsToRawCountAllQuery(view.getInternalName(), null);
+    }
+
+    default String columnsToRawCountAllQuery(String tableName, Instant timestamp) {
         final StringBuilder statement = new StringBuilder("SELECT COUNT(*) FROM `")
-                .append(nameToInternalName(table.getName()))
-                .append("` FOR SYSTEM_TIME AS OF TIMESTAMP '")
-                .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
-                .append("';");
-        try {
-            final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
-            log.trace("mapped raw count query {} to prepared statement {}", statement, pstmt);
-            return pstmt;
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement", e);
+                .append(nameToInternalName(tableName))
+                .append("`");
+        if(timestamp != null) {
+            statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '")
+                    .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
+                    .append("'");
         }
+        statement.append(";");
+        return statement.toString();
     }
 
-    default PreparedStatement queryToRawTimestampedQuery(Connection connection, String query, Database database,
-                                                         Instant timestamp, Boolean selection, Long page, Long size)
-            throws ImageNotSupportedException,
-            QueryMalformedException {
+    default String queryToRawTimestampedQuery(String query, Database database, Instant timestamp, Boolean selection, Long page, Long size)
+            throws ImageNotSupportedException, QueryMalformedException {
         log.trace("mapping query to timestamped query, query={}, database={}, timestamp={}, selection={}, page={}, size={}",
                 query, database, timestamp, selection, page, size);
         /* param check */
@@ -670,17 +684,11 @@ public interface QueryMapper {
                     + LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC"))
                     + "' ");
         }
-        try {
-            log.debug("mapped timestamped query: {}", statement);
-            return connection.prepareStatement(statement.toString());
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement", e);
-        }
+        return statement.toString();
     }
 
-    default PreparedStatement tableToRawFindAllQuery(Connection connection, Table table, Instant timestamp, Long size, Long page)
-            throws ImageNotSupportedException, QueryMalformedException {
+    default String tableToRawFindAllQuery(Table table, Instant timestamp, Long size, Long page)
+            throws ImageNotSupportedException {
         log.trace("mapping table to find all query, table={}, timestamp={}, size={}, page={}",
                 table, timestamp, size, page);
         /* param check */
@@ -694,18 +702,35 @@ public interface QueryMapper {
         } else {
             log.trace("timestamp provided {}", timestamp);
         }
+        return columnsToRawFindAllQuery(table.getInternalName(), table.getColumns(), timestamp, size, page);
+    }
+
+    default String viewToRawFindAllQuery(View view, Long size, Long page)
+            throws ImageNotSupportedException {
+        log.trace("mapping view to find all query, view={}, size={}, page={}", view, size, page);
+        /* param check */
+        if (!view.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) {
+            log.error("Currently only MariaDB is supported");
+            throw new ImageNotSupportedException("Currently only MariaDB is supported");
+        }
+        return columnsToRawFindAllQuery(view.getInternalName(), view.getColumns(), null, size, page);
+    }
+
+    private String columnsToRawFindAllQuery(String tableName, List<TableColumn> columns, Instant timestamp, Long size, Long page) {
         final int[] idx = new int[]{0};
         final StringBuilder statement = new StringBuilder("SELECT ");
-        table.getColumns()
-                .forEach(column -> statement.append(idx[0]++ > 0 ? "," : "")
+        columns.forEach(column -> statement.append(idx[0]++ > 0 ? "," : "")
                         .append("`")
                         .append(column.getInternalName())
                         .append("`"));
         statement.append(" FROM `")
-                .append(nameToInternalName(table.getName()))
-                .append("` FOR SYSTEM_TIME AS OF TIMESTAMP '")
-                .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
-                .append("'");
+                .append(nameToInternalName(tableName))
+                .append("`");
+        if (timestamp != null) {
+            statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '")
+                    .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
+                    .append("'");
+        }
         if (size != null && page != null) {
             log.trace("pagination size/limit of {}", size);
             statement.append(" LIMIT ")
@@ -714,34 +739,8 @@ public interface QueryMapper {
             statement.append(" OFFSET ")
                     .append(page * size)
                     .append(";");
-
         }
-        try {
-            final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
-            log.trace("mapped timestamped query {} to prepared statement {}", statement, pstmt);
-            return pstmt;
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}m reason: {}", statement, e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement", e);
-        }
-    }
-
-    default QueryResultDto queryTableToQueryResultDto(ResultSet result, Table table) throws DateTimeException,
-            SQLException {
-        final List<Map<String, Object>> queryResult = new LinkedList<>();
-        while (result.next()) {
-            /* map the result set to the columns through the stored metadata in the metadata database */
-            int[] idx = new int[]{1};
-            final Map<String, Object> map = new HashMap<>();
-            for (int i = 0; i < table.getColumns().size(); i++) {
-                map.put(table.getColumns().get(i).getInternalName(), dataColumnToObject(result.getObject(idx[0]++), table.getColumns().get(i)));
-            }
-            queryResult.add(map);
-        }
-        log.trace("mapped result {} to query result {}", result, queryResult);
-        return QueryResultDto.builder()
-                .result(queryResult)
-                .build();
+        return statement.toString();
     }
 
     @Transactional(readOnly = true)
diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java
index c594988657b4924af6581570e63cce73add71d20..9302a0ca0aac8a652ef8833657abff90c02e880a 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java
@@ -62,6 +62,17 @@ public interface StoreMapper {
         }
     }
 
+    default PreparedStatement queryStoreRawDeleteStaleQueries(Connection connection) throws QueryStoreException {
+        final String statement = "DELETE FROM `qs_queries` WHERE `is_persisted` = false AND ABS(DATEDIFF(`created`, NOW())) >= 1";
+        try {
+            log.trace("mapped select all query '{}' to prepared statement", statement);
+            return connection.prepareStatement(statement);
+        } catch (SQLException e) {
+            log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage());
+            throw new QueryStoreException("Failed to prepare statement", e);
+        }
+    }
+
     default PreparedStatement queryStoreRawSelectOneQuery(Connection connection, Long queryId) throws QueryStoreException {
         final String statement = "SELECT `id`, `created`, `created_by`, `query`, `query_hash`, `result_hash`, `result_number`, `is_persisted` FROM `qs_queries` q WHERE q.`id` = ?";
         try {
diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java
index 35bcfffb455bb099e0fc067b5801dbc8eb5d1d48..04234f583fe89abaa5556f60495fadf3287f60f9 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java
@@ -26,7 +26,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.regex.Pattern;
 
-@Mapper(componentModel = "spring")
+@Mapper(componentModel = "spring", uses = {ContainerMapper.class})
 public interface ViewMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ViewMapper.class);
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/fda-query-service/services/src/main/java/at/tuwien/service/DatabaseService.java
index 2e27dc0b4024fe4d03687eb77bde0df89dc3c374..982871215c63bb4953fb3b68012e83c8667ce305 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/DatabaseService.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/DatabaseService.java
@@ -2,11 +2,14 @@ package at.tuwien.service;
 
 import at.tuwien.entities.database.Database;
 import at.tuwien.exception.DatabaseNotFoundException;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
 
 public interface DatabaseService {
 
     /**
-     * Finds a database by given id in the remote database service.
+     * Finds a database by given id in the metadata database.
      *
      * @param containerId The container id.
      * @param databaseId  The database id.
@@ -14,4 +17,11 @@ public interface DatabaseService {
      * @throws DatabaseNotFoundException The database was not found.
      */
     Database find(Long containerId, Long databaseId) throws DatabaseNotFoundException;
+
+    /**
+     * Finds all databases in the metadata database.
+     *
+     * @return List of databases.
+     */
+    List<Database> findAll();
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/MessageQueueService.java b/fda-query-service/services/src/main/java/at/tuwien/service/MessageQueueService.java
index 4bd2fd9bebdb5fa3fe2f67fcc3d75af4bba75b87..ed4342ddd40cfda326958f0b23fab34b30fc8583 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/MessageQueueService.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/MessageQueueService.java
@@ -15,4 +15,11 @@ public interface MessageQueueService {
      * @throws AmqpException The consumer could not be created.
      */
     void createConsumer(String queueName, Long containerId, Long databaseId, Long tableId) throws AmqpException;
+
+    /**
+     * Restores missing consumers at the Broker Service.
+     *
+     * @throws AmqpException The consumer could not be created.
+     */
+    void restore() throws AmqpException;
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
index 119d887f3cce8a770db719496c51099d9227d3f3..01924d9fb29b8729987e5621bd6d4a4006cfa04d 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
@@ -5,16 +5,20 @@ import at.tuwien.SortType;
 import at.tuwien.api.database.query.ExecuteStatementDto;
 import at.tuwien.api.database.query.ImportDto;
 import at.tuwien.api.database.query.QueryResultDto;
-import at.tuwien.api.database.query.QueryTypeDto;
 import at.tuwien.api.database.table.TableCsvDeleteDto;
 import at.tuwien.api.database.table.TableCsvDto;
 import at.tuwien.api.database.table.TableCsvUpdateDto;
+import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.View;
+import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.exception.*;
 import at.tuwien.querystore.Query;
+import net.sf.jsqlparser.JSQLParserException;
 import org.springframework.stereotype.Service;
 
 import java.security.Principal;
 import java.time.Instant;
+import java.util.List;
 
 @Service
 public interface QueryService {
@@ -71,6 +75,26 @@ public interface QueryService {
             throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ColumnParseException,
             DatabaseConnectionException, TableMalformedException, QueryStoreException, UserNotFoundException;
 
+    /**
+     * Re-Executes the count-statement of an arbitrary query on the database container. We allow the user to only view
+     * the data, therefore the default "mariadb" user is allowed read-only access "SELECT".
+     *
+     * @param containerId   The container id.
+     * @param databaseId    The database id.
+     * @param query         The query.
+     * @param principal     The user principal.
+     * @return The result.
+     * @throws QueryStoreException        The query store is not reachable.
+     * @throws QueryMalformedException    The query is malformed.
+     * @throws DatabaseNotFoundException  The database was not found in the metdata database.
+     * @throws ImageNotSupportedException The image is not supported.
+     * @throws TableMalformedException    The table is malformed.
+     * @throws ColumnParseException       The column mapping/parsing failed.
+     */
+    Long reExecuteCount(Long containerId, Long databaseId, Query query, Principal principal)
+            throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ColumnParseException,
+            TableMalformedException, QueryStoreException;
+
     /**
      * Select all data known in the database-table id tuple at a given time and return a page of specific size, using
      * Instant to better abstract time concept (JDK 8) from SQL. We use the "mariadb" user for this.
@@ -90,8 +114,8 @@ public interface QueryService {
      * @throws TableMalformedException    The table is malformed.
      * @throws QueryMalformedException    The query is malformed.
      */
-    QueryResultDto findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp,
-                           Long page, Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+    QueryResultDto tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp,
+                                Long page, Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
             ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException,
             ContainerNotFoundException, QueryMalformedException, UserNotFoundException;
 
@@ -115,11 +139,34 @@ public interface QueryService {
      * @throws FileStorageException        The file could not be exported.
      * @throws QueryMalformedException     The query is malformed.
      */
-    ExportResource findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+    ExportResource tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
             throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
             DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException,
             FileStorageException, QueryMalformedException, UserNotFoundException;
 
+    /**
+     * Select all data known in the view id tuple and return a page of specific size.
+     * We use the "mariadb" user for this.
+     *
+     * @param containerId The container-database id pair.
+     * @param databaseId  The container-database id pair.
+     * @param view        The view.
+     * @param page        The page.
+     * @param size        The page size.
+     * @param principal   The user principal.
+     * @return The select all data result
+     * @throws ViewNotFoundException     The view was not found in the metadata database.
+     * @throws DatabaseNotFoundException  The database was not found in the metdata database.
+     * @throws ImageNotSupportedException The image is not supported.
+     * @throws ContainerNotFoundException The container was not found in the metadata database.
+     * @throws ViewMalformedException    The table is malformed.
+     * @throws QueryMalformedException    The query is malformed.
+     */
+    QueryResultDto viewFindAll(Long containerId, Long databaseId, View view,
+                               Long page, Long size, Principal principal) throws ViewNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, DatabaseConnectionException, ViewMalformedException, PaginationException,
+            ContainerNotFoundException, QueryMalformedException, UserNotFoundException, TableMalformedException;
+
     /**
      * Finds one query by container-database-query triple.
      *
@@ -156,10 +203,27 @@ public interface QueryService {
      * @throws TableMalformedException    The table columns are messed up what we got from the metadata database.
      * @throws ImageNotSupportedException The image is not supported.
      */
-    Long count(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+    Long tableCount(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
             throws ContainerNotFoundException, DatabaseNotFoundException, TableNotFoundException,
             TableMalformedException, ImageNotSupportedException, DatabaseConnectionException, QueryMalformedException, QueryStoreException, UserNotFoundException;
 
+    /**
+     * Count the total tuples for a given table id within a container-database id tuple at a given time.
+     *
+     * @param containerId The container id.
+     * @param databaseId  The database id.
+     * @param view        The view.
+     * @param principal   The user principal.
+     * @return The number of records, if successful
+     * @throws ContainerNotFoundException The container was not found in the metadata database.
+     * @throws DatabaseNotFoundException  The database was not found in the remote database.
+     * @throws TableMalformedException    The view columns are messed up what we got from the metadata database.
+     * @throws ImageNotSupportedException The image is not supported.
+     */
+    Long viewCount(Long containerId, Long databaseId, View view, Principal principal)
+            throws ContainerNotFoundException, DatabaseNotFoundException,
+            TableMalformedException, ImageNotSupportedException, DatabaseConnectionException, QueryMalformedException, QueryStoreException, UserNotFoundException;
+
     /**
      * @param containerId The container id.
      * @param databaseId  The database id.
@@ -232,4 +296,14 @@ public interface QueryService {
      */
     void insert(Long containerId, Long databaseId, Long tableId, ImportDto data, Principal principal) throws ImageNotSupportedException,
             TableMalformedException, DatabaseNotFoundException, TableNotFoundException, ContainerNotFoundException, DatabaseConnectionException, QueryMalformedException, UserNotFoundException;
+
+    /**
+     * Parses the stored columns from a given query.
+     *
+     * @param query    The query.
+     * @param database The database that contains the list of tables with list of columns.
+     * @return List of columns in the order they are referenced in the query.
+     * @throws JSQLParserException The columns could not be extracted from the query.
+     */
+    List<TableColumn> parseColumns(String query, Database database) throws JSQLParserException;
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/StoreService.java b/fda-query-service/services/src/main/java/at/tuwien/service/StoreService.java
index f2e206abb0ac473227a1b7cb6300ddf782faa1ba..baebb84c4a04ad3abf8dadef00706c9ae7bc9e20 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/StoreService.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/StoreService.java
@@ -74,11 +74,18 @@ public interface StoreService {
      * @param principal   The user principal.
      * @return The stored query on success.
      * @throws DatabaseNotFoundException   The database id was not found in the metadata database
-     * @throws ImageNotSupportedException  The image is not supported
+     * @throws ImageNotSupportedException  The image is not supported.
      * @throws DatabaseConnectionException The database connection to the remote container failed.
-     * @throws QueryStoreException         The query store raised some error
+     * @throws QueryStoreException         The query store raised some error.
      */
     Query persist(Long containerId, Long databaseId, Long queryId, Principal principal) throws DatabaseNotFoundException,
             ImageNotSupportedException, DatabaseConnectionException, QueryStoreException, UserNotFoundException;
 
+    /**
+     * Deletes the stale queries that have not been persisted within 24 hozrs.
+     *
+     * @throws ImageNotSupportedException The image is not supported.
+     * @throws QueryStoreException        The query store raised some error.
+     */
+    void deleteStaleQueries() throws ImageNotSupportedException, QueryStoreException;
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
index c5c6a30008b9b28435f45cf3fbd1216989d148f6..79910ab9bf4aaec93670d22d6678eaac437ef59c 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
 import java.util.Optional;
 
 @Log4j2
@@ -32,4 +33,10 @@ public class DatabaseServiceImpl implements DatabaseService {
         }
         return database.get();
     }
+
+    @Override
+    @Transactional(readOnly = true)
+    public List<Database> findAll() {
+        return databaseRepository.findAll();
+    }
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java
index a1d0c2ca114ef3244a75a0143f1416c9e3d4c0f8..a1dc0a91b336c9f1f8485ec7a167a6477487291e 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java
@@ -39,7 +39,6 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.time.DateTimeException;
 import java.time.Instant;
 import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
@@ -102,63 +101,149 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             columns = parseColumns(query.getQuery(), database);
         } catch (JSQLParserException e) {
             log.error("Failed to map/parse columns: {}", e.getMessage());
-            throw new ColumnParseException(e.getMessage(), e);
+            throw new ColumnParseException("Failed to map/parse columns: " + e.getMessage(), e);
         }
-        final QueryResultDto dto;
+        final String statement = queryMapper.queryToRawTimestampedQuery(query.getQuery(), database, query.getCreated(), true, page, size);
+        final QueryResultDto dto = executeNonPersistent(containerId, databaseId, statement, columns);
+
+        dto.setId(query.getId());
+        dto.setResultNumber(query.getResultNumber());
+        return dto;
+    }
+
+    @Override
+    @Transactional(readOnly = true)
+    public Long reExecuteCount(Long containerId, Long databaseId, Query query, Principal principal)
+            throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ColumnParseException,
+            TableMalformedException, QueryStoreException {
+        /* find */
+        final Database database = databaseService.find(containerId, databaseId);
+        if (!database.getContainer().getImage().getRepository().equals("mariadb")) {
+            throw new ImageNotSupportedException("Currently only MariaDB is supported");
+        }
+        /* run query */
+        try {
+            parseColumns(query.getQuery(), database);
+        } catch (JSQLParserException e) {
+            log.error("Failed to map/parse columns: {}", e.getMessage());
+            throw new ColumnParseException("Failed to map/parse columns: " + e.getMessage(), e);
+        }
+        final String statement = queryMapper.queryToRawTimestampedQuery(query.getQuery(), database, query.getCreated(), false, null, null);
+        return executeCountNonPersistent(containerId, databaseId, statement);
+    }
+
+    private PreparedStatement prepareStatement(Connection connection, String statement) throws QueryMalformedException {
+        try {
+            final PreparedStatement pstmt = connection.prepareStatement(statement);
+            log.trace("mapped timestamped query {} to prepared statement {}", statement, pstmt);
+            return pstmt;
+        } catch (SQLException e) {
+            log.error("Failed to prepare statement {}m reason: {}", statement, e.getMessage());
+            throw new QueryMalformedException("Failed to prepare statement", e);
+        }
+    }
+
+    private QueryResultDto executeNonPersistent(Long containerId, Long databaseId, String statement, List<TableColumn> columns)
+            throws QueryMalformedException, DatabaseNotFoundException, TableMalformedException {
+        /* find */
+        final Database database = databaseService.find(containerId, databaseId);
+        final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
+        /* run query */
+        final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
+                database.getContainer(), database, root);
         try {
             final Connection connection = dataSource.getConnection();
-            final PreparedStatement preparedStatement = queryMapper.queryToRawTimestampedQuery(connection, query.getQuery(),
-                    database, query.getCreated(), true, page, size);
+            final PreparedStatement preparedStatement = prepareStatement(connection, statement);
             final ResultSet resultSet = preparedStatement.executeQuery();
-            dto = queryMapper.resultListToQueryResultDto(columns, resultSet);
+            return queryMapper.resultListToQueryResultDto(columns, resultSet);
         } catch (SQLException e) {
             log.error("Failed to execute and map time-versioned query: {}", e.getMessage());
-            throw new TableMalformedException("Failed to execute and map time-versioned query", e);
+            throw new TableMalformedException("Failed to execute and map time-versioned query: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        dto.setId(query.getId());
-        dto.setResultNumber(query.getResultNumber());
-        return dto;
     }
 
-    @Override
-    @Transactional(readOnly = true)
-    public QueryResultDto findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Long page,
-                                  Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
-            ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException,
-            ContainerNotFoundException, QueryMalformedException, UserNotFoundException {
+    private Long executeCountNonPersistent(Long containerId, Long databaseId, String statement)
+            throws QueryMalformedException, TableMalformedException, DatabaseNotFoundException, QueryStoreException {
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
-        final Table table = tableService.find(containerId, databaseId, tableId);
         final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
         /* run query */
         final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
                 database.getContainer(), database, root);
-        final QueryResultDto result;
         try {
             final Connection connection = dataSource.getConnection();
-            final PreparedStatement preparedStatement = queryMapper.tableToRawFindAllQuery(connection, table, timestamp, size, page);
+            final PreparedStatement preparedStatement = prepareStatement(connection, statement);
             final ResultSet resultSet = preparedStatement.executeQuery();
-            result = queryMapper.queryTableToQueryResultDto(resultSet, table);
-        } catch (DateTimeException e) {
-            log.error("Failed to parse date from the one stored in the metadata database: {}", e.getMessage());
-            throw new TableMalformedException("Could not parse date from format", e);
+            return queryMapper.resultSetToNumber(resultSet);
         } catch (SQLException e) {
             log.error("Failed to map object: {}", e.getMessage());
-            throw new TableMalformedException("Failed to map object", e);
+            throw new TableMalformedException("Failed to map object: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        return result;
     }
 
     @Override
     @Transactional(readOnly = true)
-    public ExportResource findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
-            throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
-            DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException,
-            FileStorageException, QueryMalformedException, UserNotFoundException {
+    public QueryResultDto tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Long page,
+                                       Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, TableMalformedException, QueryMalformedException {
+        /* find */
+        final Table table = tableService.find(containerId, databaseId, tableId);
+        /* run query */
+        String statement = queryMapper.tableToRawFindAllQuery(table, timestamp, size, page);
+        return executeNonPersistent(containerId, databaseId, statement, table.getColumns());
+    }
+
+    @Override
+    @Transactional(readOnly = true)
+    public QueryResultDto viewFindAll(Long containerId, Long databaseId, View view,
+                                      Long page, Long size, Principal principal) throws DatabaseNotFoundException,
+            ImageNotSupportedException, QueryMalformedException, TableMalformedException {
+        /* find */
+        /* run query */
+        String statement = queryMapper.viewToRawFindAllQuery(view, size, page);
+        return executeNonPersistent(containerId, databaseId, statement, view.getColumns());
+    }
+
+    @Override
+    @Transactional
+    public Long tableCount(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+            throws DatabaseNotFoundException, TableNotFoundException, ImageNotSupportedException,
+            QueryMalformedException, QueryStoreException, TableMalformedException {
+        /* find */
+        final Table table = tableService.find(containerId, databaseId, tableId);
+        final String statement = queryMapper.tableToRawCountAllQuery(table, timestamp);
+        return executeCountNonPersistent(containerId, databaseId, statement);
+    }
+
+    @Override
+    @Transactional
+    public Long viewCount(Long containerId, Long databaseId, View view, Principal principal)
+            throws DatabaseNotFoundException, ImageNotSupportedException,
+            QueryMalformedException, QueryStoreException, TableMalformedException {
+        /* find */
+        final String statement = queryMapper.viewToRawCountAllQuery(view);
+        return executeCountNonPersistent(containerId, databaseId, statement);
+    }
+
+    @Transactional(readOnly = true)
+    public QueryResultDto findAllView(Long containerId, Long databaseId, Long viewId, Instant timestamp, Long page,
+                                      Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, TableMalformedException, QueryMalformedException {
+        /* find */
+        final Table table = tableService.find(containerId, databaseId, viewId);
+        /* run query */
+        String statement = queryMapper.tableToRawFindAllQuery(table, timestamp, size, page);
+        return executeNonPersistent(containerId, databaseId, statement, table.getColumns());
+    }
+
+    @Override
+    @Transactional(readOnly = true)
+    public ExportResource tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+            throws TableNotFoundException, DatabaseNotFoundException, FileStorageException, QueryMalformedException {
         final String filename = RandomStringUtils.randomAlphabetic(40) + ".csv";
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
@@ -178,7 +263,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             FileUtils.forceDelete(file);
         } catch (IOException | SQLException e) {
             log.error("Failed to execute query and/or export file: {}", e.getMessage());
-            throw new FileStorageException("Failed to execute query and/or export file", e);
+            throw new FileStorageException("Failed to execute query and/or export file: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
@@ -227,36 +312,11 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
                 .build();
     }
 
-    @Override
-    @Transactional
-    public Long count(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
-            throws DatabaseNotFoundException, TableNotFoundException, ImageNotSupportedException,
-            QueryMalformedException, QueryStoreException, TableMalformedException {
-        /* find */
-        final Database database = databaseService.find(containerId, databaseId);
-        final Table table = tableService.find(containerId, databaseId, tableId);
-        final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
-        /* run query */
-        final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
-                database.getContainer(), database, root);
-        try {
-            final Connection connection = dataSource.getConnection();
-            final PreparedStatement preparedStatement = queryMapper.tableToRawCountAllQuery(connection, table, timestamp);
-            final ResultSet resultSet = preparedStatement.executeQuery();
-            return queryMapper.resultSetToNumber(resultSet);
-        } catch (SQLException e) {
-            log.error("Failed to count raw tuples: {}", e.getMessage());
-            throw new TableMalformedException("Failed to count raw tuples", e);
-        } finally {
-            dataSource.close();
-        }
-    }
-
     @Override
     @Transactional
     public void update(Long containerId, Long databaseId, Long tableId, TableCsvUpdateDto data, Principal principal)
             throws ImageNotSupportedException, TableMalformedException, DatabaseNotFoundException,
-            TableNotFoundException, QueryMalformedException, UserNotFoundException {
+            TableNotFoundException, QueryMalformedException {
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
         final Table table = tableService.find(containerId, databaseId, tableId);
@@ -271,7 +331,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             preparedStatement.executeUpdate();
         } catch (SQLException e) {
             log.error("Failed to update tuples: {}", e.getMessage());
-            throw new TableMalformedException("Failed to update tuples", e);
+            throw new TableMalformedException("Failed to update tuples: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
@@ -288,10 +348,6 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
         final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
         log.trace("parsed insert data {}", data);
         /* run query */
-        if (data.getData().size() == 0) {
-            log.error("Failed to parse data, the provided map {} is empty", data.getData());
-            throw new TableMalformedException("Failed to parse data");
-        }
         final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
                 database.getContainer(), database, root);
         /* prepare the statement */
@@ -301,14 +357,14 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             preparedStatement.executeUpdate();
         } catch (DateTimeParseException e) {
             log.error("Failed to parse date: {}", e.getMessage());
-            throw new TableMalformedException("Failed to parse date", e);
+            throw new TableMalformedException("Failed to parse date: " + e.getMessage(), e);
         } catch (NumberFormatException e) {
             log.error("Failed to parse number: {}", e.getMessage());
-            throw new TableMalformedException("Failed to parse number", e);
+            throw new TableMalformedException("Failed to parse number: " + e.getMessage(), e);
         } catch (Exception e) {
             log.error("Database failed to accept tuple: {}", e.getMessage());
             log.throwing(e);
-            throw new TableMalformedException("Database failed to accept tuple " + e.getMessage(), e);
+            throw new TableMalformedException("Database failed to accept tuple: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
@@ -334,7 +390,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             preparedStatement.executeUpdate();
         } catch (SQLException e) {
             log.error("Failed to delete tuples: {}", e.getMessage());
-            throw new TableMalformedException("Failed to delete tuples", e);
+            throw new TableMalformedException("Failed to delete tuples: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
@@ -399,7 +455,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
      * @throws JSQLParserException The columns could not be extracted from the query.
      */
     @Transactional(readOnly = true)
-    protected List<TableColumn> parseColumns(String query, Database database) throws JSQLParserException {
+    public List<TableColumn> parseColumns(String query, Database database) throws JSQLParserException {
         final List<TableColumn> columns = new ArrayList<>();
         final CCJSqlParserManager parserRealSql = new CCJSqlParserManager();
         final Statement statement = parserRealSql.parse(new StringReader(query));
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java
index 00f16ff96f763f335a24177d1c66cfd4185f3438..89bcb5425ec77f72cf971366b3bd70ec2e80c7dd 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java
@@ -1,19 +1,22 @@
 package at.tuwien.service.impl;
 
 import at.tuwien.amqp.RabbitMqConsumer;
+import at.tuwien.api.amqp.ConsumerDto;
 import at.tuwien.config.AmqpConfig;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
 import at.tuwien.service.MessageQueueService;
 import at.tuwien.service.QueryService;
+import at.tuwien.service.TableService;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.rabbitmq.client.*;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.io.IOException;
+import java.util.List;
 
 @Log4j2
 @Service
@@ -23,14 +26,19 @@ public class RabbitMqServiceImpl implements MessageQueueService {
     private final AmqpConfig amqpConfig;
     private final ObjectMapper objectMapper;
     private final QueryService queryService;
+    private final TableService tableService;
+    private final BrokerServiceGateway brokerServiceGateway;
 
     @Autowired
     public RabbitMqServiceImpl(Channel channel, AmqpConfig amqpConfig, ObjectMapper objectMapper,
-                               QueryService queryService) {
+                               QueryService queryService, TableService tableService,
+                               BrokerServiceGateway brokerServiceGateway) {
         this.channel = channel;
         this.amqpConfig = amqpConfig;
         this.objectMapper = objectMapper;
         this.queryService = queryService;
+        this.tableService = tableService;
+        this.brokerServiceGateway = brokerServiceGateway;
     }
 
     @Override
@@ -54,4 +62,25 @@ public class RabbitMqServiceImpl implements MessageQueueService {
         }
     }
 
+    @Override
+    public void restore() throws AmqpException {
+        final List<Table> tables = tableService.findAll();
+        final List<ConsumerDto> consumers = brokerServiceGateway.findAllConsumers();
+        for (Table table : tables) {
+            final long consumerCount = consumers.stream().filter(c -> c.getQueue().getName().equals(table.getQueueName())).count();
+            if (consumerCount >= amqpConfig.getAmqpConsumers()) {
+                log.trace("listener table with name {} already has {} consumers (max. {})", table.getName(),
+                        consumerCount, amqpConfig.getAmqpConsumers());
+                continue;
+            }
+            log.debug("table with id {} has {} consumers, but needs {} in total", table.getId(), consumerCount,
+                    amqpConfig.getAmqpConsumers());
+            for (long i = consumerCount; i < amqpConfig.getAmqpConsumers(); i++) {
+                createConsumer(table.getQueueName(), table.getDatabase().getContainer().getId(),
+                        table.getDatabase().getId(), table.getId());
+                log.trace("creating consumer #{}", i);
+            }
+        }
+    }
+
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/StoreServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/StoreServiceImpl.java
index 52dba2e3368ea79eaa13b6b4026bcfcf1904ab61..b03514297f2fab2544257505a51d1272d73dfabe 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/StoreServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/StoreServiceImpl.java
@@ -181,6 +181,34 @@ public class StoreServiceImpl extends HibernateConnector implements StoreService
         return out;
     }
 
+    @Override
+    public void deleteStaleQueries() throws ImageNotSupportedException, QueryStoreException {
+        /* find */
+        final List<Database> databases = databaseService.findAll();
+        for (Database database : databases) {
+            if (!database.getContainer().getImage().getRepository().equals("mariadb")) {
+                log.error("Currently only MariaDB is supported");
+                throw new ImageNotSupportedException("Currently only MariaDB is supported");
+            }
+            final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
+            /* run query */
+            final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
+                    database.getContainer(), database, root);
+            /* delete stale queries older than 24hrs */
+            try {
+                final Connection connection = dataSource.getConnection();
+                final PreparedStatement preparedStatement = storeMapper.queryStoreRawDeleteStaleQueries(connection);
+                final int affected = preparedStatement.executeUpdate();
+                log.debug("delete stale queries affected {} rows", affected);
+            } catch (SQLException e) {
+                log.error("Failed to delete stale queries in database with id {}, reason: {}", database.getId(), e.getMessage());
+                throw new QueryStoreException("Failed to delete stale queries in database with id " + database.getId() + ": " + e.getMessage());
+            } finally {
+                dataSource.close();
+            }
+        }
+    }
+
     protected List<Query> resultSetToQueryList(ResultSet resultSet) throws SQLException {
         final List<Query> queries = new LinkedList<>();
         while (resultSet.next()) {
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
index 830cc6d216c6ded0d7ba54cc1a2eec61203549e5..4a8e6b8408642cfefe968c1c4fc341fc6de5469b 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
@@ -3,6 +3,7 @@ package at.tuwien.service.impl;
 import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.View;
+import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.DatabaseMapper;
@@ -10,10 +11,12 @@ import at.tuwien.mapper.ViewMapper;
 import at.tuwien.repository.elastic.ViewIdxRepository;
 import at.tuwien.repository.jpa.ViewRepository;
 import at.tuwien.service.DatabaseService;
+import at.tuwien.service.QueryService;
 import at.tuwien.service.UserService;
 import at.tuwien.service.ViewService;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
+import net.sf.jsqlparser.JSQLParserException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -35,17 +38,19 @@ public class ViewServiceImpl extends HibernateConnector implements ViewService {
     private final ViewRepository viewRepository;
     private final DatabaseService databaseService;
     private final ViewIdxRepository viewIdxRepository;
+    private final QueryService queryService;
 
     @Autowired
     public ViewServiceImpl(ViewMapper viewMapper, UserService userService, DatabaseMapper databaseMapper,
                            ViewRepository viewRepository, DatabaseService databaseService,
-                           ViewIdxRepository viewIdxRepository) {
+                           ViewIdxRepository viewIdxRepository, QueryService queryService) {
         this.viewMapper = viewMapper;
         this.userService = userService;
         this.databaseMapper = databaseMapper;
         this.viewRepository = viewRepository;
         this.databaseService = databaseService;
         this.viewIdxRepository = viewIdxRepository;
+        this.queryService = queryService;
     }
 
     @Override
@@ -118,6 +123,13 @@ public class ViewServiceImpl extends HibernateConnector implements ViewService {
         /* create view */
         final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
                 database.getContainer(), database, root);
+        final List<TableColumn> columns;
+        try {
+            columns = queryService.parseColumns(data.getQuery(), database);
+        } catch (JSQLParserException e) {
+            log.error("Failed to map/parse columns: {}", e.getMessage());
+            throw new QueryMalformedException(e.getMessage(), e);
+        }
         try {
             final Connection connection = dataSource.getConnection();
             final PreparedStatement createViewStatement = viewMapper.viewCreateDtoToRawCreateViewQuery(connection, data);
@@ -139,6 +151,7 @@ public class ViewServiceImpl extends HibernateConnector implements ViewService {
                 .query(data.getQuery())
                 .isInitialView(false)
                 .isPublic(data.getIsPublic())
+                .columns(columns)
                 .build();
         final View view = viewRepository.save(entity);
         log.info("Created view with id {}", view.getId());
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index ff9d2c1e77d97ce40c7192c37caed20457eab013..d971603dd8dd5f1e3c387b75759ca34359923590 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -83,9 +83,9 @@ public abstract class BaseUnitTest {
 
     public final static String DATABASE_NET = "fda-userdb";
 
-    public final static String BROKER_NAME = "fda-broker-service";
-    public final static String BROKER_IP = "172.29.0.2";
-    public final static String BROKER_HOSTNAME = "broker-service";
+    public final static String BROKER_NAME = "dbrepo-broker-service";
+    public final static String BROKER_IP = "172.31.0.2";
+    public final static String BROKER_HOSTNAME = "dbrepo-broker-service";
     public final static Integer BROKER_MANAGEMENT_PORT = 15672;
     public final static String BROKER_IMAGE = "rabbitmq";
     public final static String BROKER_TAG = "3-management-alpine";
@@ -146,24 +146,24 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_1_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
     public final static String CONTAINER_1_NAME = "u01";
-    public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01";
-    public final static String CONTAINER_1_IP = "172.28.0.5";
+    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
+    public final static String CONTAINER_1_IP = "172.30.0.5";
     public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS);
 
     public final static Long CONTAINER_2_ID = 2L;
     public final static String CONTAINER_2_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_1;
     public final static String CONTAINER_2_NAME = "u02";
-    public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02";
-    public final static String CONTAINER_2_IP = "172.28.0.6";
+    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02";
+    public final static String CONTAINER_2_IP = "172.30.0.6";
     public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS);
 
     public final static Long CONTAINER_3_ID = 3L;
     public final static String CONTAINER_3_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_1;
     public final static String CONTAINER_3_NAME = "u03";
-    public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03";
-    public final static String CONTAINER_3_IP = "172.28.0.7";
+    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03";
+    public final static String CONTAINER_3_IP = "172.30.0.7";
     public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS);
 
     public final static Long DATABASE_1_ID = 1L;
@@ -739,7 +739,7 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_NGINX_NET = "fda-public";
     public final static String CONTAINER_NGINX_NAME = "file-service";
     public final static String CONTAINER_NGINX_INTERNALNAME = "fda-test-file-service";
-    public final static String CONTAINER_NGINX_IP = "172.29.0.3";
+    public final static String CONTAINER_NGINX_IP = "172.31.0.3";
     public final static Instant CONTAINER_NGINX_CREATED = Instant.now().minus(3, HOURS);
 
     public final static Long CONCEPT_1_ID = 1L;
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java b/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java
index 6cf55041bae2691730fb6c5131673c568471cc03..26d1b50051997b362f19029252437e06aea44e63 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java
@@ -21,7 +21,7 @@ public class GatewayConfig {
     @Bean("brokerRestTemplate")
     public RestTemplate brokerRestTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://broker-service:15672"));
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://dbrepo-broker-service:15672"));
         restTemplate.getInterceptors()
                 .add(new BasicAuthenticationInterceptor(brokerUsername, brokerPassword));
         return restTemplate;
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java
index 300e882c68bf1fd1dcbee8ab12312598030b83ba..1b5a0ecb183d79aa34a3aa66aafcd24aed43a49f 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java
@@ -67,14 +67,14 @@ public class MessageQueueServiceIntegrationTest extends BaseUnitTest {
                 .withName("fda-userdb")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
+                                .withSubnet("172.30.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         dockerClient.createNetworkCmd()
                 .withName("fda-public")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
+                                .withSubnet("172.31.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         /* create amqp */
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
index 059284210924f98846d57f109e174a55aad2f745..49fc8fef9ea21eedeb34c2cdf011f96f340a05be 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
@@ -98,14 +98,14 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
                 .withName("fda-userdb")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
+                                .withSubnet("172.30.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         dockerClient.createNetworkCmd()
                 .withName("fda-public")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
+                                .withSubnet("172.31.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         /* create container */
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java b/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
index 6caf0d930eb80c443a319292d5f749981002668d..dfc90d2ea25ae4920fd2edd74a26660209190554 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
@@ -34,7 +34,7 @@ public class AmqpUtils {
 
     public void createExchange(String exchange) {
         exchange = exchange.replace("/", "%2F");
-        final URI uri = URI.create("http://broker-service:15672/api/exchanges/%2F/" + exchange);
+        final URI uri = URI.create("http://dbrepo-broker-service:15672/api/exchanges/%2F/" + exchange);
         final CreateExchangeDto payload = CreateExchangeDto.builder()
                 .type("fanout")
                 .autoDelete(false)
@@ -67,7 +67,7 @@ public class AmqpUtils {
     }
 
     public boolean queueExists(String queue) {
-        final URI uri = URI.create("http://broker-service:15672/api/queues/%2F/");
+        final URI uri = URI.create("http://dbrepo-broker-service:15672/api/queues/%2F/");
         final ResponseEntity<QueueDto[]> response = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(null), QueueDto[].class);
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find queue, code is {}", response.getStatusCode());
diff --git a/fda-ui/.gitignore b/fda-ui/.gitignore
index 0c83f47701873d10665a28e24aad623e89467776..a6a8dd571f3fc30997a2b59aab90d21abc4aff7c 100644
--- a/fda-ui/.gitignore
+++ b/fda-ui/.gitignore
@@ -21,6 +21,7 @@ lib-cov
 
 # Coverage directory used by tools like istanbul
 coverage/
+coverage.txt
 
 # nyc test coverage
 .nyc_output
@@ -93,4 +94,5 @@ sw.*
 *.swp
 
 # CI records some videos for the e2e tests
-videos
+videos/
+screenshots/
diff --git a/fda-ui/.nycrc b/fda-ui/.nycrc
index ccda5111b9ac9d41694692f5c4e0a12dadc6fbbb..a4841b7947c1e8e06b5ca816319f1eb0f20b952e 100644
--- a/fda-ui/.nycrc
+++ b/fda-ui/.nycrc
@@ -6,7 +6,7 @@
   "branches": 35,
   "check-coverage": true,
   "include": [ "components/**/*.vue", "layouts/**/*.vue", "pages/**/*.vue", "server-middleware/**/*.js", "store/**/*.js"],
-  "exclude": ["node_modules"],
+  "exclude": ["node_modules", "server-middleware", "store"],
   "extension": [".js", ".vue"],
   "reporter": [
     "lcov",
diff --git a/fda-ui/.prod/default.conf b/fda-ui/.prod/default.conf
deleted file mode 100644
index 43a88f37d85a14ad680cfe0e2c2d483b8ba3bafc..0000000000000000000000000000000000000000
--- a/fda-ui/.prod/default.conf
+++ /dev/null
@@ -1,30 +0,0 @@
-server {
-  listen                3000 default_server;
-  server_name           dbrepo.local;
-  proxy_set_header Host dbrepo.local;
-
-  root /usr/share/nginx/html;
-  index  index.html index.htm;
-
-  location /api {
-    proxy_set_header      X-Real-IP $remote_addr;
-    proxy_set_header Host $host;
-    proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_pass            http://fda-gateway-service:9095;
-  }
-
-  location / {
-    root   /usr/share/nginx/html;
-    try_files $uri $uri/ /index.html;
-    index  index.html index.htm;
-  }
-
-  # allow post on static pages
-  error_page  405     =200 $uri;
-
-  error_page   500 502 503 504  /50x.html;
-  location = /50x.html {
-    root   /usr/share/nginx/html;
-  }
-
-}
diff --git a/fda-ui/.prod/secure.conf b/fda-ui/.prod/secure.conf
deleted file mode 100644
index 402ce356e6f69ac6a322b36c7f3fe78672d6264f..0000000000000000000000000000000000000000
--- a/fda-ui/.prod/secure.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-server {
-  listen                443 default_server;
-  server_name           dbrepo.ossdip.at;
-  proxy_set_header Host dbrepo.ossdip.at;
-
-  root /usr/share/nginx/html;
-
-  index index.html;
-  location / {
-    root   /usr/share/nginx/html;
-    try_files $uri $uri/ /index.html;
-    index  index.html index.htm;
-  }
-
-  location /api {
-    proxy_set_header      X-Real-IP $remote_addr;
-    proxy_set_header Host $host;
-    proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_pass            http://fda-gateway-service:9095;
-  }
-
-  location /server-middleware {
-    proxy_set_header      X-Real-IP $remote_addr;
-    proxy_set_header Host $host;
-    proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_pass            https://fda-ui:443;
-  }
-
-  error_page   500 502 503 504  /50x.html;
-  location = /50x.html {
-    root   /usr/share/nginx/html;
-  }
-
-  ssl    on;
-  ssl_certificate     /etc/nginx/conf.d/cert.pem;
-  ssl_certificate_key /etc/nginx/conf.d/privkey.pem;
-
-}
diff --git a/fda-ui/Dockerfile b/fda-ui/Dockerfile
index b7d21fc55b84240c6a1fdd86f44cf6425c487e98..0df37b3162497a09a783844a2b2eef4f264f9a14 100644
--- a/fda-ui/Dockerfile
+++ b/fda-ui/Dockerfile
@@ -1,4 +1,3 @@
-# FROM node:lts as build
 FROM node:14-alpine as build
 MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
 
@@ -35,6 +34,9 @@ COPY ./utils ./utils
 
 RUN yarn build > /dev/null
 
+FROM node:14-alpine as runtime
+MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
+
 EXPOSE 3000
 EXPOSE 9100
 
@@ -51,6 +53,13 @@ ENV VERSION="${TAG}"
 ENV TITLE="Database Repository"
 ENV ICON="/favicon.ico"
 
+WORKDIR /app
+
+COPY --from=build /usr/local/bin/node_exporter/ /usr/local/bin/node_exporter/
+COPY --from=build /app /app
+
+RUN ls -la
+
 COPY ./docker-entrypoint.sh /app/docker-entrypoint.sh
 RUN chmod +x /app/docker-entrypoint.sh
 
diff --git a/fda-ui/components/DatabaseList.vue b/fda-ui/components/DatabaseList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2f85f6a72ed63ff7c776abf354e839b5fc4198c9
--- /dev/null
+++ b/fda-ui/components/DatabaseList.vue
@@ -0,0 +1,193 @@
+<template>
+  <div>
+    <v-progress-linear v-if="loadingContainers || loadingDatabases" :color="loadingColor" :indeterminate="!error" />
+    <v-card
+      v-for="(container, idx) in containers"
+      :key="idx"
+      :to="link(container)"
+      :disabled="!container.database"
+      flat
+      tile>
+      <v-divider class="mx-4" />
+      <v-card-title v-if="!hasDatabase(container)" v-text="container.name" />
+      <v-card-title v-if="hasDatabase(container)">
+        <a :href="`/container/${container.id}/database/${container.database.id}`">{{ container.name }}</a>
+      </v-card-title>
+      <v-card-subtitle v-if="!hasIdentifier(container)" class="db-subtitle" v-text="formatCreator(container.creator)" />
+      <v-card-subtitle v-if="hasIdentifier(container)" class="db-subtitle" v-text="formatCreatorz(container)" />
+      <v-card-text class="db-description">
+        <div class="db-tags">
+          <v-chip v-if="hasDatabase(container) && container.database.is_public" small color="green" outlined>Public</v-chip>
+          <v-chip v-if="hasDatabase(container) && !container.database.is_public" small color="red" outlined>Private</v-chip>
+          <v-chip v-if="hasIdentifier(container)" small outlined>PID</v-chip>
+          <v-chip
+            v-if="identifierCreated(container)"
+            small
+            outlined
+            v-text="container.database.identifier.publisher" />
+        </div>
+        <div v-text="identifierDescription(container)" />
+      </v-card-text>
+      <v-card-text v-if="canInit(container)" class="db-buttons">
+        <v-btn
+          small
+          secondary
+          :loading="container.database.loading"
+          @click.stop="initDatabase(container)">
+          Start
+        </v-btn>
+      </v-card-text>
+      <v-divider v-if="idx - 1 === databases.length" class="mx-4" />
+    </v-card>
+    <v-toolbar v-if="false" flat>
+      <v-toolbar-title>
+        <v-btn
+          small
+          color="secondary">
+          More
+        </v-btn>
+      </v-toolbar-title>
+    </v-toolbar>
+  </div>
+</template>
+
+<script>
+import { formatCreators, formatUser, formatYearUTC, isResearcher } from '@/utils'
+
+export default {
+  data () {
+    return {
+      loadingContainers: false,
+      loadingCreate: false,
+      createDbDialog: false,
+      databases: [],
+      containers: [],
+      searchQuery: null,
+      limit: 100,
+      createDatabaseDto: {
+        name: null,
+        is_public: true
+      },
+      items: [
+        { text: 'Databases', to: '/container', activeClass: '' }
+      ],
+      loadingDatabases: false,
+      error: false
+    }
+  },
+  computed: {
+    loadingColor () {
+      return this.error ? 'red lighten-2' : 'primary'
+    },
+    token () {
+      return this.$store.state.token
+    },
+    user () {
+      return this.$store.state.user
+    },
+    isResearcher () {
+      return isResearcher(this.user)
+    },
+    config () {
+      if (this.token === null) {
+        return {}
+      }
+      return {
+        headers: { Authorization: `Bearer ${this.token}` }
+      }
+    }
+  },
+  mounted () {
+    this.loadContainers()
+  },
+  methods: {
+    formatCreator (creator) {
+      return formatUser(creator)
+    },
+    formatCreatorz (container) {
+      const creators = formatCreators(container)
+      return creators || this.formatCreator(container.creator)
+    },
+    canInit (container) {
+      if (!this.token) {
+        return false
+      }
+      if (container.creator.username !== this.user.username) {
+        return false
+      }
+      return !container.database.id && !this.loadingDatabases
+    },
+    hasDatabase (container) {
+      return container.database
+    },
+    hasIdentifier (container) {
+      return container.database && container.database.identifier
+    },
+    async initDatabase (container) {
+      await this.startContainer(container)
+        .then(() => this.createDatabase(container))
+    },
+    identifierCreated (container) {
+      if (!container.database.identifier) {
+        return null
+      }
+      return formatYearUTC(container.database.identifier.created)
+    },
+    identifierDescription (container) {
+      if (!container.database.identifier) {
+        return null
+      }
+      return container.database.identifier.description
+    },
+    async loadContainers () {
+      this.createDbDialog = false
+      try {
+        this.loadingContainers = true
+        const res = await this.$axios.get(`/api/container?limit=${this.limit}`)
+        this.containers = res.data
+        console.debug('containers', this.containers)
+        this.error = false
+      } catch (error) {
+        this.error = true
+        console.error('Failed to retrieve containers', error)
+        const { message } = error.response.data
+        this.$toast.error(`Failed to retrieve containers: ${message}`)
+      }
+      this.loadingContainers = false
+    },
+    async startContainer (container) {
+      try {
+        container.database.loading = true
+        const res = await this.$axios.put(`/api/container/${container.id}`, { action: 'start' }, this.config)
+        console.debug('started container', res.data)
+        this.error = false
+      } catch (error) {
+        const { status } = error.response
+        if (status !== 409) {
+          this.error = true
+          this.$toast.error('Failed to start container')
+        }
+      }
+      container.database.loading = false
+    },
+    link (container) {
+      if (!container.database || !container.database.id) {
+        return null
+      }
+      return `/container/${container.id}/database/${container.database.id}`
+    }
+  }
+}
+</script>
+
+<style>
+.v-chip:not(:first-child) {
+  margin-left: 8px;
+}
+.db-subtitle {
+  padding-bottom: 8px;
+}
+.db-tags {
+  margin-bottom: 8px;
+}
+</style>
diff --git a/fda-ui/components/QueryList.vue b/fda-ui/components/QueryList.vue
index 96227d2816243e881c2a21d01b2a5702e5474041..5e5f6772b115f0755ff1c138b05a823ba1eed2ce 100644
--- a/fda-ui/components/QueryList.vue
+++ b/fda-ui/components/QueryList.vue
@@ -2,9 +2,6 @@
   <div>
     <v-progress-linear v-if="loadingIdentifiers || loadingQueries || error" :color="loadingColor" :value="loadProgress" />
     <v-tabs-items>
-      <v-card v-if="!loadingQueries && queries.length === 0 && !error" flat>
-        <v-card-text v-text="emptyMessage" />
-      </v-card>
       <div v-if="!loadingQueries && !error">
         <div v-for="(item,i) in queries" :key="i">
           <v-divider v-if="i !== 0" class="mx-4" />
@@ -16,12 +13,15 @@
                   <pre>{{ item.query }}</pre>
                 </v-list-item-subtitle>
               </v-list-item-content>
+              <v-list-item-action v-if="item.identifier">
+                <v-icon color="primary">mdi-identifier</v-icon>
+              </v-list-item-action>
             </v-list-item>
           </v-list-item-group>
         </div>
       </div>
       <div v-if="!loadingIdentifiers && loadingQueries">
-        <!-- show identifiers when error -->
+        <!-- show identifiers when loading subsets -->
         <div v-for="(item,i) in identifiers" :key="i">
           <v-divider v-if="i !== 0" class="mx-4" />
           <v-list-item-group>
@@ -32,6 +32,28 @@
                   <pre>{{ item.query }}</pre>
                 </v-list-item-subtitle>
               </v-list-item-content>
+              <v-list-item-action>
+                <v-icon color="primary">mdi-identifier</v-icon>
+              </v-list-item-action>
+            </v-list-item>
+          </v-list-item-group>
+        </div>
+      </div>
+      <div v-if="!loadingIdentifiers && !isPublicOrOwner">
+        <!-- show identifiers when private -->
+        <div v-for="(item,i) in identifiers" :key="i">
+          <v-divider v-if="i !== 0" class="mx-4" />
+          <v-list-item-group>
+            <v-list-item two-line :class="clazz(item)" :to="link(item)" :href="navigate(item)">
+              <v-list-item-content>
+                <v-list-item-title v-text="item.title" />
+                <v-list-item-subtitle class="mt-2">
+                  <pre>{{ item.query }}</pre>
+                </v-list-item-subtitle>
+              </v-list-item-content>
+              <v-list-item-action>
+                <v-icon color="primary">mdi-identifier</v-icon>
+              </v-list-item-action>
             </v-list-item>
           </v-list-item-group>
         </div>
@@ -81,11 +103,20 @@ export default {
     creator () {
       return this.queryDetails.creator
     },
-    emptyMessage () {
-      if (this.isPublicOrOwner()) {
-        return '(no subsets)'
+    isPublicOrOwner () {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_public) {
+        return true
+      }
+      if (this.token === null) {
+        return false
       }
-      return '(private database)'
+      if (!this.user) {
+        return false
+      }
+      return this.database.creator.username === this.user.username
     }
   },
   mounted () {
@@ -117,10 +148,14 @@ export default {
         const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query?persisted=true`, this.config)
         this.queries = res.data
         console.debug('queries', this.queries)
-      } catch (err) {
-        this.error = true
-        console.error('Connection to query store failed', err.response.index)
-        this.$toast.error(err.response.index.message)
+      } catch (error) {
+        const { status, data } = error.response
+        const { message } = data
+        if (status !== 405) {
+          this.error = true
+          console.error('Connection to query store failed', error)
+          this.$toast.error(`Failed to connect to query store: ${message}`)
+        }
       }
       this.loadingQueries = false
     },
@@ -149,29 +184,11 @@ export default {
       return `/pid/${queryOrIdentifier.identifier.id}`
     },
     clazz (queryOrIdentifier) {
-      if (!('identifier' in queryOrIdentifier) || queryOrIdentifier.identifier === null) {
-        return null
-      }
       if ('query_id' in queryOrIdentifier || queryOrIdentifier.identifier) {
         return 'primary--text'
       }
       return null
     },
-    isPublicOrOwner () {
-      if (!this.database) {
-        return false
-      }
-      if (this.database.is_public) {
-        return true
-      }
-      if (this.token === null) {
-        return false
-      }
-      if (!this.user) {
-        return false
-      }
-      return this.database.creator.username === this.user.username
-    },
     simulateProgress () {
       if (this.loadProgress !== 0) {
         return
diff --git a/fda-ui/components/TableList.vue b/fda-ui/components/TableList.vue
index c326f81505cee79b2c62bec9635bd4514f916a4b..456a8f6b087409e8a728ac0acc20830706db27a0 100644
--- a/fda-ui/components/TableList.vue
+++ b/fda-ui/components/TableList.vue
@@ -9,7 +9,9 @@
     <div v-for="(item,i) in tables" :key="i">
       <v-divider v-if="i !== 0" class="mx-4" />
       <v-list-item-group>
-        <v-list-item two-line :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${item.id}`">
+        <v-list-item
+          two-line
+          :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${item.id}`">
           <v-list-item-content>
             <v-list-item-title v-text="item.name" />
             <v-list-item-subtitle class="mt-2" v-text="item.description" />
@@ -113,29 +115,11 @@ export default {
       }
       return formatTimestampUTCLabel(this.tableDetails.created)
     },
-    hasReadAccess () {
-      if (!this.database) {
-        return false
-      }
-      if (this.database.is_public) {
-        /* database is public */
-        return true
-      }
-      if (!this.user) {
+    canRead () {
+      if (!this.user || !this.access) {
         return false
       }
-      if (this.database.creator.username === this.user.username) {
-        /* user is creator of database */
-        return true
-      }
-      if (!this.access) {
-        return false
-      }
-      if (this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all') {
-        /* user has some level of access */
-        return true
-      }
-      return false
+      return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all'
     },
     canModify () {
       if (!this.token || !this.user.username) {
@@ -171,7 +155,7 @@ export default {
       /* use cache */
       this.tableDetails = table
       /* load remaining info */
-      if (this.hasReadAccess) {
+      if (this.canRead) {
         try {
           this.loadingDetails = true
           const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${table.id}`, this.config)
diff --git a/fda-ui/components/TableToolbar.vue b/fda-ui/components/TableToolbar.vue
index 350f5a1e50327094dbe0ac3865882cb8972d58e8..c138b2e7dcb4337733f04beb6ae07d9719edcdb3 100644
--- a/fda-ui/components/TableToolbar.vue
+++ b/fda-ui/components/TableToolbar.vue
@@ -35,7 +35,7 @@
       <v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/info`">
         Info
       </v-tab>
-      <v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/data`">
+      <v-tab v-if="canRead" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/data`">
         Data
       </v-tab>
       <v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/schema`">
diff --git a/fda-ui/components/ViewList.vue b/fda-ui/components/ViewList.vue
index ef511dbd6e10ca85f502d5adb00c45c1c71b0219..b2aff93d4e03c52af606c7792d50141af0dff87a 100644
--- a/fda-ui/components/ViewList.vue
+++ b/fda-ui/components/ViewList.vue
@@ -9,7 +9,7 @@
     <div v-for="(item,i) in views" :key="i">
       <v-divider v-if="i !== 0" class="mx-4" />
       <v-list-item-group>
-        <v-list-item two-line :class="clazz(item)" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/view/${item.id}`">
+        <v-list-item two-line :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/view/${item.id}`">
           <v-list-item-content>
             <v-list-item-title v-text="item.name" />
             <v-list-item-subtitle class="mt-2">
@@ -127,12 +127,6 @@ export default {
         this.$toast.error('Failed to delete view')
         console.error('Failed to delete view')
       }
-    },
-    clazz (view) {
-      if (view.is_public === false) {
-        return null
-      }
-      return 'primary--text'
     }
   }
 }
diff --git a/fda-ui/components/dialogs/EditTuple.vue b/fda-ui/components/dialogs/EditTuple.vue
index b5443874a9f33e66aeaf97b80831f8583d34fdbd..a3bf26d5f60d32e26954e764d98a33d233e92716 100644
--- a/fda-ui/components/dialogs/EditTuple.vue
+++ b/fda-ui/components/dialogs/EditTuple.vue
@@ -1,5 +1,5 @@
 <template>
-  <div v-if="tuple">
+  <div v-if="localTuple">
     <v-form ref="form" v-model="valid" @submit.prevent="submit">
       <v-card>
         <v-progress-linear v-if="loading" :color="loadingColor" :indeterminate="!error" />
@@ -8,7 +8,7 @@
           <div v-for="(attr,idx) in columns" :key="idx">
             <v-text-field
               v-if="attr.column_type === 'number'"
-              v-model.number="tuple[attr.internal_name]"
+              v-model.number="localTuple[attr.internal_name]"
               :disabled="(!edit && attr.auto_generated)"
               class="mb-2"
               :hint="hint(attr)"
@@ -19,7 +19,7 @@
               type="number" />
             <v-text-field
               v-if="attr.column_type === 'string' || attr.column_type === 'text' || attr.column_type === 'decimal'"
-              v-model="tuple[attr.internal_name]"
+              v-model="localTuple[attr.internal_name]"
               :disabled="(edit && attr.is_primary_key) || (!edit && attr.auto_generated)"
               class="mb-2"
               :rules="(attr.is_null_allowed || attr.auto_generated) ? [] : [ v => !!v || $t('Required') ]"
@@ -28,7 +28,7 @@
               type="text" />
             <v-text-field
               v-if="attr.column_type === 'timestamp'"
-              v-model="tuple[attr.internal_name]"
+              v-model="localTuple[attr.internal_name]"
               suffix="UTC"
               hint="e.g. 2022-07-12 18:32:59"
               :rules="(attr.auto_generated) ? [] : (attr.is_null_allowed ? [ validateTimestamp ] : [validateTimestamp || $t('Required format yyyy-MM-dd HH:mm:ss'), v => !!v || $t('Required')])"
@@ -46,7 +46,7 @@
               min-width="auto">
               <template v-slot:activator="{ on, attrs }">
                 <v-text-field
-                  v-model="tuple[attr.internal_name]"
+                  v-model="localTuple[attr.internal_name]"
                   :label="label(attr)"
                   suffix="UTC"
                   readonly
@@ -54,25 +54,27 @@
                   v-on="on" />
               </template>
               <v-date-picker
-                v-model="tuple[attr.internal_name]"
+                v-model="localTuple[attr.internal_name]"
                 color="primary"
                 no-title
                 scrollable />
             </v-menu>
             <v-select
               v-if="attr.column_type === 'ENUM'"
-              v-model="tuple[attr.internal_name]"
+              v-model="localTuple[attr.internal_name]"
               class="mb-2"
               :rules="(attr.is_null_allowed || attr.auto_generated) ? [] : [ v => !!v || $t('Required') ]"
               :required="required(attr)"
               :items="attr.enum_values"
               :label="label(attr)" />
-            <v-checkbox
+            <v-select
               v-if="attr.column_type === 'boolean'"
-              v-model="tuple[attr.internal_name]"
-              :rules="(attr.is_null_allowed || attr.auto_generated) ? [] : [ v => !!v || $t('Required') ]"
-              :required="required(attr)"
+              v-model="localTuple[attr.internal_name]"
               class="mb-2"
+              :rules="(attr.is_null_allowed || attr.auto_generated) ? [] : [ v => v !== null || $t('Required') ]"
+              :required="required(attr)"
+              :items="bools"
+              :clearable="attr.is_null_allowed"
               :label="label(attr)" />
           </div>
         </v-card-text>
@@ -127,7 +129,12 @@ export default {
       loading: false,
       error: false,
       menu: false,
-      columns: this.$parent.$parent.$parent.$parent.table.columns
+      columns: this.$parent.$parent.$parent.$parent.table.columns,
+      localTuple: null,
+      bools: [
+        { text: 'true', value: true },
+        { text: 'false', value: false }
+      ]
     }
   },
   computed: {
@@ -141,6 +148,14 @@ export default {
       return (this.edit ? 'Edit' : 'Add') + ' tuple'
     }
   },
+  watch: {
+    tuple (val) {
+      this.localTuple = val
+    }
+  },
+  mounted () {
+    this.localTuple = Object.assign({}, this.tuple)
+  },
   methods: {
     submit () {
       this.$refs.form.validate()
@@ -178,7 +193,7 @@ export default {
           constraints[c.internal_name] = this.tuple[c.internal_name]
         })
       const data = {
-        data: this.tuple,
+        data: this.localTuple,
         keys: constraints
       }
       try {
@@ -188,9 +203,10 @@ export default {
         console.info('update result')
         this.$toast.success('Successfully updated tuple!')
         this.$emit('close', { success: true })
-      } catch (err) {
-        console.error('Failed to update tuple', err)
-        this.$toast.error('Failed to update tuple')
+      } catch (error) {
+        console.error('Failed to update tuple', error)
+        const { message } = error.response.data
+        this.$toast.error('Failed to update tuple: ' + message)
       }
     },
     async addTuple () {
@@ -198,7 +214,7 @@ export default {
       this.columns
         .filter(c => c.is_primary_key)
         .forEach((c) => {
-          constraints[c.internal_name] = this.tuple[c.internal_name]
+          constraints[c.internal_name] = this.localTuple[c.internal_name]
         })
       try {
         const res = await this.$axios.post(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data`, {
diff --git a/fda-ui/components/dialogs/Persist.vue b/fda-ui/components/dialogs/Persist.vue
index f57c31ec2234cc99d62751787255285a492b1a16..a8595e18fd1151270c670c256f2509997c799b63 100644
--- a/fda-ui/components/dialogs/Persist.vue
+++ b/fda-ui/components/dialogs/Persist.vue
@@ -64,6 +64,19 @@
                 required />
             </v-col>
           </v-row>
+          <v-row dense>
+            <v-col>
+              <v-select
+                id="visibility"
+                v-model="visibility"
+                name="visibility"
+                label="Visibility *"
+                :items="['Public']"
+                disabled
+                :rules="[v => !!v || $t('Required')]"
+                required />
+            </v-col>
+          </v-row>
           <v-row v-for="(creator,i) in identifier.creators" :key="`c-${i}`" dense>
             <v-col cols="3">
               <v-text-field
@@ -200,6 +213,7 @@ export default {
       loading: false,
       error: false, // XXX: `error` is never changed
       licenses: [],
+      visibility: 'Public',
       identifier: {
         cid: parseInt(this.$route.params.container_id),
         dbid: parseInt(this.$route.params.database_id),
diff --git a/fda-ui/components/query/Builder.vue b/fda-ui/components/query/Builder.vue
index a624a3809aec061902fca8e895972bc2ce38dce6..311aac14f2dce772d544e29c11b558dab57e9e9e 100644
--- a/fda-ui/components/query/Builder.vue
+++ b/fda-ui/components/query/Builder.vue
@@ -209,10 +209,6 @@ export default {
     }
   },
   computed: {
-    selectItems () {
-      const columns = this.tableDetails && this.tableDetails.columns
-      return columns || []
-    },
     columnNames () {
       return this.columns && this.columns.map(s => s.internal_name)
     },
@@ -334,7 +330,7 @@ export default {
         this.$toast.error(err.response.data.message)
       }
       this.loadingQuery = false
-      await this.$refs.queryResults.reExecute(this.resultId)
+      await Promise.all([this.$refs.queryResults.reExecute(this.resultId), this.$refs.queryResults.reExecuteCount(this.resultId)])
     },
     async buildQuery () {
       if (!this.table) {
diff --git a/fda-ui/components/query/Results.vue b/fda-ui/components/query/Results.vue
index 4d52923b58edcb2e02d63c055ee77dea183b5195..d04b59378614effed3b3a6595bbb912f13c164bc 100644
--- a/fda-ui/components/query/Results.vue
+++ b/fda-ui/components/query/Results.vue
@@ -3,7 +3,7 @@
     flat
     :headers="result.headers"
     :items="result.rows"
-    :loading="loading"
+    :loading="loading > 0"
     :options.sync="options"
     :server-items-length="total" />
 </template>
@@ -18,7 +18,7 @@ export default {
   },
   data () {
     return {
-      loading: false,
+      loading: 0,
       resultId: null,
       id: null,
       result: {
@@ -29,7 +29,7 @@ export default {
         page: 1,
         itemsPerPage: 10
       },
-      total: 0
+      total: -1
     }
   },
   computed: {
@@ -60,7 +60,7 @@ export default {
   },
   methods: {
     async executeFirstTime (parent, sql, timestamp) {
-      this.loading = true
+      this.loading++
       try {
         const res = await this.$axios.post(this.executeUrl, { statement: sql, timestamp }, this.config)
         console.debug('query result', res.data)
@@ -80,7 +80,7 @@ export default {
         }
         this.error = true
       }
-      this.loading = false
+      this.loading--
     },
     buildHeaders (firstLine) {
       return Object.keys(firstLine).map(k => ({
@@ -92,13 +92,16 @@ export default {
     reExecuteUrl (resultId) {
       const page = this.options.page - 1
       const urlParams = `page=${page}&size=${this.options.itemsPerPage}`
-      return `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}` + (this.type === 'view' ? '/view' : '/query') + `/${resultId}/data?${urlParams}`
+      return `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/${this.type}/${resultId}/data?${urlParams}`
+    },
+    reExecuteCountUrl (resultId) {
+      return `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/${this.type}/${resultId}/data/count`
     },
     async reExecute (id) {
       if (id === null) {
         return
       }
-      this.loading = true
+      this.loading++
       try {
         const res = await this.$axios.get(this.reExecuteUrl(id), this.config)
         this.mapResults(res.data)
@@ -107,7 +110,21 @@ export default {
         console.error('failed to execute query', error)
         this.error = true
       }
-      this.loading = false
+      this.loading--
+    },
+    async reExecuteCount (id) {
+      if (id === null) {
+        return
+      }
+      this.loading++
+      try {
+        const res = await this.$axios.get(this.reExecuteCountUrl(id), this.config)
+        this.total = res.data
+      } catch (error) {
+        console.error('failed to execute query count', error)
+        this.error = true
+      }
+      this.loading--
     },
     mapResults (data) {
       if (data.result.length) {
@@ -115,7 +132,9 @@ export default {
       }
       console.debug('query result', data)
       this.result.rows = data.result
-      this.total = data.result_number
+      if (this.total < 0 && data.result_number != null) {
+        this.total = data.result_number
+      }
     }
   }
 }
diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue
index 03887d4bed746416a37d0271c9f32ded815e797b..a2ced808cfa3cfd0e8fd39f7b19493682d1b2079 100644
--- a/fda-ui/layouts/default.vue
+++ b/fda-ui/layouts/default.vue
@@ -50,7 +50,7 @@
           single-line
           hide-details
           placeholder="Search ..." />
-        <v-btn icon class="ml-2" type="submit" @click="retrieve">
+        <v-btn icon class="ml-2" type="submit" name="search-submit" @click="retrieve">
           <v-icon>mdi-magnify</v-icon>
         </v-btn>
         <v-spacer />
@@ -227,8 +227,10 @@ export default {
     this.loadUser()
     this.setTheme()
     this.loadDatabase()
-      .then(() => this.loadIdentifier())
-    this.loadTable()
+      .then(() => {
+        this.loadIdentifier()
+        this.loadTable()
+      })
     this.loadAccess()
     if (this.$route.query && this.$route.query.q) {
       this.search = this.$route.query.q
@@ -298,9 +300,16 @@ export default {
         const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}`, this.config)
         this.$store.commit('SET_TABLE', res.data)
         console.debug('table', this.table)
-      } catch (err) {
-        console.error('Could not load table', err)
-        this.$toast.error('Could not load table')
+      } catch (error) {
+        const { status } = error.response
+        if (status === 405) {
+          const table = this.database.tables.filter(t => t.id === Number(this.$route.params.table_id))[0]
+          this.$store.commit('SET_TABLE', table)
+        } else {
+          const { message } = error.response.data
+          console.error('Failed to load table', error)
+          this.$toast.error(`Failed to load table: ${message}`)
+        }
       }
       this.loading = false
     },
@@ -327,7 +336,7 @@ export default {
       this.loading = false
     },
     async loadIdentifier () {
-      if ('identifier' in this.database) {
+      if (!this.database || 'identifier' in this.database) {
         return
       }
       try {
diff --git a/fda-ui/package.json b/fda-ui/package.json
index de4d543b8929a002388db5d4e3a55e9cc2e96bfa..1649177b07b97389c2827d1c565f2db4f7e77ca9 100644
--- a/fda-ui/package.json
+++ b/fda-ui/package.json
@@ -8,15 +8,16 @@
     "build": "nuxt build",
     "start": "nuxt start",
     "generate": "nuxt generate",
+    "clean": "rm -f ./videos/*",
     "ver": "nuxt --version",
     "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
     "lint": "yarn lint:js",
-    "coverage": "nyc ava test/unit/**/* test/specs/**/*",
+    "coverage": "nyc ava test/unit/**/* test/specs/**/* > ./coverage.txt",
     "test:unit": "ava test/unit/**/* test/specs/**/*",
     "test:watch": "ava --watch test/unit/**/* test/specs/**/*",
-    "test:e2e": "cross-env PORT=3001 ava --timeout=2h --fail-fast test/e2e/**",
+    "test:e2e": "yarn clean && cross-env PORT=3001 ava --timeout=2h --fail-fast test/e2e/**",
     "test:e2e:docker": "cross-env PORT=3000 SLOWMO=500 ava --timeout=2h --fail-fast test/e2e/**",
-    "test": "yarn test:unit && yarn test:e2e:docker"
+    "test": "yarn clean && yarn test:unit && yarn test:e2e:docker && yarn coverage"
   },
   "dependencies": {
     "@babel/plugin-transform-runtime": "^7.13.9",
@@ -25,6 +26,7 @@
     "@nuxtjs/eslint-module": "^2.0.0",
     "@nuxtjs/proxy": "^2.1.0",
     "@nuxtjs/vuetify": "^1.11.2",
+    "axios": "^1.3.0",
     "chart.js": "^3.8.0",
     "core-js": "^3.6.5",
     "date-fns": "^2.16.1",
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/info.vue b/fda-ui/pages/container/_container_id/database/_database_id/info.vue
index 6b4849304911ec51016292a87a7034d335a04d43..b9224362e62047fb60aa8b81f72f49b67b949b53 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/info.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/info.vue
@@ -114,33 +114,7 @@
             </v-card-actions>
           </v-card-text>
         </v-card>
-        <v-divider v-if="hasIdentifier || (isCreator && isResearcher) || isDataSteward" />
-        <v-card flat tile>
-          <v-card-title>Container</v-card-title>
-          <v-card-text>
-            <v-list dense>
-              <v-list-item>
-                <v-list-item-content>
-                  <v-list-item-title class="mt-2">
-                    Container Name
-                  </v-list-item-title>
-                  <v-list-item-content>
-                    <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" />
-                    <span v-if="!loading" v-text="container_name" />
-                  </v-list-item-content>
-                  <v-list-item-title class="mt-2">
-                    Container Internal Name
-                  </v-list-item-title>
-                  <v-list-item-content>
-                    <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" />
-                    <span v-if="!loading" v-text="container_internal_name" />
-                  </v-list-item-content>
-                </v-list-item-content>
-              </v-list-item>
-            </v-list>
-          </v-card-text>
-        </v-card>
-        <v-divider />
+        <v-divider v-if="isDataSteward || hasIdentifier || (!hasIdentifier && isCreator && isResearcher)" />
         <v-card flat tile>
           <v-card-title>Database</v-card-title>
           <v-card-text>
@@ -205,6 +179,32 @@
             </v-list>
           </v-card-text>
         </v-card>
+        <v-divider />
+        <v-card flat tile>
+          <v-card-title>Container</v-card-title>
+          <v-card-text>
+            <v-list dense>
+              <v-list-item>
+                <v-list-item-content>
+                  <v-list-item-title class="mt-2">
+                    Container Name
+                  </v-list-item-title>
+                  <v-list-item-content>
+                    <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" />
+                    <span v-if="!loading" v-text="container_name" />
+                  </v-list-item-content>
+                  <v-list-item-title class="mt-2">
+                    Container Internal Name
+                  </v-list-item-title>
+                  <v-list-item-content>
+                    <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" />
+                    <span v-if="!loading" v-text="container_internal_name" />
+                  </v-list-item-content>
+                </v-list-item-content>
+              </v-list-item>
+            </v-list>
+          </v-card-text>
+        </v-card>
       </v-tab-item>
     </v-tabs-items>
     <v-dialog
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
index 97cc6d16ceda3ed5d6f4c3742e4a27d175f9fc6d..4ca589d1527db7c2bd3eea1a845348c3f3d2d9c9 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
@@ -336,6 +336,9 @@ export default {
       if (this.query.creator.username === this.username) {
         return true
       }
+      if (!this.query.identifier) {
+        return false
+      }
       return this.query.identifier.visibility === 'everyone'
     },
     canWrite () {
@@ -367,6 +370,7 @@ export default {
   methods: {
     loadResult () {
       this.$refs.queryResults.reExecute(this.query.id)
+      this.$refs.queryResults.reExecuteCount(this.query.id)
     },
     async download (mime) {
       if (mime === 'text/csv') {
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/settings.vue b/fda-ui/pages/container/_container_id/database/_database_id/settings.vue
index 63f3d69a7d1a6a5b5c72c760e6cbd7c2add615f6..a22d9092ede9f2dca88c0e21c619011358dc403e 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/settings.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/settings.vue
@@ -174,7 +174,7 @@ export default {
     async updateDatabaseVisibility () {
       try {
         this.loading = true
-        await this.$axios.put(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/transfer`, this.modifyVisibility, this.config)
+        await this.$axios.put(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/visibility`, this.modifyVisibility, this.config)
         this.$toast.success('Successfully updated the database')
         location.reload()
       } catch (err) {
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue
index f041e3630467686d5afe0b2c834ca0fd319fa75b..17f58d3b1ed4fea81a5bb3f5aee217b26b2df852 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div v-if="canRead">
     <TableToolbar :selection="selection" @modified="modified" />
     <v-toolbar :color="versionColor" flat>
       <v-toolbar-title>
@@ -23,7 +23,7 @@
       </v-toolbar-title>
     </v-toolbar>
     <v-card tile>
-      <v-progress-linear v-if="loadingData || error" :value="loadProgress" :color="error ? 'error' : 'primary'" />
+      <v-progress-linear v-if="loadingData > 0 || error" :value="loadProgress" :color="error ? 'error' : 'primary'" />
       <v-data-table
         :headers="headers"
         :items="rows"
@@ -41,7 +41,7 @@
 <script>
 import TimeTravel from '@/components/dialogs/TimeTravel'
 import TableToolbar from '@/components/TableToolbar'
-import { formatTimestampUTCLabel, formatDateUTC, formatTimestamp } from '@/utils'
+import { formatTimestampUTC, formatDateUTC, formatTimestamp } from '@/utils'
 
 export default {
   components: {
@@ -51,10 +51,10 @@ export default {
   data () {
     return {
       loading: true,
-      loadingData: true,
+      loadingData: 0,
       loadProgress: 0,
       editTupleDialog: false,
-      total: 0,
+      total: -1,
       footerProps: {
         'items-per-page-options': [10, 20, 30, 40, 50]
       },
@@ -64,6 +64,7 @@ export default {
       selection: [],
       pickVersionDialog: null,
       version: null,
+      lastReload: new Date(),
       tab: null,
       error: false, // XXX: `error` is never changed
       options: {
@@ -165,7 +166,7 @@ export default {
   watch: {
     version (newVersion, oldVersion) {
       console.info('selected new version', newVersion)
-      this.loadData()
+      this.reload()
     },
     options () {
       this.loadData()
@@ -177,7 +178,7 @@ export default {
     }
   },
   mounted () {
-    this.loadData()
+    this.reload()
     this.simulateProgress()
     this.loadProperties()
   },
@@ -254,19 +255,22 @@ export default {
         this.selection = []
       }
       if (success) {
-        this.loadData()
+        this.reload()
       }
     },
+    reload () {
+      this.lastReload = new Date()
+      this.loadData()
+      this.loadCount()
+    },
     async loadData () {
       try {
-        this.loadingData = true
-        let url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data?page=${this.options.page - 1}&size=${this.options.itemsPerPage}`
+        this.loadingData++
+        const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data?page=${this.options.page - 1}&size=${this.options.itemsPerPage}&timestamp=${this.versionISO || this.lastReload.toISOString()}`
         if (this.version !== null) {
           console.info('versioning active', this.version)
-          url += `&timestamp=${this.versionISO}`
         }
         const res = await this.$axios.get(url, this.config)
-        this.total = parseInt(res.headers['fda-count'])
         this.rows = res.data.result.map((row) => {
           for (const col in row) {
             const columnDefinition = this.dateColumns.filter(c => c.internal_name === col)
@@ -274,7 +278,7 @@ export default {
               if (columnDefinition[0].column_type === 'date') {
                 row[col] = formatDateUTC(row[col])
               } else if (columnDefinition[0].column_type === 'timestamp') {
-                row[col] = formatTimestampUTCLabel(row[col])
+                row[col] = formatTimestampUTC(row[col])
               }
             }
           }
@@ -294,8 +298,36 @@ export default {
           console.error('Failed to load data', code)
           this.$toast.error('Failed to load data: ' + message)
         }
+      } finally {
+        this.loadingData--
+      }
+    },
+    async loadCount () {
+      try {
+        this.loadingData++
+        const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data/count?timestamp=${this.versionISO || this.lastReload.toISOString()}`
+        if (this.version !== null) {
+          console.info('versioning active', this.version)
+        }
+        const res = await this.$axios.get(url, this.config)
+        this.total = res.data
+        console.info('total', this.total)
+      } catch (error) {
+        console.error('Failed to load count', error)
+        this.error = true
+        this.loadProgress = 100
+        const { status, data } = error.response
+        const { message, code } = data
+        if (status === 423) {
+          console.error('Database is offline', code)
+          this.$toast.error('Database is offline: ' + message)
+        } else {
+          console.error('Failed to load data', code)
+          this.$toast.error('Failed to load data: ' + message)
+        }
+      } finally {
+        this.loadingData--
       }
-      this.loadingData = false
     },
     simulateProgress () {
       if (this.loadProgress !== 0) {
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue
index 50e51aaafa3be94accfb3769bc8b58875acd0186..9a27f6db5cac79fa2ea91b15ffd0c1f441aa98d0 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue
@@ -31,16 +31,18 @@
                 <span v-if="table && table.creator">{{ formatCreator(table.creator) }} <span v-if="is_owner(table)" style="flex:none;">&nbsp;(you)</span></span>
                 <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" />
               </v-list-item-content>
-              <v-list-item-title class="mt-2">
+              <v-list-item-title v-if="table && table.created" class="mt-2">
                 Table Creation
               </v-list-item-title>
-              <v-list-item-content>
-                <span v-if="table && table.created">{{ createdUTC }}</span>
-                <v-skeleton-loader v-if="!table" type="text" class="skeleton-small" />
+              <v-list-item-content v-if="table && table.created">
+                <span>{{ createdUTC }}</span>
+              </v-list-item-content>
+              <v-list-item-content v-if="!table">
+                <v-skeleton-loader type="text" class="skeleton-medium" />
               </v-list-item-content>
             </v-list-item-content>
           </v-list-item>
-          <v-list-item>
+          <v-list-item v-if="canModify">
             <v-list-item-icon>
               <v-icon>mdi-rabbit</v-icon>
             </v-list-item-icon>
@@ -58,29 +60,35 @@
                 <pre v-if="database && database.exchange_name">{{ database.exchange_name }}</pre>
                 <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" />
               </v-list-item-content>
-              <v-list-item-title class="mt-2">
+              <v-list-item-title v-if="table && table.queue_name" class="mt-2">
                 Queue Name
               </v-list-item-title>
-              <v-list-item-content>
-                <pre v-if="table && table.queue_name">{{ table.queue_name }}</pre>
-                <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" />
+              <v-list-item-content v-if="table && table.queue_name">
+                <pre>{{ table.queue_name }}</pre>
               </v-list-item-content>
-              <v-list-item-title class="mt-2">
+              <v-list-item-content v-if="!table">
+                <v-skeleton-loader type="text" class="skeleton-medium" />
+              </v-list-item-content>
+              <v-list-item-title v-if="table && table.routing_key" class="mt-2">
                 Routing Key
               </v-list-item-title>
-              <v-list-item-content>
-                <pre v-if="table && table.routing_key">{{ table.routing_key }}</pre>
-                <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" />
+              <v-list-item-content v-if="table && table.routing_key">
+                <pre>{{ table.routing_key }}</pre>
               </v-list-item-content>
-              <v-list-item-title v-if="hasReadAccess" class="mt-2">
+              <v-list-item-content v-if="!table">
+                <v-skeleton-loader type="text" class="skeleton-medium" />
+              </v-list-item-content>
+              <v-list-item-title v-if="canRead" class="mt-2">
                 Consumer Count
               </v-list-item-title>
-              <v-list-item-content v-if="hasReadAccess" class="amqp-consumer">
-                <span v-text="`${consumersUp}/${consumersTotal}`" />
+              <v-list-item-content v-if="canRead" class="amqp-consumer">
+                <span v-if="attemptedLoadingConsumers" v-text="`${consumersUp}/${consumersTotal}`" />
                 <v-badge
+                  v-if="attemptedLoadingConsumers"
                   class="ml-1"
                   :color="consumersState.color"
                   :content="consumersState.text" />
+                <v-skeleton-loader v-else type="text" class="skeleton-xsmall" />
               </v-list-item-content>
             </v-list-item-content>
           </v-list-item>
@@ -101,6 +109,7 @@ export default {
   data () {
     return {
       loadingConsumers: false,
+      attemptedLoadingConsumers: false,
       selection: [],
       consumers: [],
       items: [
@@ -137,29 +146,11 @@ export default {
     table () {
       return this.$store.state.table
     },
-    hasReadAccess () {
-      if (!this.database) {
-        return false
-      }
-      if (this.database.is_public) {
-        /* database is public */
-        return true
-      }
-      if (!this.user) {
+    canRead () {
+      if (!this.user || !this.access) {
         return false
       }
-      if (this.database.creator.username === this.user.username) {
-        /* user is creator of database */
-        return true
-      }
-      if (!this.access) {
-        return false
-      }
-      if (this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all') {
-        /* user has some level of access */
-        return true
-      }
-      return false
+      return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all'
     },
     createdUTC () {
       if (this.table.created === undefined || this.table.created === null) {
@@ -192,7 +183,7 @@ export default {
       return this.consumers.filter(c => c.active).length
     },
     canModify () {
-      if (!this.token || !this.user.username) {
+      if (!this.token || !this.user.username || !this.table || !('creator' in this.table) || !this.table.creator || !('username' in this.table.creator) || !this.table.creator.username) {
         /* not yet loaded */
         return false
       }
@@ -223,9 +214,11 @@ export default {
       }
     }
   },
-  mounted () {
-    this.pollConsumerStatus(true)
-    setInterval(() => this.pollConsumerStatus(false), 5 * 1000)
+  watch: {
+    table (val) {
+      this.pollConsumerStatus(true)
+      setInterval(() => this.pollConsumerStatus(false), 5 * 1000)
+    }
   },
   methods: {
     formatCreator (creator) {
@@ -247,10 +240,13 @@ export default {
         const consumers = res.data.filter(c => c.queue.name === this.table.queue_name)
         console.debug('filtered', consumers)
         this.consumers = consumers
-      } catch (err) {
-        console.error('Could not find consumers', err)
+      } catch (error) {
+        const { message } = error
+        console.error('Failed to find consumers', error)
+        this.$toast.error(`Failed to find consumers: ${message}`)
       }
       this.loadingConsumers = false
+      this.attemptedLoadingConsumers = true
     }
   }
 }
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue
index 712dafbd367544bcb34a374d75527b8173dd3e26..72022b57c94af3625d59739cbba55c117b764262 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue
@@ -183,10 +183,10 @@ export default {
       return null
     },
     hasUnit (item) {
-      return item.unit !== null
+      return item.unit && 'uri' in item.unit
     },
     hasConcept (item) {
-      return item.concept !== null
+      return item.concept && 'uri' in item.concept
     },
     pick (item) {
       this.column = item
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue
index 4d9df5a1e7658661fccfd4d2ffea501b54c0fdec..55930ae93e6856d48598213f02e4ded25c69ba24 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue
@@ -191,6 +191,7 @@ export default {
         return
       }
       this.$refs.queryResults.reExecute(viewId)
+      this.$refs.queryResults.reExecuteCount(viewId)
     },
     formatUTC (timestamp) {
       return formatTimestampUTCLabel(timestamp)
diff --git a/fda-ui/pages/container/index.vue b/fda-ui/pages/container/index.vue
index f2036ed2d7a95b6aa88f5c01e3189d6696130986..b439563e202f6e6eea3439da3efce5da89d885a9 100644
--- a/fda-ui/pages/container/index.vue
+++ b/fda-ui/pages/container/index.vue
@@ -2,67 +2,16 @@
   <div>
     <v-toolbar flat>
       <v-toolbar-title>
-        <span>Databases</span>
+        Recent Databases
       </v-toolbar-title>
       <v-spacer />
       <v-toolbar-title>
-        <v-btn v-if="isResearcher" color="primary" @click.stop="createDbDialog = true">
+        <v-btn v-if="isResearcher" color="primary" name="create-database" @click.stop="createDbDialog = true">
           <v-icon left>mdi-plus</v-icon> Database
         </v-btn>
       </v-toolbar-title>
     </v-toolbar>
-    <v-toolbar dense flat>
-      <v-toolbar-items>
-        <span class="mr-4">Filter:</span>
-        <v-checkbox
-          v-model="filterPrivate"
-          label="Private" />
-        <v-checkbox
-          v-if="user"
-          v-model="filterMine"
-          class="ml-2"
-          label="Mine" />
-      </v-toolbar-items>
-    </v-toolbar>
-    <v-progress-linear v-if="loadingContainers || loadingDatabases" :color="loadingColor" :indeterminate="!error" />
-    <v-card
-      v-for="(container, idx) in filter(containers)"
-      :key="idx"
-      :to="link(container)"
-      :disabled="!container.database"
-      flat
-      tile>
-      <v-divider class="mx-4" />
-      <v-card-title v-if="notInit(container)" v-text="container.name" />
-      <v-card-title v-if="!notInit(container)">
-        <a :href="`/container/${container.id}/database/${container.database.id}`">{{ container.name }}</a>
-      </v-card-title>
-      <v-card-subtitle v-if="!container.database.identifier" class="db-subtitle" v-text="formatCreator(container.creator)" />
-      <v-card-subtitle v-if="container.database.identifier" class="db-subtitle" v-text="formatCreatorz(container)" />
-      <v-card-text class="db-description">
-        <div class="db-tags">
-          <v-chip v-if="!notInit(container) && container.database.is_public" small color="green" outlined>Public</v-chip>
-          <v-chip v-if="!notInit(container) && !container.database.is_public" small color="red" outlined>Private</v-chip>
-          <v-chip v-if="identifierCreated(container)" small outlined>Database</v-chip>
-          <v-chip
-            v-if="identifierCreated(container)"
-            small
-            outlined
-            v-text="container.database.identifier.publisher" />
-          <v-chip v-if="identifierCreated(container)" small outlined v-text="identifierCreated(container)" />
-        </div>
-        <div v-text="identifierDescription(container)" />
-      </v-card-text>
-      <v-card-text v-if="canInit(container)" class="db-buttons">
-        <v-btn
-          small
-          secondary
-          :loading="container.database.loading"
-          @click.stop="initDatabase(container)">
-          Start
-        </v-btn>
-      </v-card-text>
-    </v-card>
+    <DatabaseList ref="databases" />
     <v-dialog
       v-model="createDbDialog"
       persistent
@@ -75,22 +24,19 @@
 <script>
 import { mdiDatabaseArrowRightOutline } from '@mdi/js'
 import CreateDB from '@/components/dialogs/CreateDB'
-import { formatTimestampUTCLabel, formatCreators, formatYearUTC, formatUser, isResearcher } from '@/utils'
+import DatabaseList from '@/components/DatabaseList'
+import { isResearcher } from '@/utils'
 
 export default {
   components: {
-    CreateDB
+    CreateDB,
+    DatabaseList
   },
   data () {
     return {
       loadingContainers: false,
       loadingCreate: false,
       createDbDialog: false,
-      databases: [],
-      containers: [],
-      filterPrivate: false,
-      filterMine: false,
-      searchQuery: null,
       createDatabaseDto: {
         name: null,
         is_public: true
@@ -104,18 +50,12 @@ export default {
     }
   },
   computed: {
-    loadingColor () {
-      return this.error ? 'red lighten-2' : 'primary'
-    },
     token () {
       return this.$store.state.token
     },
     user () {
       return this.$store.state.user
     },
-    isResearcher () {
-      return isResearcher(this.user)
-    },
     config () {
       if (this.token === null) {
         return {}
@@ -123,119 +63,12 @@ export default {
       return {
         headers: { Authorization: `Bearer ${this.token}` }
       }
+    },
+    isResearcher () {
+      return isResearcher(this.user)
     }
   },
-  mounted () {
-    this.loadContainers()
-      .then(() => this.loadDatabases())
-  },
   methods: {
-    formatCreator (creator) {
-      return formatUser(creator)
-    },
-    formatCreatorz (container) {
-      return formatCreators(container)
-    },
-    canInit (container) {
-      if (!this.token) {
-        return false
-      }
-      if (container.creator.username !== this.user.username) {
-        return false
-      }
-      return !container.database.id && !this.loadingDatabases
-    },
-    notInit (container) {
-      return !container.database.id
-    },
-    async initDatabase (container) {
-      await this.startContainer(container)
-        .then(() => this.createDatabase(container))
-    },
-    filter (containers) {
-      if (this.loadingDatabases) {
-        return []
-      }
-      let filtered = containers
-      if (this.filterPrivate) {
-        filtered = filtered.filter(c => !c.database.is_public)
-      }
-      if (this.user && this.filterMine) {
-        filtered = filtered.filter(c => c.creator.username === this.user.username)
-      }
-      return filtered
-    },
-    identifierCreated (container) {
-      if (!container.database.identifier) {
-        return null
-      }
-      return formatYearUTC(container.database.identifier.created)
-    },
-    identifierDescription (container) {
-      if (!container.database.identifier) {
-        return null
-      }
-      return container.database.identifier.description
-    },
-    async loadContainers () {
-      this.createDbDialog = false
-      try {
-        this.loadingContainers = true
-        const res = await this.$axios.get('/api/container/')
-        this.containers = res.data.map((container) => {
-          container.database = {
-            id: null,
-            loading: false
-          }
-          return container
-        })
-        console.debug('containers', this.containers)
-        this.error = false
-      } catch (err) {
-        console.error('containers', err)
-        this.error = true
-      }
-      this.loadingContainers = false
-    },
-    async loadDatabases () {
-      if (this.containers.length === 0) {
-        return
-      }
-      this.loadingDatabases = true
-      for (const container of this.containers) {
-        try {
-          const res = await this.$axios.get(`/api/container/${container.id}/database`, this.config)
-          for (const info of res.data) {
-            info.container_id = container.id
-            info.visibility = info.is_public
-            info.created = formatTimestampUTCLabel(info.created)
-            const filtered = this.containers.filter(c => c.id === container.id)[0]
-            filtered.database = info
-          }
-        } catch (err) {
-          if (err.response === undefined || err.response.status === undefined || err.response.status !== 401) {
-            console.error('Failed to load databases for container', err)
-          }
-        }
-      }
-      this.loadingDatabases = false
-      console.debug('containers with databases', this.containers)
-    },
-    async startContainer (container) {
-      try {
-        container.database.loading = true
-        const res = await this.$axios.put(`/api/container/${container.id}`, { action: 'start' }, this.config)
-        console.debug('started container', res.data)
-        this.error = false
-      } catch (error) {
-        const { status } = error.response
-        if (status !== 409) {
-          this.error = true
-          this.$toast.error('Failed to start container')
-        }
-      }
-      container.database.loading = false
-    },
     async createDatabase (container) {
       try {
         container.database.loading = true
@@ -255,30 +88,9 @@ export default {
     closed (event) {
       this.createDbDialog = false
       if (event.success) {
-        this.loadContainers()
-          .then(() => this.loadDatabases())
+        this.$refs.databases.loadContainers()
       }
-    },
-    link (container) {
-      if (!container.database || !container.database.id) {
-        return null
-      }
-      return `/container/${container.id}/database/${container.database.id}`
     }
   }
 }
 </script>
-<style scoped>
-  tbody tr {
-    cursor: pointer;
-  }
-  .v-chip:not(:first-child) {
-    margin-left: 8px;
-  }
-  .db-subtitle {
-    padding-bottom: 8px;
-  }
-  .db-tags {
-    margin-bottom: 8px;
-  }
-</style>
diff --git a/fda-ui/pages/forgot.vue b/fda-ui/pages/forgot.vue
index af20390b04503bc6484650995cb66b270b6b2f47..809139658b9b5bb04f1bb430a62b69ef4a03de14 100644
--- a/fda-ui/pages/forgot.vue
+++ b/fda-ui/pages/forgot.vue
@@ -18,6 +18,7 @@
                 v-model="data.username"
                 autocomplete="off"
                 autofocus
+                name="username"
                 label="Username" />
             </v-col>
           </v-row>
@@ -27,6 +28,7 @@
                 v-model="data.email"
                 autocomplete="off"
                 type="email"
+                name="email"
                 label="E-Mail Address" />
             </v-col>
           </v-row>
@@ -38,6 +40,7 @@
             :disabled="!valid || !formValid"
             color="primary"
             type="submit"
+            name="submit"
             @click="forgot">
             Reset password
           </v-btn>
diff --git a/fda-ui/pages/login.vue b/fda-ui/pages/login.vue
index c063503b9032528cfab050acd94800e930ed1a75..44ee3235cf09fd0e02f0e3e4eb09bd1f2a6a94fa 100644
--- a/fda-ui/pages/login.vue
+++ b/fda-ui/pages/login.vue
@@ -18,6 +18,7 @@
                 autocomplete="off"
                 autofocus
                 required
+                name="username"
                 :rules="[v => !!v || $t('Required')]"
                 label="Username *" />
             </v-col>
@@ -29,6 +30,7 @@
                 autocomplete="off"
                 type="password"
                 required
+                name="password"
                 :rules="[v => !!v || $t('Required')]"
                 label="Password *" />
             </v-col>
@@ -41,6 +43,7 @@
             :disabled="!valid"
             color="primary"
             type="submit"
+            name="submit"
             :loading="loading"
             @click="login">
             Login
diff --git a/fda-ui/pages/search/index.vue b/fda-ui/pages/search/index.vue
index a6d5489897dd90fa00ffa80b667cf9e2454b3dd5..a466a0f9229d395bfd03be5e671e250eec482079 100644
--- a/fda-ui/pages/search/index.vue
+++ b/fda-ui/pages/search/index.vue
@@ -46,6 +46,12 @@ export default {
       }
       return this.$route.query.q
     },
+    type () {
+      if (!this.$route.query || !this.$route.query.t) {
+        return null
+      }
+      return this.$route.query.t
+    },
     header () {
       if (this.results.length !== 1) {
         return `${this.results.length} results`
@@ -64,7 +70,14 @@ export default {
   watch: {
     '$route.query.q': {
       handler (query) {
-        this.retrieve(query)
+        this.retrieve()
+      },
+      deep: true,
+      immediate: true
+    },
+    '$route.query.t': {
+      handler (type) {
+        this.retrieve()
       },
       deep: true,
       immediate: true
@@ -76,13 +89,13 @@ export default {
     }
   },
   methods: {
-    async retrieve (v) {
+    async retrieve () {
       if (this.loading) {
         return
       }
       this.loading = true
       try {
-        const res = await this.$axios.get(`/retrieve/databaseindex,tableindex,columnindex,identifierindex,viewindex/_search?q=${v}*&terminate_after=50`, this.elasticConfig)
+        const res = await this.$axios.get(`/retrieve/_all/_search?q=${this.query}*&terminate_after=50`, this.elasticConfig)
         console.info('search results', res.data.hits.total.value)
         console.debug('search results for', this.$route.query.q, 'are', res.data.hits.hits)
         this.results = res.data.hits.hits.map(h => h._source)
diff --git a/fda-ui/pages/signup.vue b/fda-ui/pages/signup.vue
index d777c2b568f46725f0527491e390bc94ce65713e..2b88602a4e7b006558a5f5759771a9c2dcbde622 100644
--- a/fda-ui/pages/signup.vue
+++ b/fda-ui/pages/signup.vue
@@ -20,6 +20,7 @@
                 autocomplete="off"
                 autofocus
                 required
+                name="email"
                 :rules="[v => !!v || $t('Required')]"
                 hint="e.g. max.mustermann@work.com"
                 label="Work E-Mail Address *" />
@@ -31,6 +32,7 @@
                 v-model="createAccount.username"
                 autocomplete="off"
                 required
+                name="username"
                 :rules="[v => !!v || $t('Required'),
                          v => /^[a-z0-9]{3,}$/.test(v) || $t('Only lowercase letters, min. 3 length')]"
                 hint="e.g. mmustermann"
@@ -43,6 +45,7 @@
                 v-model="createAccount.password"
                 autocomplete="off"
                 required
+                name="password"
                 :rules="[v => !!v || $t('Required')]"
                 type="password"
                 label="Password *" />
@@ -54,6 +57,7 @@
                 v-model="password2"
                 autocomplete="off"
                 required
+                name="password-confirm"
                 :rules="[v => !!v || $t('Required'), v => (!!v && v) === createAccount.password || $t('Not matching!')]"
                 type="password"
                 label="Repeat Password *" />
@@ -64,6 +68,7 @@
               <v-checkbox
                 v-model="consent"
                 required
+                name="consent"
                 :rules="[v => !!v || $t('Required')]"
                 label="I understand the warning and do not use production data" />
             </v-col>
@@ -73,6 +78,7 @@
               <v-checkbox
                 v-model="privacy"
                 required
+                name="privacy"
                 :rules="[v => !!v || $t('Required')]"
                 label="I have read and accept the privacy statement" />
             </v-col>
@@ -84,6 +90,7 @@
             :disabled="!valid"
             color="primary"
             type="submit"
+            name="submit"
             :loading="loading"
             @click="register">
             Submit
diff --git a/fda-ui/test/e2e/database.js b/fda-ui/test/e2e/database.js
index 1820f89fbf91fa90839baa5c082e46e1b2b41798..15a86e980b777905aa866d6162fd4976371905a2 100644
--- a/fda-ui/test/e2e/database.js
+++ b/fda-ui/test/e2e/database.js
@@ -1,63 +1,24 @@
 const test = require('ava')
-const axios = require('axios')
+const { mutations } = require('store')
 const { pageMacro, before, after } = require('./_utils')
 
 test.before(before)
 test.after(after)
 
-test('create database and see the tabs', pageMacro, async (t, page) => {
-  const database = 'Test Database ' + Math.random().toString(36).substring(7)
-  const description = 'Test Description'
-
-  await page.go('/databases')
-
-  // Click create new button
-  await page.click('button:has-text("Database")')
-
-  // Fill database name
-  await page.fill('input[name="database"]', database)
-
-  // Fill database description
-  await page.fill('textarea[name="description"]', description)
-
-  // Press Tab
-  await page.press('textarea[name="description"]', 'Tab')
-
-  // Select mariadb:10.5
-  await page.press('#engine', 'ArrowDown')
-
-  // Click submit button
-  await page.click('button:has-text("Create")')
-
-  // See page load
-  let success = await page.waitForSelector('text=' + database)
-  t.true(!!success, `Database ${database} seems not to be created, notification not found`)
-
-  const id = await axios.get('http://localhost:9092/api/database/').then(function (response) {
-    return response.filter(function (item) {
-      return item.name === database
-    }).id
-  })
-
-  // -------------------------------------------------------------------------------------------------------------------
-
-  await page.go('/databases/' + id + '/info')
-
-  // find 'mariadb' anywhere on the page:
-  success = await page.waitForSelector('text=mariadb:10.5')
-  t.true(!!success, 'Could not find the mariadb image on the site')
-
-  await page.go('/databases/' + id + '/tables')
-
-  // find 'mariadb' anywhere on the page:
-  success = await page.waitForSelector('text=(no tables)')
-  t.true(!!success, 'Could not find the tables on the site')
-
-  // -------------------------------------------------------------------------------------------------------------------
+test('databases_seeDatabases_succeeds', pageMacro, async (t, page) => {
+  await page.go('/container')
+  /* test */
+  const success = await page.waitForSelector('main >> header >> text=Databases')
+  t.true(!!success, 'Failed to find \'Databases\' in page')
+})
 
-  await page.go('/databases/' + id + '/queries')
+test('databases_createDatabase_succeeds', pageMacro, async (t, page) => {
+  const state = { token: null, user: null, database: null, table: null, access: null }
 
-  // find 'mariadb' anywhere on the page:
-  success = await page.waitForSelector('text=(no queries)')
-  t.true(!!success, 'Could not find the queries on the site')
+  await page.go('/container')
+  mutations.SET_TOKEN(state, 'ABC')
+  mutations.SET_USER(state, { username: 'ava' })
+  await page.screenshot({ path: './screenshots/databases_createDatabase_succeeds.png' })
+  /* test */
+  t.true(true)
 })
diff --git a/fda-ui/test/e2e/forgot.js b/fda-ui/test/e2e/forgot.js
new file mode 100644
index 0000000000000000000000000000000000000000..03c3415564e006031ec606d4be3c2b0948737b01
--- /dev/null
+++ b/fda-ui/test/e2e/forgot.js
@@ -0,0 +1,18 @@
+const test = require('ava')
+const { pageMacro, before, after } = require('./_utils')
+
+test.before(before)
+test.after(after)
+
+test('login_succeeds', pageMacro, async (t, page) => {
+  const email = 'ava@example.com'
+  const username = 'ava'
+
+  await page.go('/forgot')
+  await page.fill('input[name="username"]', username)
+  await page.fill('input[name="email"]', email)
+
+  /* test */
+  const success = await page.waitForSelector('button[name="submit"]:not([disabled])')
+  t.true(!!success, 'Failed to reset user information')
+})
diff --git a/fda-ui/test/e2e/index.js b/fda-ui/test/e2e/index.js
index ee391d1d6d52aa4d5a364a6da3c4ac4675dbb2c4..399bd9485ec9a043ac1638517c48e133ba936aff 100644
--- a/fda-ui/test/e2e/index.js
+++ b/fda-ui/test/e2e/index.js
@@ -4,7 +4,50 @@ const { pageMacro, before, after } = require('./_utils')
 test.before(before)
 test.after(after)
 
-test('visit homepage', pageMacro, async (t, page) => {
+test('home_seeDatabaseRepository_succeeds', pageMacro, async (t, page) => {
   await page.go('/')
-  t.is(await page.title(), 'FAIR Data Austria - Database Repository (Sandbox)')
+
+  // find 'Database Repository' anywhere on the page:
+  const success = await page.waitForSelector('text=Database Repository')
+  t.true(!!success, 'Failed to find \'Database Repository\' in page')
+})
+
+test('home_seeInformation_succeeds', pageMacro, async (t, page) => {
+  await page.go('/')
+
+  // find 'Information' anywhere on the page:
+  const success = await page.waitForSelector('text=Information')
+  t.true(!!success, 'Failed to find \'Information\' in page')
+})
+
+test('home_seeDatabases_succeeds', pageMacro, async (t, page) => {
+  await page.go('/')
+
+  // find 'Databases' anywhere on the page:
+  const success = await page.waitForSelector('text=Databases')
+  t.true(!!success, 'Failed to find \'Databases\' in page')
+})
+
+test('home_seeLogin_succeeds', pageMacro, async (t, page) => {
+  await page.go('/')
+
+  // find 'Login' anywhere on the page:
+  const success = await page.waitForSelector('text=Login')
+  t.true(!!success, 'Failed to find \'Login\' in page')
+})
+
+test('home_seeSignup_succeeds', pageMacro, async (t, page) => {
+  await page.go('/')
+
+  // find 'Signup' anywhere on the page:
+  const success = await page.waitForSelector('text=Signup')
+  t.true(!!success, 'Failed to find \'Signup\' in page')
+})
+
+test('home_seeSearch_succeeds', pageMacro, async (t, page) => {
+  await page.go('/')
+
+  // find 'Search' anywhere on the page:
+  const success = await page.waitForSelector('[placeholder="Search ..."]')
+  t.true(!!success, 'Failed to find \'Search\' in page')
 })
diff --git a/fda-ui/test/e2e/login.js b/fda-ui/test/e2e/login.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ddae6a394c3d1bccc933b8e8a6e7d1fa0e50552
--- /dev/null
+++ b/fda-ui/test/e2e/login.js
@@ -0,0 +1,18 @@
+const test = require('ava')
+const { pageMacro, before, after } = require('./_utils')
+
+test.before(before)
+test.after(after)
+
+test('login_succeeds', pageMacro, async (t, page) => {
+  const username = 'ava'
+  const password = Math.random().toString(36).substring(7)
+
+  await page.go('/login')
+  await page.fill('input[name="username"]', username)
+  await page.fill('input[name="password"]', password)
+
+  /* test */
+  const success = await page.waitForSelector('button[name="submit"]:not([disabled])')
+  t.true(!!success, 'Failed to login')
+})
diff --git a/fda-ui/test/e2e/search.js b/fda-ui/test/e2e/search.js
new file mode 100644
index 0000000000000000000000000000000000000000..b2fbc9868e30f8ec0caa4a6d0103c0ca271c3d05
--- /dev/null
+++ b/fda-ui/test/e2e/search.js
@@ -0,0 +1,28 @@
+const test = require('ava')
+const { pageMacro, before, after } = require('./_utils')
+
+test.before(before)
+test.after(after)
+
+test('search_succeeds', pageMacro, async (t, page) => {
+  const query = 'dummy'
+
+  await page.go('/')
+  await page.fill('input[placeholder="Search ..."]', query)
+
+  /* test */
+  const success = await page.waitForSelector('button[name="search-submit"]')
+  t.true(!!success, 'Failed to search')
+})
+
+test('search_execute_succeeds', pageMacro, async (t, page) => {
+  const query = 'dummy'
+
+  await page.go('/')
+  await page.fill('input[placeholder="Search ..."]', query)
+  await page.click('button[name="search-submit"]')
+
+  /* test */
+  const success = await page.waitForSelector('button[name="search-submit"]')
+  t.true(!!success, 'Failed to search')
+})
diff --git a/fda-ui/test/e2e/signup.js b/fda-ui/test/e2e/signup.js
new file mode 100644
index 0000000000000000000000000000000000000000..d25e27a274b212fc671dba8be5bd3f3990922ec4
--- /dev/null
+++ b/fda-ui/test/e2e/signup.js
@@ -0,0 +1,21 @@
+const test = require('ava')
+const { pageMacro, before, after } = require('./_utils')
+
+test.before(before)
+test.after(after)
+
+test('signup_succeeds', pageMacro, async (t, page) => {
+  const email = 'ava@example.com'
+  const username = 'ava'
+  const password = Math.random().toString(36).substring(7)
+
+  await page.go('/signup')
+  await page.fill('input[name="email"]', email)
+  await page.fill('input[name="username"]', username)
+  await page.fill('input[name="password"]', password)
+  await page.fill('input[name="password-confirm"]', password)
+
+  /* test */
+  const success = await page.waitForSelector('button[name="submit"]:not([disabled])')
+  t.true(!!success, 'Failed to sign-up')
+})
diff --git a/fda-ui/test/e2e/tables.js b/fda-ui/test/e2e/tables.js
deleted file mode 100644
index 208280da7730b141049532b2e1dc73c8866ea02d..0000000000000000000000000000000000000000
--- a/fda-ui/test/e2e/tables.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const test = require('ava')
-const axios = require('axios')
-const { pageMacro, before, after } = require('./_utils')
-
-test.before(before)
-test.after(after)
-
-test('create table using form', pageMacro, async (t, page) => {
-  const database = 'Test Database ' + Math.random().toString(36).substring(7)
-  const table = 'Test Table ' + Math.random().toString(36).substring(7)
-  const description = 'Test Description'
-
-  await page.go('/databases')
-
-  // Click create new button
-  await page.click('button:has-text("Database")')
-
-  // Fill database name
-  await page.fill('input[name="database"]', database)
-
-  // Fill database description
-  await page.fill('textarea[name="description"]', description)
-
-  // Press Tab
-  await page.press('textarea[name="description"]', 'Tab')
-
-  // Select mariadb:10.5
-  await page.press('#engine', 'ArrowDown')
-
-  // Click submit button
-  await page.click('button:has-text("Create")')
-
-  // See page load
-  let success = await page.waitForSelector('text=' + database)
-  t.true(!!success, `Database ${database} seems not to be created, notification not found`)
-
-  const id = await axios.get('http://localhost:9092/api/database/').then(function (response) {
-    return response.filter(function (item) {
-      return item.name === database
-    }).id
-  })
-
-  // -------------------------------------------------------------------------------------------------------------------
-
-  await page.go('/databases/' + id + '/tables')
-
-  // Click create new button
-  await page.click('button:has-text("Create Table")')
-
-  // Fill table name
-  await page.fill('input[name="name"]', table)
-
-  // Fill table description
-  await page.fill('input[name="description"]', description)
-
-  // Click submit button
-  await page.click('button:has-text("Create Table")')
-
-  // See page load
-  success = await page.waitForSelector('text=aaaaaaaa')
-  t.true(!!success, `Table ${database} seems not to be created, notification not found`)
-})
diff --git a/fda-ui/test/unit/query.js b/fda-ui/test/unit/query.js
index af97f551459143ea52318666258bae5387e0a0a0..1721491863978b8b2ee50141700991768a852504 100644
--- a/fda-ui/test/unit/query.js
+++ b/fda-ui/test/unit/query.js
@@ -1,14 +1,14 @@
 const test = require('ava')
 const { buildQuery, castNum } = require('@/server-middleware/query')
 
-test('simple select', (t) => {
+test('buildQuery_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table'
   })
   t.is(r.sql, 'select * from `Table`')
 })
 
-test('select some columns', (t) => {
+test('buildQuery_columns_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table',
     select: ['database', 'bbb']
@@ -16,7 +16,7 @@ test('select some columns', (t) => {
   t.is(r.sql, 'select `database`, `bbb` from `Table`')
 })
 
-test('simple where clause', (t) => {
+test('buildQuery_where_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -26,7 +26,7 @@ test('simple where clause', (t) => {
   t.is(r.sql, 'select * from `Table` where `foo` = 42')
 })
 
-test('simple where clause with numeric string', (t) => {
+test('buildQuery_whereNumeric_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -36,7 +36,7 @@ test('simple where clause with numeric string', (t) => {
   t.is(r.sql, 'select * from `Table` where `foo` = 42')
 })
 
-test('simple where clause with non-numeric string', (t) => {
+test('buildQuery_whereString_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -46,7 +46,7 @@ test('simple where clause with non-numeric string', (t) => {
   t.is(r.sql, 'select * from `Table` where `foo` = \'bla\'')
 })
 
-test('using unallowed operator', (t) => {
+test('buildQuery_illegalOperator_fails', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -57,7 +57,7 @@ test('using unallowed operator', (t) => {
   t.is(r.error, 'The operator "UNKNOWN" is not permitted')
 })
 
-test('where clause with explicit `and`', (t) => {
+test('buildQuery_whereAndExplicit_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -69,7 +69,7 @@ test('where clause with explicit `and`', (t) => {
   t.is(r.sql, 'select * from `Table` where `foo` = 42 and `bar` = 42')
 })
 
-test('where clause with implicit `and`', (t) => {
+test('buildQuery_whereAndImplicit_succeeds', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -81,7 +81,7 @@ test('where clause with implicit `and`', (t) => {
   t.is(r.sql, 'select * from `Table` where `foo` = 42 and `bar` = 42')
 })
 
-test('where clause with `or`', (t) => {
+test('buildQuery_whereOr', (t) => {
   const r = buildQuery({
     table: 'Table',
     clauses: [
@@ -93,7 +93,7 @@ test('where clause with `or`', (t) => {
   t.is(r.sql, 'select * from `Table` where `foo` = 42 or `bar` = 42')
 })
 
-test('cast numeric strings to numbers', (t) => {
+test('castNum_succeeds', (t) => {
   t.is(castNum(''), '')
   t.is(castNum(' '), ' ')
   t.is(castNum('0'), 0)
diff --git a/fda-ui/test/unit/utils.js b/fda-ui/test/unit/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..4b6a0f0be00d091b169c13c70a1b5daf55d708be
--- /dev/null
+++ b/fda-ui/test/unit/utils.js
@@ -0,0 +1,279 @@
+const test = require('ava')
+const {
+  isNonNegativeInteger,
+  isDeveloper,
+  isResearcher,
+  isDataSteward,
+  formatUser,
+  formatDateUTC,
+  formatYearUTC,
+  formatMonthUTC,
+  formatDayUTC,
+  formatTimestamp,
+  formatCreators,
+  formatTimestampUTCLabel,
+  formatTimestampUTC
+} = require('@/utils')
+
+test('isNonNegativeInteger_succeeds', (t) => {
+  /* test */
+  const response = isNonNegativeInteger('1')
+  t.is(response, true)
+})
+
+test('isNonNegativeInteger_zero_succeeds', (t) => {
+  /* test */
+  const response = isNonNegativeInteger('0')
+  t.is(response, true)
+})
+
+test('isNonNegativeInteger_fails', (t) => {
+  /* test */
+  const response = isNonNegativeInteger('-1')
+  t.is(response, false)
+})
+
+test('isDeveloper_succeeds', (t) => {
+  const user = { roles: ['ROLE_DEVELOPER'] }
+  /* test */
+  const response = isDeveloper(user)
+  t.is(response, true)
+})
+
+test('isDeveloper_fails', (t) => {
+  const user = { roles: [] }
+  /* test */
+  const response = isDeveloper(user)
+  t.is(response, false)
+})
+
+test('isDeveloper_otherRole_fails', (t) => {
+  const user = { roles: ['ROLE_RESEARCHER'] }
+  /* test */
+  const response = isDeveloper(user)
+  t.is(response, false)
+})
+
+test('isResearcher_succeeds', (t) => {
+  const user = { roles: ['ROLE_RESEARCHER'] }
+  /* test */
+  const response = isResearcher(user)
+  t.is(response, true)
+})
+
+test('isResearcher_fails', (t) => {
+  const user = { roles: [] }
+  /* test */
+  const response = isResearcher(user)
+  t.is(response, false)
+})
+
+test('isResearcher_otherRole_fails', (t) => {
+  const user = { roles: ['ROLE_DEVELOPER'] }
+  /* test */
+  const response = isResearcher(user)
+  t.is(response, false)
+})
+
+test('isDataSteward_succeeds', (t) => {
+  const user = { roles: ['ROLE_DATA_STEWARD'] }
+  /* test */
+  const response = isDataSteward(user)
+  t.is(response, true)
+})
+
+test('isDataSteward_fails', (t) => {
+  const user = { roles: [] }
+  /* test */
+  const response = isDataSteward(user)
+  t.is(response, false)
+})
+
+test('isDataSteward_otherRole_fails', (t) => {
+  const user = { roles: ['ROLE_DEVELOPER'] }
+  /* test */
+  const response = isDataSteward(user)
+  t.is(response, false)
+})
+
+test('formatUser_fails', (t) => {
+  const user = null
+  /* test */
+  const response = formatUser(user)
+  t.is(response, null)
+})
+
+test('formatUser_usernameMissing_fails', (t) => {
+  const user = { lastname: null, firstname: null }
+  /* test */
+  const response = formatUser(user)
+  t.is(response, null)
+})
+
+test('formatUser_succeeds', (t) => {
+  const user = { lastname: null, firstname: null, username: 'mweise' }
+  /* test */
+  const response = formatUser(user)
+  t.is(response, 'mweise')
+})
+
+test('formatUser_firstnameLastname_succeeds', (t) => {
+  const user = { lastname: 'Martin', firstname: 'Weise', username: 'mweise' }
+  /* test */
+  const response = formatUser(user)
+  t.is(response, 'Weise Martin')
+})
+
+test('formatUser_titles_succeeds', (t) => {
+  const user = { lastname: 'Martin', firstname: 'Weise', username: 'mweise', titles_before: 'Dipl.-Ing.', titles_after: 'BSc' }
+  /* test */
+  const response = formatUser(user)
+  t.is(response, 'Dipl.-Ing. Weise Martin BSc')
+})
+
+test('formatDateUTC_succeeds', (t) => {
+  /* test */
+  const response = formatDateUTC('2023-02-15 10:32:21')
+  t.is(response, '2023-02-15')
+})
+
+test('formatDateUTC_fails', (t) => {
+  /* test */
+  const response = formatDateUTC(null)
+  t.is(response, null)
+})
+
+test('formatYearUTC_fails', (t) => {
+  /* test */
+  const response = formatYearUTC(null)
+  t.is(response, null)
+})
+
+test('formatYearUTC_succeeds', (t) => {
+  /* test */
+  const response = formatYearUTC('2023-02-15 10:32:21')
+  t.is(response, '2023')
+})
+
+test('formatMonthUTC_fails', (t) => {
+  /* test */
+  const response = formatMonthUTC(null)
+  t.is(response, null)
+})
+
+test('formatMonthUTC_succeeds', (t) => {
+  /* test */
+  const response = formatMonthUTC('2023-02-15 10:32:21')
+  t.is(response, '02')
+})
+
+test('formatDayUTC_fails', (t) => {
+  /* test */
+  const response = formatDayUTC(null)
+  t.is(response, null)
+})
+
+test('formatDayUTC_succeeds', (t) => {
+  /* test */
+  const response = formatDayUTC('2023-02-15 10:32:21')
+  t.is(response, '15')
+})
+
+test('formatTimestamp_fails', (t) => {
+  /* test */
+  const response = formatTimestamp(null)
+  t.is(response, null)
+})
+
+test('formatTimestamp_succeeds', (t) => {
+  /* test */
+  const response = formatTimestamp('2023-02-15 10:32:21')
+  t.is(response, '2023-02-15 10:32:21')
+})
+
+test('formatCreators_containerMissing_fails', (t) => {
+  const container = null
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, null)
+})
+
+test('formatCreators_databaseMissing_fails', (t) => {
+  const container = { }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, null)
+})
+
+test('formatCreators_identifierMissing_fails', (t) => {
+  const container = { database: { } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, null)
+})
+
+test('formatCreators_creatorsMissing_fails', (t) => {
+  const container = { database: { identifier: { } } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, null)
+})
+
+test('formatCreators_identifierNull_fails', (t) => {
+  const container = { database: { identifier: null } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, null)
+})
+
+test('formatCreators_creatorsEmpty_fails', (t) => {
+  const container = { database: { identifier: { creators: [] } } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, null)
+})
+
+test('formatCreators_single_succeeds', (t) => {
+  const container = { database: { identifier: { creators: [{ firstname: 'Martin', lastname: 'Weise' }] } } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, 'M., Weise')
+})
+
+test('formatCreators_double_succeeds', (t) => {
+  const container = { database: { identifier: { creators: [{ firstname: 'Martin', lastname: 'Weise' }, { firstname: 'Tobias', lastname: 'Grantner' }] } } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, 'M., Weise, & T., Grantner')
+})
+
+test('formatCreators_multiple_succeeds', (t) => {
+  const container = { database: { identifier: { creators: [{ firstname: 'Martin', lastname: 'Weise' }, { firstname: 'Tobias', lastname: 'Grantner' }, { firstname: 'Josef', lastname: 'Taha' }] } } }
+  /* test */
+  const response = formatCreators(container)
+  t.is(response, 'M., Weise, T., Grantner, & J., Taha')
+})
+
+test('formatTimestampUTCLabel_succeeds', (t) => {
+  /* test */
+  const response = formatTimestampUTCLabel('2023-02-15 10:32:21')
+  t.is(response, '2023-02-15 09:32:21 (UTC)')
+})
+
+test('formatTimestampUTCLabel_fails', (t) => {
+  /* test */
+  const response = formatTimestampUTCLabel(null)
+  t.is(response, null)
+})
+
+test('formatTimestampUTC_fails', (t) => {
+  /* test */
+  const response = formatTimestampUTC(null)
+  t.is(response, null)
+})
+
+test('formatTimestampUTC_succeeds', (t) => {
+  /* test */
+  const response = formatTimestampUTC('2023-02-15 10:32:21')
+  t.is(response, '2023-02-15 09:32:21')
+})
diff --git a/fda-ui/utils/index.js b/fda-ui/utils/index.js
index 5e8dde78716edfb27d7341feb5ec45592a921bc9..2cb3310639179d677ae038562ba7be92a03504c8 100644
--- a/fda-ui/utils/index.js
+++ b/fda-ui/utils/index.js
@@ -53,10 +53,10 @@ function formatUser (user) {
   if (!user) {
     return null
   }
-  if (!('firstname' in user) || !('lastname' in user)) {
-    return user.username
-  }
-  if (user.firstname === null || user.lastname === null) {
+  if (!('firstname' in user) || !('lastname' in user) || user.firstname === null || user.lastname === null) {
+    if (!('username' in user)) {
+      return null
+    }
     return user.username
   }
   let name = ''
@@ -70,13 +70,6 @@ function formatUser (user) {
   return name
 }
 
-function padLeft (str, padString, length) {
-  while (str.length < length) {
-    str = padString + str
-  }
-  return str
-}
-
 function formatDateUTC (str) {
   if (str === null) {
     return null
@@ -117,8 +110,8 @@ function formatTimestamp (str) {
 }
 
 function formatCreators (container) {
-  if (!container.database.identifier || !container.database.identifier.creators) {
-    return ''
+  if (!container || !('database' in container) || !('identifier' in container.database) || !container.database.identifier || !('creators' in container.database.identifier) || !container.database.identifier.creators) {
+    return null
   }
   const creators = container.database.identifier.creators
   if (creators.length === 0) {
@@ -127,8 +120,8 @@ function formatCreators (container) {
   let str = ''
   for (let i = 0; i < creators.length; i++) {
     /* separator */
-    if (i > 0 && creators.length === 2) {
-      str += ' & '
+    if (creators.length > 1 && i === creators.length - 1) {
+      str += ', & '
     } else if (i > 0 && creators.length !== 2) {
       str += ', '
     }
@@ -170,7 +163,6 @@ module.exports = {
   formatYearUTC,
   formatMonthUTC,
   formatDayUTC,
-  padLeft,
   formatCreators,
   isDeveloper,
   isResearcher,
diff --git a/fda-ui/yarn.lock b/fda-ui/yarn.lock
index e302f9ae08538f8432dbf7fe79485fca4dc56503..421217b621020514a9f20925a4ba668b5d2735c6 100644
--- a/fda-ui/yarn.lock
+++ b/fda-ui/yarn.lock
@@ -2767,6 +2767,15 @@ axios@^0.21.1:
   dependencies:
     follow-redirects "^1.14.0"
 
+axios@^1.3.0:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.3.tgz#e7011384ba839b885007c9c9fae1ff23dceb295b"
+  integrity sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==
+  dependencies:
+    follow-redirects "^1.15.0"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
 babel-eslint@^10.1.0:
   version "10.1.0"
   resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@@ -5639,6 +5648,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.0:
   resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
   integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
 
+follow-redirects@^1.15.0:
+  version "1.15.2"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
+  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
 for-in@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -5661,6 +5675,15 @@ form-data@^3.0.0:
     combined-stream "^1.0.8"
     mime-types "^2.1.12"
 
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
 forwarded@0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -10091,6 +10114,11 @@ proxy-addr@~2.0.7:
     forwarded "0.2.0"
     ipaddr.js "1.9.1"
 
+proxy-from-env@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+  integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
 prr@~1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"