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 36fb8d753994b88376b278622de69351a108abdf..ae9e683f84116b3457f7a61d93748f2e47c31c2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,10 +3,11 @@ target/
 !.mvn/wrapper/maven-wrapper.jar
 !**/src/main/**/target/
 !**/src/test/**/target/
-
+dbrepo-*
 # Notebooks
 .jupyter/
 .pytest_cache/
+__pycache__/
 
 # demo
 .demo
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/.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 8dffa725c1febcd0ce08eb324b3d152a7ee37b5c..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
@@ -295,14 +295,16 @@ services:
     networks:
       core:
       public:
+    ports:
+      - "3000:3000"
     env_file:
       - .env
     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-analyse-service/coverage.txt b/fda-analyse-service/coverage.txt
deleted file mode 100644
index bd9242486b093b8e72178a4ea40d827b672b6788..0000000000000000000000000000000000000000
--- a/fda-analyse-service/coverage.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Name                        Stmts   Miss  Cover
------------------------------------------------
-determine_dt.py                56     16    71%
-determine_pk.py                49      0   100%
-test/__init__.py                0      0   100%
-test/test_determine_dt.py      34      7    79%
-test/test_determine_pk.py      41      1    98%
------------------------------------------------
-TOTAL                         180     24    87%
diff --git a/fda-analyse-service/report.xml b/fda-analyse-service/report.xml
deleted file mode 100644
index 5495aa234b14a375786b0e8c9c482875c2573e2b..0000000000000000000000000000000000000000
--- a/fda-analyse-service/report.xml
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="12" time="1.131" timestamp="2023-01-26T09:31:19.024531" hostname="medusa"><testcase classname="test.test_determine_dt.DetermineDatatypesTest" name="test_determine_datatypes_fileDoesNotExist_fails" time="0.001" /><testcase classname="test.test_determine_dt.DetermineDatatypesTest" name="test_determine_datatypes_fileEmpty_fails" time="0.002" /><testcase classname="test.test_determine_dt.DetermineDatatypesTest" name="test_determine_datatypes_separatorSemicolon_succeeds" time="0.004" /><testcase classname="test.test_determine_dt.DetermineDatatypesTest" name="test_determine_datatypes_succeeds" time="0.166" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_largeFileIdFirst_succeeds" time="0.073" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_largeFileIdInBetween_succeeds" time="0.072" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_largeFileNoPrimaryKey_fails" time="0.062" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_largeFileNullInUnique_fails" time="0.106" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_smallFileIdFirst_fails" time="0.013" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_smallFileIdIntBetween_fails" time="0.013" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_smallFileNoPrimaryKey_fails" time="0.011" /><testcase classname="test.test_determine_pk.DeterminePrimaryKeyTest" name="test_determine_pk_smallFileNullInUnique_fails" time="0.012" /></testsuite></testsuites>
\ No newline at end of file
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-discovery-service/rest-service/ready b/fda-discovery-service/rest-service/ready
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
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 9503fa90bf5417dc186c9eb07c63a3acf1735554..ff4afcc63083db7e0b0de80b0fe4cfc69b88c8da 100644
--- a/fda-metadata-db/setup-schema.sql
+++ b/fda-metadata-db/setup-schema.sql
@@ -402,7 +402,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 5df209241867821d3efc77320d363c49420a091a..05746427c70f6e306974911ae7778d970da6019e 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
@@ -301,12 +301,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"};
@@ -329,8 +339,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"};
@@ -353,8 +363,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"));
@@ -374,8 +384,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"));
@@ -395,9 +405,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()
@@ -419,7 +429,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);
 
@@ -435,6 +445,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";
@@ -1003,9 +1035,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;
 
@@ -1014,9 +1047,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()
@@ -1050,6 +1086,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);
@@ -1060,9 +1097,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_2_COLUMNS = List.of(TableColumn.builder()
@@ -2056,6 +2096,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)
@@ -2189,6 +2243,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";
@@ -2227,7 +2295,7 @@ public abstract class BaseUnitTest {
     public final static Long VIEW_2_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_2_DATABASE_ID = DATABASE_1_ID;
     public final static Boolean VIEW_2_PUBLIC = true;
-    public final static String VIEW_2_QUERY = "select `date`, `location`, `mintemp`, `rainfall` from `weather_aus`";
+    public final static String VIEW_2_QUERY = "select `date`, `location`, `mintemp`, `rainfall` from `weather_aus` where `location` = 'Albury'";
 
     public final static View VIEW_2 = View.builder()
             .id(VIEW_2_ID)
@@ -2258,7 +2326,7 @@ public abstract class BaseUnitTest {
     public final static Long VIEW_3_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_3_DATABASE_ID = DATABASE_1_ID;
     public final static Boolean VIEW_3_PUBLIC = false;
-    public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`lat`, m.`lng` from `weather_aus` w join `mock_view` m on m.`location` = w.`location`";
+    public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`lat`, m.`lng` from `weather_aus` w join `junit2` m on m.`location` = w.`location`";
 
     public final static View VIEW_3 = View.builder()
             .id(VIEW_3_ID)
@@ -2313,8 +2381,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()
@@ -2348,7 +2416,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 c5809d8aa80f3b8e83bfda2eaf6e9fe2d2ecb4f6..ff2b07d0c10f0b07052c128bea344c24a1f53c72 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);
         });
     }
 
@@ -374,7 +362,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
@@ -392,8 +380,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
@@ -526,7 +514,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..eed98297653d5f527f7a4604b00a68b84bff61e6 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,22 +2,19 @@ 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;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.rabbitmq.client.*;
 import lombok.extern.log4j.Log4j2;
-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.*;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -27,9 +24,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 +53,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 +87,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 +195,18 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
         channel.basicPublish(DATABASE_1_EXCHANGE, TABLE_1_ROUTING_KEY, basicProperties, objectMapper.writeValueAsBytes(TABLE_1_CSV_DTO));
     }
 
+    @Test
+    @Disabled("Not testable")
+    public void restore_succeeds() throws AmqpException, IOException {
+
+        /* mock */
+        when(tableRepository.findAll())
+                .thenReturn(List.of(TABLE_1));
+
+        /* test */
+        messageQueueService.restore();
+        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..29e074c8f21a6dd864d6e3c1a3504a588c6d0163 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,17 +9,15 @@ 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;
 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.springframework.beans.factory.annotation.Autowired;
@@ -30,12 +28,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 +56,14 @@ public class ViewServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private ViewIdxRepository viewIdxRepository;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private DatabaseRepository databaseRepository;
 
@@ -93,13 +94,19 @@ public class ViewServiceIntegrationTest 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_2, VIEW_3));
+    }
+
     @Test
     public void create_viewJoinOnView_succeeds() throws DatabaseNotFoundException, UserNotFoundException,
             DatabaseConnectionException, ViewMalformedException, QueryMalformedException, SQLException {
         final ViewCreateDto request = ViewCreateDto.builder()
-                .name(VIEW_3_NAME)
+                .name("Debug")
                 .query(VIEW_3_QUERY)
-                .isPublic(VIEW_3_PUBLIC)
+                .isPublic(true)
                 .build();
 
         /* mock */
@@ -119,7 +126,7 @@ public class ViewServiceIntegrationTest extends BaseUnitTest {
         assertEquals(VIEW_3_INTERNAL_NAME, response.getInternalName());
         assertEquals(VIEW_3_QUERY, response.getQuery());
         final List<Map<String, String>> resultSet = MariaDbConfig.selectQuery(CONTAINER_1_INTERNALNAME, DATABASE_1_INTERNALNAME,
-                "SELECT j.* FROM `junit3` j", "mintemp", "rainfall", "location", "lat", "lng");
+                "SELECT j.* FROM `debug` j", "mintemp", "rainfall", "location", "lat", "lng");
         assertEquals("13.4", resultSet.get(0).get("mintemp"));
         assertEquals("0.6", resultSet.get(0).get("rainfall"));
         assertEquals("Albury", resultSet.get(0).get("location"));
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/weather/2_weather.sql b/fda-query-service/rest-service/src/test/resources/weather/2_weather.sql
index 3d352607f1c3cacbbd80a7f18df7ad5881c664a2..29967f2977ef6b6f12da00b0c218382e5c024322 100644
--- a/fda-query-service/rest-service/src/test/resources/weather/2_weather.sql
+++ b/fda-query-service/rest-service/src/test/resources/weather/2_weather.sql
@@ -39,7 +39,7 @@ VALUES (1, '2008-12-01', 'Albury', 13.4, 0.6),
 ## TEST CASE PRE-REQUISITE                                                                                            ##
 ########################################################################################################################
 
-CREATE VIEW mock_view AS
+CREATE VIEW junit2 AS
 (
 SELECT `location`, `lat`, `lng`
 FROM `weather_location`
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..0ab98c4ebee9a2cf549e04be3e5782e3de4e39e7 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,13 +123,20 @@ 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);
             createViewStatement.executeUpdate();
         } catch (SQLException e) {
             log.error("Failed to create view: {}", e.getMessage());
-            throw new ViewMalformedException("Failed to create view", e);
+            throw new ViewMalformedException("Failed to create view: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
@@ -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-semantics-service/.coverage b/fda-semantics-service/.coverage
deleted file mode 100644
index 71d9c3ff33f4130c7b3a4a880b8162ec161f96fb..0000000000000000000000000000000000000000
Binary files a/fda-semantics-service/.coverage and /dev/null differ
diff --git a/fda-semantics-service/coverage.txt b/fda-semantics-service/coverage.txt
deleted file mode 100644
index dbcdea6c85914de1708358021d8cf4e9b3be8b81..0000000000000000000000000000000000000000
--- a/fda-semantics-service/coverage.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Name                    Stmts   Miss  Cover
--------------------------------------------
-app.py                    132     71    46%
-list.py                    56      0   100%
-onto_feat.py               41     26    37%
-save.py                    31     26    16%
-test/__init__.py            0      0   100%
-test/test_app.py           38      1    97%
-test/test_list.py          40      1    98%
-test/test_validate.py      18      1    94%
-validate.py                21      0   100%
--------------------------------------------
-TOTAL                     377    126    67%
diff --git a/fda-semantics-service/report.xml b/fda-semantics-service/report.xml
deleted file mode 100644
index cf16f04fdeab656dd38e42ddf7d9435be3f81012..0000000000000000000000000000000000000000
--- a/fda-semantics-service/report.xml
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="18" time="85.067" timestamp="2023-01-26T09:41:09.876196" hostname="medusa"><testcase classname="test.test_validate.ValidatorUnitTest" name="test_validator_dividedunit" time="0.006" /><testcase classname="test.test_validate.ValidatorUnitTest" name="test_validator_misspelling" time="0.003" /><testcase classname="test.test_validate.ValidatorUnitTest" name="test_validator_no_SI_Unit" time="0.002" /><testcase classname="test.test_validate.ValidatorUnitTest" name="test_validator_prefixedunit" time="0.002" /><testcase classname="test.test_validate.ValidatorUnitTest" name="test_validator_true" time="0.002" /><testcase classname="test.test_list.ListUnitTest" name="test_get_concept_uri_hasSpaces_succeeds" time="22.945" /><testcase classname="test.test_list.ListUnitTest" name="test_get_concept_uri_succeeds" time="24.992" /><testcase classname="test.test_list.ListUnitTest" name="test_get_unit_uri_hasBraces_succeeds" time="0.239" /><testcase classname="test.test_list.ListUnitTest" name="test_get_unit_uri_succeeds" time="0.056" /><testcase classname="test.test_list.ListUnitTest" name="test_list_concepts_succeeds" time="19.513" /><testcase classname="test.test_list.ListUnitTest" name="test_list_units_fails" time="0.116" /><testcase classname="test.test_list.ListUnitTest" name="test_list_units_succeeds" time="0.066" /><testcase classname="test.test_app.AppUnitTest" name="test_save_concept_name_null_fails" time="0.004" /><testcase classname="test.test_app.AppUnitTest" name="test_save_concept_uri_and_name_null_fails" time="0.002" /><testcase classname="test.test_app.AppUnitTest" name="test_save_concept_uri_null_fails" time="0.002" /><testcase classname="test.test_app.AppUnitTest" name="test_save_unit_name_null_fails" time="0.002" /><testcase classname="test.test_app.AppUnitTest" name="test_save_unit_uri_and_name_null_fails" time="0.002" /><testcase classname="test.test_app.AppUnitTest" name="test_save_unit_uri_null_fails" time="0.002" /></testsuite></testsuites>
\ No newline at end of file
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 aaab95c894008ac7bf65964450a2f8101ac643b6..08631811019b691a48e725754a824f989c060f05 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
@@ -85,9 +85,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";
@@ -148,24 +148,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;
@@ -761,7 +761,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 3ef1c854c2c2891e8313fa4d4fb07becc3a81b36..9d95e621ef0b22c053fc8b3c8309b77decda2b81 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
@@ -102,14 +102,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"