From 4264eee5e3170314c96a3ee395ad22a512425ae7 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Thu, 9 Mar 2023 07:55:12 +0100
Subject: [PATCH] Merge dev into feature branch

---
 .dbrepo2/deploy                               |  40 --
 .dbrepo2/known_hosts                          |   6 -
 .fda-deployment/clean                         |   4 -
 .fda-deployment/clean-tmp                     |   6 -
 .fda-deployment/crontab                       |   2 -
 .../fda-authentication-service/install_cert   |  52 ---
 .../fda-authentication-service/install_smtp   |   2 -
 .fda-deployment/fda-ui/install_cert           |  12 -
 .fda-deployment/hosts                         |   7 -
 .gitignore                                    |   2 +-
 .gitlab-ci.yml                                | 133 +++---
 .gitlab/jacoco2cobertura.py                   | 155 -------
 .gitlab/tests/test_containers.py              |  97 -----
 .gitlab/tests/test_query.py                   | 284 -------------
 .junit/hosts                                  |  10 +
 {.dbrepo2 => .junit}/teardown                 |   0
 Makefile                                      | 112 ++---
 docker-compose.dbrepo1.yml                    |  74 ++--
 docker-compose.dbrepo2.yml                    |  76 ++--
 docker-compose.prod.yml                       |  76 ++--
 docker-compose.yml                            |  15 +-
 .../src/test/java/at/tuwien/BaseUnitTest.java |   2 +-
 .../java/at/tuwien/config/DockerConfig.java   |  60 ++-
 .../service/QueueServiceIntegrationTest.java  |  57 +--
 .../service/UserServiceIntegrationTest.java   |  59 +--
 .../src/test/resources/application.properties |   2 +-
 .../tuwien/endpoints/ContainerEndpoint.java   |  14 +-
 .../at/tuwien/endpoints/ImageEndpoint.java    |  24 --
 .../src/test/java/at/tuwien/BaseUnitTest.java |  35 +-
 .../endpoint/ContainerEndpointUnitTest.java   |  37 +-
 .../endpoint/ImageEndpointUnitTest.java       |   9 +-
 .../ContainerServiceIntegrationTest.java      | 402 +-----------------
 .../java/at/tuwien/mapper/DatabaseMapper.java |   7 +
 .../repository/jpa/ContainerRepository.java   |   2 -
 .../repository/jpa/DatabaseRepository.java    |  10 +
 .../repository/jpa/IdentifierRepository.java  |  10 +
 .../at/tuwien/service/ContainerService.java   |   7 +-
 .../service/impl/ContainerServiceImpl.java    |  16 +-
 .../at/tuwien/endpoints/DatabaseEndpoint.java |  23 -
 .../src/test/java/at/tuwien/BaseUnitTest.java |  36 +-
 .../java/at/tuwien/config/DockerConfig.java   |   4 +-
 .../endpoint/DatabaseEndpointUnitTest.java    | 108 ++++-
 .../src/test/resources/application.properties |   4 +-
 .../src/test/resources/nginx/nginx.conf       |   2 +-
 .../java/at/tuwien/mapper/DatabaseMapper.java |   1 +
 .../api/container/ContainerBriefDto.java      |   4 +
 .../tuwien/api/database/DatabaseBriefDto.java |   6 +-
 .../api/identifier/CreatorBriefDto.java       |  28 ++
 .../api/identifier/IdentifierBriefDto.java    |  19 +
 .../at/tuwien/entities/database/Database.java |  18 +-
 .../entities/identifier/Identifier.java       |   7 +-
 .../at/tuwien/endpoint/TableDataEndpoint.java |   9 +-
 .../src/main/resources/application-local.yml  |   2 +-
 .../src/test/java/at/tuwien/BaseUnitTest.java |  56 ++-
 .../at/tuwien/auth/AuthTokenFilterTest.java   |   4 -
 .../java/at/tuwien/config/DockerConfig.java   |  13 +-
 .../java/at/tuwien/config/RabbitMqConfig.java |   4 +-
 .../endpoint/ExportEndpointUnitTest.java      |   7 +
 .../endpoint/QueryEndpointUnitTest.java       |   7 +
 .../endpoint/StoreEndpointUnitTest.java       |   7 +
 .../endpoint/TableDataEndpointUnitTest.java   |   7 +
 .../TableHistoryEndpointUnitTest.java         |   7 +
 .../tuwien/endpoint/ViewEndpointUnitTest.java |   7 +
 .../RabbitMqListenerIntegrationTest.java      |  54 ++-
 .../ViewIdxRepositoryIntegrationTest.java     |   7 +
 .../ViewRepositoryIntegrationTest.java        |   7 +
 .../ContainerServiceIntegrationTest.java      |   7 +
 .../service/QueryServiceIntegrationTest.java  |  11 +-
 .../service/QueueServiceIntegrationTest.java  |   9 +-
 .../service/StoreServiceIntegrationTest.java  |   7 +
 .../service/TableServiceIntegrationTest.java  |   8 +
 .../tuwien/service/TableServiceUnitTest.java  |   7 +
 .../service/ViewServiceIntegrationTest.java   |  12 +-
 .../src/test/resources/application.properties |   8 +-
 .../test/resources/webserver/weather_aus.csv  |   3 -
 .../tuwien/gateway/BrokerServiceGateway.java  |   1 +
 .../impl/BrokerServiceGatewayImpl.java        |  17 +-
 .../tuwien/listener/MessageQueueListener.java |   6 +
 .../listener/impl/RabbitMqListenerImpl.java   |   2 +-
 .../at/tuwien/mapper/ContainerMapper.java     |  15 +
 .../java/at/tuwien/mapper/ViewMapper.java     |   2 +-
 .../java/at/tuwien/service/QueryService.java  |   2 +-
 .../tuwien/service/impl/QueryServiceImpl.java |  49 +--
 .../src/test/java/at/tuwien/BaseUnitTest.java |  20 +-
 .../java/at/tuwien/config/GatewayConfig.java  |   2 +-
 .../MessageQueueServiceIntegrationTest.java   |   4 +-
 .../service/TableServiceIntegrationTest.java  |   4 +-
 .../test/java/at/tuwien/utils/AmqpUtils.java  |   4 +-
 fda-ui/.gitignore                             |   4 +-
 fda-ui/.nycrc                                 |   2 +-
 fda-ui/.prod/default.conf                     |  30 --
 fda-ui/.prod/secure.conf                      |  38 --
 fda-ui/Dockerfile                             |  11 +-
 fda-ui/components/DatabaseList.vue            | 192 +++++++++
 fda-ui/components/QueryList.vue               |  77 ++--
 fda-ui/components/TableList.vue               |  30 +-
 fda-ui/components/TableToolbar.vue            |   2 +-
 fda-ui/components/ViewList.vue                |   8 +-
 fda-ui/components/dialogs/Persist.vue         |  14 +
 fda-ui/components/query/Builder.vue           |   4 -
 fda-ui/layouts/default.vue                    |  22 +-
 fda-ui/package.json                           |   8 +-
 .../database/_database_id/info.vue            |  54 +--
 .../_database_id/query/_query_id/index.vue    |   3 +
 .../database/_database_id/settings.vue        |   2 +-
 .../_database_id/table/_table_id/data.vue     |   2 +-
 .../_database_id/table/_table_id/info.vue     |  82 ++--
 .../_database_id/table/_table_id/schema.vue   |   4 +-
 fda-ui/pages/container/index.vue              | 208 +--------
 fda-ui/pages/forgot.vue                       |   3 +
 fda-ui/pages/login.vue                        |   3 +
 fda-ui/pages/search/index.vue                 |  19 +-
 fda-ui/pages/signup.vue                       |   7 +
 fda-ui/test/e2e/database.js                   |  69 +--
 fda-ui/test/e2e/forgot.js                     |  18 +
 fda-ui/test/e2e/index.js                      |  47 +-
 fda-ui/test/e2e/login.js                      |  18 +
 fda-ui/test/e2e/search.js                     |  28 ++
 fda-ui/test/e2e/signup.js                     |  21 +
 fda-ui/test/e2e/tables.js                     |  62 ---
 fda-ui/test/unit/query.js                     |  20 +-
 fda-ui/test/unit/utils.js                     | 279 ++++++++++++
 fda-ui/utils/index.js                         |  24 +-
 fda-ui/yarn.lock                              |  28 ++
 124 files changed, 1773 insertions(+), 2246 deletions(-)
 delete mode 100755 .dbrepo2/deploy
 delete mode 100644 .dbrepo2/known_hosts
 delete mode 100755 .fda-deployment/clean
 delete mode 100755 .fda-deployment/clean-tmp
 delete mode 100644 .fda-deployment/crontab
 delete mode 100755 .fda-deployment/fda-authentication-service/install_cert
 delete mode 100755 .fda-deployment/fda-authentication-service/install_smtp
 delete mode 100755 .fda-deployment/fda-ui/install_cert
 delete mode 100644 .fda-deployment/hosts
 delete mode 100755 .gitlab/jacoco2cobertura.py
 delete mode 100644 .gitlab/tests/test_containers.py
 delete mode 100644 .gitlab/tests/test_query.py
 create mode 100644 .junit/hosts
 rename {.dbrepo2 => .junit}/teardown (100%)
 create mode 100644 fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java
 create mode 100644 fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java
 create mode 100644 fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java
 delete mode 100644 fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv
 create mode 100644 fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
 delete mode 100644 fda-ui/.prod/default.conf
 delete mode 100644 fda-ui/.prod/secure.conf
 create mode 100644 fda-ui/components/DatabaseList.vue
 create mode 100644 fda-ui/test/e2e/forgot.js
 create mode 100644 fda-ui/test/e2e/login.js
 create mode 100644 fda-ui/test/e2e/search.js
 create mode 100644 fda-ui/test/e2e/signup.js
 delete mode 100644 fda-ui/test/e2e/tables.js
 create mode 100644 fda-ui/test/unit/utils.js

diff --git a/.dbrepo2/deploy b/.dbrepo2/deploy
deleted file mode 100755
index 2cda49aec7..0000000000
--- 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 d17a72e2de..0000000000
--- 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 03506fc6ef..0000000000
--- 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 ac34df7e9c..0000000000
--- 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 bbc97b1a42..0000000000
--- 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 f52db602f4..0000000000
--- 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 22b0afaa76..0000000000
--- 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 9255312371..0000000000
--- 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 40da214c6a..0000000000
--- 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 e372ff156b..ae9e683f84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,7 @@ target/
 !.mvn/wrapper/maven-wrapper.jar
 !**/src/main/**/target/
 !**/src/test/**/target/
-
+dbrepo-*
 # Notebooks
 .jupyter/
 .pytest_cache/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c18ce65e3b..1967e4afea 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 76ad75a705..0000000000
--- a/.gitlab/jacoco2cobertura.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env python3
-import sys
-import xml.etree.ElementTree as ET
-import re
-import os.path
-
-# branch-rate="0.0" complexity="0.0" line-rate="1.0"
-# branch="true" hits="1" number="86"
-
-def find_lines(j_package, filename):
-    """Return all <line> elements for a given source file in a package."""
-    lines = list()
-    sourcefiles = j_package.findall("sourcefile")
-    for sourcefile in sourcefiles:
-        if sourcefile.attrib.get("name") == os.path.basename(filename):
-            lines = lines + sourcefile.findall("line")
-    return lines
-
-def line_is_after(jm, start_line):
-    return int(jm.attrib.get('line', 0)) > start_line
-
-def method_lines(jmethod, jmethods, jlines):
-    """Filter the lines from the given set of jlines that apply to the given jmethod."""
-    start_line = int(jmethod.attrib.get('line', 0))
-    larger     = list(int(jm.attrib.get('line', 0)) for jm in jmethods if line_is_after(jm, start_line))
-    end_line   = min(larger) if len(larger) else 99999999
-
-    for jline in jlines:
-        if start_line <= int(jline.attrib['nr']) < end_line:
-            yield jline
-
-def convert_lines(j_lines, into):
-    """Convert the JaCoCo <line> elements into Cobertura <line> elements, add them under the given element."""
-    c_lines = ET.SubElement(into, 'lines')
-    for jline in j_lines:
-        mb = int(jline.attrib['mb'])
-        cb = int(jline.attrib['cb'])
-        ci = int(jline.attrib['ci'])
-
-        cline = ET.SubElement(c_lines, 'line')
-        cline.set('number', jline.attrib['nr'])
-        cline.set('hits', '1' if ci > 0 else '0') # Probably not true but no way to know from JaCoCo XML file
-
-        if mb + cb > 0:
-            percentage = str(int(100 * (float(cb) / (float(cb) + float(mb))))) + '%'
-            cline.set('branch',             'true')
-            cline.set('condition-coverage', percentage + ' (' + str(cb) + '/' + str(cb + mb) + ')')
-
-            cond = ET.SubElement(ET.SubElement(cline, 'conditions'), 'condition')
-            cond.set('number',   '0')
-            cond.set('type',     'jump')
-            cond.set('coverage', percentage)
-        else:
-            cline.set('branch', 'false')
-
-def guess_filename(path_to_class):
-    m = re.match('([^$]*)', path_to_class)
-    return (m.group(1) if m else path_to_class) + '.java'
-
-def add_counters(source, target):
-    target.set('line-rate',   counter(source, 'LINE'))
-    target.set('branch-rate', counter(source, 'BRANCH'))
-    target.set('complexity', counter(source, 'COMPLEXITY', sum))
-
-def fraction(covered, missed):
-    return covered / (covered + missed)
-
-def sum(covered, missed):
-    return covered + missed
-
-def counter(source, type, operation=fraction):
-    cs = source.findall('counter')
-    c = next((ct for ct in cs if ct.attrib.get('type') == type), None)
-
-    if c is not None:
-        covered = float(c.attrib['covered'])
-        missed  = float(c.attrib['missed'])
-
-        return str(operation(covered, missed))
-    else:
-        return '0.0'
-
-def convert_method(j_method, j_lines):
-    c_method = ET.Element('method')
-    c_method.set('name',      j_method.attrib['name'])
-    c_method.set('signature', j_method.attrib['desc'])
-
-    add_counters(j_method, c_method)
-    convert_lines(j_lines, c_method)
-
-    return c_method
-
-def convert_class(j_class, j_package):
-    c_class = ET.Element('class')
-    c_class.set('name',     j_class.attrib['name'].replace('/', '.'))
-    c_class.set('filename', guess_filename(j_class.attrib['name']))
-
-    all_j_lines = list(find_lines(j_package, c_class.attrib['filename']))
-
-    c_methods   = ET.SubElement(c_class, 'methods')
-    all_j_methods = list(j_class.findall('method'))
-    for j_method in all_j_methods:
-        j_method_lines = method_lines(j_method, all_j_methods, all_j_lines)
-        c_methods.append(convert_method(j_method, j_method_lines))
-
-    add_counters(j_class, c_class)
-    convert_lines(all_j_lines, c_class)
-
-    return c_class
-
-def convert_package(j_package):
-    c_package = ET.Element('package')
-    c_package.attrib['name'] = j_package.attrib['name'].replace('/', '.')
-
-    c_classes = ET.SubElement(c_package, 'classes')
-    for j_class in j_package.findall('class'):
-        c_classes.append(convert_class(j_class, j_package))
-
-    add_counters(j_package, c_package)
-
-    return c_package
-
-def convert_root(source, target, source_roots):
-    target.set('timestamp', str(int(source.find('sessioninfo').attrib['start']) / 1000))
-
-    sources     = ET.SubElement(target, 'sources')
-    for s in source_roots:
-        ET.SubElement(sources, 'source').text = s
-
-    packages = ET.SubElement(target, 'packages')
-    for package in source.findall('package'):
-        packages.append(convert_package(package))
-
-    add_counters(source, target)
-
-def jacoco2cobertura(filename, source_roots):
-    if filename == '-':
-        root = ET.fromstring(sys.stdin.read())
-    else:
-        tree = ET.parse(filename)
-        root = tree.getroot()
-
-    into = ET.Element('coverage')
-    convert_root(root, into, source_roots)
-    print(ET.tostring(into, encoding='utf8', method='xml').decode("utf-8"))
-
-if __name__ == '__main__':
-    if len(sys.argv) < 2:
-        print("Usage: cover2cover.py FILENAME [SOURCE_ROOTS]")
-        sys.exit(1)
-
-    filename    = sys.argv[1]
-    source_roots = sys.argv[2:] if 2 < len(sys.argv) else '.'
-
-    jacoco2cobertura(filename, source_roots)
\ No newline at end of file
diff --git a/.gitlab/tests/test_containers.py b/.gitlab/tests/test_containers.py
deleted file mode 100644
index dd4e1a97cc..0000000000
--- a/.gitlab/tests/test_containers.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/bin/env python3
-from api_container.api.container_endpoint_api import ContainerEndpointApi
-from api_database.api.database_endpoint_api import DatabaseEndpointApi
-import time
-
-container = ContainerEndpointApi()
-database = DatabaseEndpointApi()
-
-def create_container():
-    response = container.create1({
-        "name": "Pilot Factory Data",
-        "repository": "mariadb",
-        "tag": "10.5"
-    })
-    print("created container with id %d" % response.id)
-    return response
-
-
-def start_container(container_id):
-    response = container.modify({
-        "action": "start"
-    }, container_id)
-    print("... starting")
-    time.sleep(5)
-    print("started container with id %d" % response.id)
-    return response
-
-
-def create_database(container_id, is_public=True):
-    response = database.create({
-        "name": "Pilot Factory Data",
-        "is_public": is_public
-    }, container_id)
-    print("created database with id %d" % response.id)
-    return response
-
-token = ""  # keep
-
-from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi
-from api_authentication.api.user_endpoint_api import UserEndpointApi
-import uuid
-
-authentication = AuthenticationEndpointApi()
-user = UserEndpointApi()
-
-def create_user(username):
-    response = user.register({
-        "username": username,
-        "password": username,
-        "email": username + "@gmail.com"
-    })
-    print("created user with id %d" % response.id)
-    return response
-
-
-def auth_user(username):
-    response = authentication.authenticate_user1({
-        "username": username,
-        "password": username
-    })
-    print("authenticated user with id %d" % response.id)
-    token = response.token
-    container.api_client.default_headers = {"Authorization": "Bearer " + token}
-    database.api_client.default_headers = {"Authorization": "Bearer " + token}
-    return response
-
-
-def find_database(container_id, database_id):
-    response = database.find_by_id(container_id, database_id)
-    print("found database with id %d" % response.id)
-    return response
-
-
-def update_database(container_id, database_id):
-    response = database.update({
-        "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).",
-        "publisher": "Technical University of Vienna",
-        "license": {
-            "identifier": "CC0-1.0",
-            "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode"
-        },
-        "language": "en",
-        "publication_year": 2022
-    }, container_id, database_id)
-    print("updated database with id %d" % response.id)
-    return response
-
-
-def test_containers():
-    username = str(uuid.uuid1()).replace("-", "")
-    uid = create_user(username).id
-    auth_user(username)
-    # container 1
-    cid = create_container().id
-    start_container(cid)
-    dbid = create_database(cid).id
-    update_database(cid, dbid)
diff --git a/.gitlab/tests/test_query.py b/.gitlab/tests/test_query.py
deleted file mode 100644
index 283f311b65..0000000000
--- a/.gitlab/tests/test_query.py
+++ /dev/null
@@ -1,284 +0,0 @@
-#!/bin/env python3
-
-import time
-import os
-import shutil
-import uuid
-
-from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi
-from api_authentication.api.user_endpoint_api import UserEndpointApi
-from api_container.api.container_endpoint_api import ContainerEndpointApi
-from api_database.api.database_endpoint_api import DatabaseEndpointApi
-from api_table.api.table_endpoint_api import TableEndpointApi
-from api_query.api.table_data_endpoint_api import TableDataEndpointApi
-from api_query.api.query_endpoint_api import QueryEndpointApi
-from api_query.api.table_history_endpoint_api import TableHistoryEndpointApi
-from api_identifier.api.identifier_endpoint_api import IdentifierEndpointApi
-from api_identifier.api.persistence_endpoint_api import PersistenceEndpointApi
-from api_query.api.view_endpoint_api import ViewEndpointApi
-from api_query.rest import ApiException
-
-authentication = AuthenticationEndpointApi()
-user = UserEndpointApi()
-container = ContainerEndpointApi()
-database = DatabaseEndpointApi()
-table = TableEndpointApi()
-query = QueryEndpointApi()
-history = TableHistoryEndpointApi()
-data = TableDataEndpointApi()
-identifier = IdentifierEndpointApi()
-persistence = PersistenceEndpointApi()
-view = ViewEndpointApi()
-
-token = ""  # keep
-
-
-def create_user(username):
-    response = user.register({
-        "username": username,
-        "password": username,
-        "email": username + "@gmail.com"
-    })
-    print("created user with id %d" % response.id)
-    return response
-
-
-def update_password(user_id, password):
-    response = user.update_password({
-        "password": password
-    }, user_id)
-    print("updated password for user with id %d" % user_id)
-    return response
-
-
-def auth_user(username):
-    response = authentication.authenticate_user1({
-        "username": username,
-        "password": username
-    })
-    print("authenticated user with id %d" % response.id)
-    token = response.token
-    container.api_client.default_headers = {"Authorization": "Bearer " + token}
-    database.api_client.default_headers = {"Authorization": "Bearer " + token}
-    table.api_client.default_headers = {"Authorization": "Bearer " + token}
-    data.api_client.default_headers = {"Authorization": "Bearer " + token}
-    query.api_client.default_headers = {"Authorization": "Bearer " + token}
-    identifier.api_client.default_headers = {"Authorization": "Bearer " + token}
-    user.api_client.default_headers = {"Authorization": "Bearer " + token}
-    persistence.api_client.default_headers = {"Authorization": "Bearer " + token}
-    history.api_client.default_headers = {"Authorization": "Bearer " + token}
-    view.api_client.default_headers = {"Authorization": "Bearer " + token}
-    return response
-
-
-def create_container():
-    response = container.create1({
-        "name": "Pilot Factory Data",
-        "repository": "mariadb",
-        "tag": "10.5"
-    })
-    print("created container with id %d" % response.id)
-    return response
-
-
-def start_container(container_id):
-    response = container.modify({
-        "action": "start"
-    }, container_id)
-    print("... starting")
-    time.sleep(5)
-    print("started container with id %d" % response.id)
-    return response
-
-
-def create_database(container_id, is_public=True):
-    response = database.create({
-        "name": "Pilot Factory Data",
-        "is_public": is_public
-    }, container_id)
-    print("created database with id %d" % response.id)
-    return response
-
-
-def find_database(container_id, database_id):
-    response = database.find_by_id(container_id, database_id)
-    print("found database with id %d" % response.id)
-    return response
-
-
-def update_database(container_id, database_id):
-    response = database.update({
-        "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).",
-        "publisher": "Technical University of Vienna",
-        "license": {
-            "identifier": "CC0-1.0",
-            "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode"
-        },
-        "language": "en",
-        "publication_year": 2022
-    }, container_id, database_id)
-    print("updated database with id %d" % response.id)
-    return response
-
-
-def create_table(container_id, database_id, columns=None):
-    if columns is None:
-        columns = [{
-            "name": "Date",
-            "type": "date",
-            "dfid": 1,
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Location",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Parameter",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Interval",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Unit",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Value",
-            "type": "decimal",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }, {
-            "name": "Status",
-            "type": "string",
-            "unique": False,
-            "primary_key": False,
-            "null_allowed": True,
-        }]
-    response = table.create({
-        "name": "Airquality " + str(uuid.uuid1()),
-        "description": "Airquality in Zürich, Switzerland",
-        "columns": columns
-    }, "Bearer " + token, container_id, database_id)
-    print("created table with id %d" % response.id)
-    return response
-
-
-def find_table(container_id, database_id, table_id):
-    response = table.find_by_id(container_id, database_id, table_id)
-    print("found table with id %d" % response.id)
-    return response
-
-
-def fill_table(container_id, database_id, table_id):
-    response = data.import_csv({
-        "location": "/path/to/data.csv",
-        "quote": "\"",
-        "null_element": "NA"
-        "separator": ",",
-    }, container_id, database_id, table_id)
-    print("filled table with id %d" % table_id)
-    return response
-
-
-def create_query(container_id, database_id, statement, page=0, size=3):
-    response = query.execute({
-        "statement": statement
-    }, container_id, database_id, page=page, size=size)
-    print("executed query with id %d" % response.id)
-    return response
-
-
-def delete_tuple(container_id, database_id, table_id, keys):
-    response = data.delete(keys, container_id, database_id, table_id)
-    print("deleted tuples for table with id %d" % table_id)
-    return response
-
-
-def download_query_data(container_id, database_id, query_id):
-    response = query.export1(container_id, database_id, query_id)
-    print("downloaded query data for query with id %d" % query_id)
-    return response
-
-
-def list_views(container_id, database_id):
-    response = view.find_all(container_id, database_id)
-    print("list views for database with id %d" % database_id)
-    return response
-
-
-def create_view(container_id, database_id, table_name):
-    response = view.create({
-        "name": "Air Quality " + str(uuid.uuid1()),
-        "query": "SELECT `date`, `parameter`, `value` FROM `" + table_name + "` WHERE `date` = '2021-10-02T14:00'",
-        "is_public": True
-    }, container_id, database_id)
-    print("created view with id %d" % response.id)
-    return response
-
-
-def data_view(container_id, database_id, view_id):
-    response = view.data(container_id, database_id, view_id)
-    print("retrieved data for view with id %d" % response.id)
-    return response
-
-
-def test_identifiers():
-    #
-    # create 1 user and 2 containers (public, private)
-    #
-    username = str(uuid.uuid1()).replace("-", "")
-    uid = create_user(username).id
-    auth_user(username)
-    # container 1
-    cid = create_container().id
-    start_container(cid)
-    dbid = create_database(cid).id
-    update_database(cid, dbid)
-    tid = create_table(cid, dbid).id
-    tname = find_table(cid, dbid, tid).internal_name
-    fill_table(cid, dbid, tid)
-    create_query(cid, dbid, "select `id` from `" + tname + "`")
-    create_query(cid, dbid, "select `date` from `" + tname + "`")
-    qid = create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "`").id
-    create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "` order by `date` asc")
-    create_query(cid, dbid, "select t.`date`, t.location, t.status from `" + tname + "` t group by t.`date` order by t.`date` asc")
-    create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "` group by `date`, `location` asc")
-    download_query_data(cid, dbid, qid)
-    # container 2 (=private)
-    cid = create_container().id
-    start_container(cid)
-    dbid = create_database(cid, False).id
-    update_database(cid, dbid)
-    tid = create_table(cid, dbid).id
-    tname = find_table(cid, dbid, tid).internal_name
-    fill_table(cid, dbid, tid)
-    qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id
-    qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id
-    vid = create_view(cid, dbid, tname).id
-    data_view(cid, dbid, vid)
-    list_views(cid, dbid)
-    for i in range(5, 10):
-        delete_tuple(cid, dbid, tid, {
-            "keys": {
-                "id": i
-            }
-        })
-        time.sleep(1)
-    delete_tuple(cid, dbid, tid, {
-        "keys": {
-            "location": "Schimmelstrasse"
-        }
-    })
diff --git a/.junit/hosts b/.junit/hosts
new file mode 100644
index 0000000000..701ef56fa3
--- /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 ec1921ff29..a5bce8de2e 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 dfd09f5097..01db36561d 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 dbd34f265e..7c169dd1ce 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 78fc30f911..8984baecab 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -31,7 +31,7 @@ networks:
 
 services:
 
-  metadata-db:
+  dbrepo-metadata-db:
     restart: on-failure
     container_name: dbrepo-metadata-db
     hostname: metadata-db
@@ -48,7 +48,7 @@ services:
     logging:
       driver: json-file
 
-  discovery-service:
+  dbrepo-discovery-service:
     restart: on-failure
     container_name: dbrepo-discovery-service
     hostname: discovery-service
@@ -60,7 +60,7 @@ services:
     logging:
       driver: json-file
 
-  gateway-service:
+  dbrepo-gateway-service:
     restart: on-failure
     container_name: dbrepo-gateway-service
     hostname: gateway-service
@@ -72,12 +72,12 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  database-service:
+  dbrepo-database-service:
     restart: on-failure
     container_name: dbrepo-database-service
     hostname: database-service
@@ -90,16 +90,16 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      container-service:
+      dbrepo-container-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  container-service:
+  dbrepo-container-service:
     restart: on-failure
     container_name: dbrepo-container-service
     hostname: container-service
@@ -111,12 +111,12 @@ services:
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  authentication-service:
+  dbrepo-authentication-service:
     restart: on-failure
     container_name: dbrepo-authentication-service
     hostname: authentication-service
@@ -126,16 +126,16 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  query-service:
+  dbrepo-query-service:
     restart: on-failure
     container_name: dbrepo-query-service
     hostname: query-service
@@ -148,14 +148,14 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      table-service:
+      dbrepo-table-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  table-service:
+  dbrepo-table-service:
     restart: on-failure
     container_name: dbrepo-table-service
     hostname: table-service
@@ -169,16 +169,16 @@ services:
       - /var/run/docker.sock:/var/run/docker.sock
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
-      search-service:
+      dbrepo-search-service:
         condition: service_started
-      broker-service:
+      dbrepo-broker-service:
         condition: service_started
     logging:
       driver: json-file
 
-  identifier-service:
+  dbrepo-identifier-service:
     restart: on-failure
     container_name: dbrepo-identifier-service
     hostname: identifier-service
@@ -188,16 +188,16 @@ services:
     env_file:
       - .env
     depends_on:
-      query-service:
+      dbrepo-query-service:
         condition: service_healthy
-      authentication-service:
+      dbrepo-authentication-service:
         condition: service_healthy
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     logging:
       driver: json-file
 
-  metadata-service:
+  dbrepo-metadata-service:
     restart: on-failure
     container_name: dbrepo-metadata-service
     hostname: metadata-service
@@ -207,12 +207,12 @@ services:
     env_file:
       - .env
     depends_on:
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_started
     logging:
       driver: json-file
 
-  analyse-service:
+  dbrepo-analyse-service:
     restart: on-failure
     container_name: dbrepo-analyse-service
     hostname: analyse-service
@@ -226,12 +226,12 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     logging:
       driver: json-file
 
-  semantics-service:
+  dbrepo-semantics-service:
     restart: on-failure
     container_name: dbrepo-semantics-service
     hostname: semantics-service
@@ -244,14 +244,14 @@ services:
       - ${SHARED_FILESYSTEM}:/tmp
       - /var/run/docker.sock:/var/run/docker.sock
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
-      metadata-db:
+      dbrepo-metadata-db:
         condition: service_healthy
     logging:
       driver: json-file
 
-  broker-service:
+  dbrepo-broker-service:
     restart: on-failure
     container_name: dbrepo-broker-service
     hostname: broker-service
@@ -263,14 +263,14 @@ services:
     env_file:
       - .env
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     volumes:
       - broker-service-data:/var/lib/rabbitmq/
     logging:
       driver: json-file
 
-  search-service:
+  dbrepo-search-service:
     restart: always
     container_name: dbrepo-search-service
     hostname: search-service
@@ -278,7 +278,7 @@ services:
     networks:
       core:
     depends_on:
-      discovery-service:
+      dbrepo-discovery-service:
         condition: service_healthy
     env_file:
       - .env
@@ -287,7 +287,7 @@ services:
     logging:
       driver: json-file
 
-  ui:
+  dbrepo-ui:
     restart: on-failure
     container_name: dbrepo-ui
     hostname: ui
@@ -302,9 +302,9 @@ services:
     volumes:
       - ${SHARED_FILESYSTEM}:/tmp
     depends_on:
-      identifier-service:
+      dbrepo-identifier-service:
         condition: service_healthy
-      database-service:
+      dbrepo-database-service:
         condition: service_healthy
     logging:
       driver: json-file
diff --git a/docker-compose.yml b/docker-compose.yml
index fd864bd166..955a59d41c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -10,27 +10,26 @@ volumes:
   broker-service-data:
 
 networks:
-  public:
-    name: public
+  userdb:
+    name: userdb
     driver: bridge
     ipam:
       config:
-        - subnet: 172.29.0.0/16
-  userdb:
-    name: userdb
+        - subnet: 172.30.0.0/16
+  public:
+    name: public
     driver: bridge
     ipam:
       config:
-        - subnet: 172.28.0.0/16
+        - subnet: 172.31.0.0/16
   core:
     name: core
     driver: bridge
     ipam:
       config:
-        - subnet: 172.27.0.0/16
+        - subnet: 172.32.0.0/16
 
 services:
-
   fda-metadata-db:
     restart: on-failure
     container_name: dbrepo-metadata-db
diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index be355787b9..c6c927f9b9 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 fc15443f9e..37b2ca7d1b 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 f887b5a86c..ba84081446 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 371ed3450a..c72d988189 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 b0ccd00eda..d57104b1ea 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 9dfe9e4b53..5c3d11e564 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 7f02363385..bbb5d2ecba 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 c22a810fea..0a59ea1f45 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 7407254558..cd82d0b81d 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 f84ae04db5..9ef775d53d 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 8aef59c9fc..fd1c316006 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 6a7b557780..1879065a2d 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 37b8abb773..df2a6eba16 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 0000000000..688993ab3c
--- /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 0000000000..f76f9976d6
--- /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 2528621ed4..26654fc34f 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 4dc6996229..9753d9687e 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 57820c3a21..bfeb98549b 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/test/java/at/tuwien/BaseUnitTest.java b/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index 7a1890e25d..e32140f007 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 5340810c86..7c55429c92 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 4808082aff..61cbf30d02 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 33b8c25e25..ddfddd8b33 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 f4ada65dc8..6604865024 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 26aca837e2..f986f75772 100644
--- a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
+++ b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
@@ -85,6 +85,7 @@ public interface DatabaseMapper {
             @Mapping(target = "id", source = "id"),
             @Mapping(target = "engine", source = "container.image", qualifiedByName = "engineMapping"),
             @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"),
+            @Mapping(target = "container", ignore = true),
     })
     DatabaseBriefDto databaseToDatabaseBriefDto(Database data);
 
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
index c8a6ff55aa..e48292d753 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 699889b1c1..d91f7ce74d 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 0000000000..ad0910407b
--- /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 a3e816be75..c17feec05c 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 90a49b81b8..a3233d7135 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/identifier/Identifier.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java
index a6385bb908..95ffd29e59 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-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 117a60a338..277e622b62 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
@@ -147,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 */
@@ -156,16 +156,9 @@ public class TableDataEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Missing data view permission");
         }
         validateDataParams(page, size, sortDirection, sortColumn);
-        /* find */
-        // TODO: Remove these comments
-        //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.tableFindAll(containerId, databaseId, tableId, timestamp, page, size, principal);
         log.trace("find table data resulted in result {}", response);
         return ResponseEntity.ok()
-        //        .headers(headers)
                 .body(response);
     }
 
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 8e36da9b7b..9451262fbd 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 dd59dcd081..556aa3937d 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -300,12 +300,22 @@ public abstract class BaseUnitTest {
             .tag(IMAGE_ELASTIC_TAG)
             .build();
 
+    public final static Long IMAGE_PROXY_ID = 4L;
+    public final static String IMAGE_PROXY_REPOSITORY = "nginx";
+    public final static String IMAGE_PROXY_TAG = "latest";
+
+    public final static ContainerImage IMAGE_PROXY = ContainerImage.builder()
+            .id(IMAGE_PROXY_ID)
+            .repository(IMAGE_PROXY_REPOSITORY)
+            .tag(IMAGE_PROXY_TAG)
+            .build();
+
     public final static Long CONTAINER_1_ID = 1L;
     public final static String CONTAINER_1_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
     public final static String CONTAINER_1_NAME = "u01";
-    public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01";
-    public final static String CONTAINER_1_IP = "172.28.0.5";
+    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
+    public final static String CONTAINER_1_IP = "172.30.0.5";
     public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS);
     public final static String[] CONTAINER_1_ENV = new String[]{"MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb",
             "MARIADB_DATABASE=weather"};
@@ -328,8 +338,8 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_2_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_1;
     public final static String CONTAINER_2_NAME = "u02";
-    public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02";
-    public final static String CONTAINER_2_IP = "172.28.0.6";
+    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02";
+    public final static String CONTAINER_2_IP = "172.30.0.6";
     public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS);
     public final static String[] CONTAINER_2_ENV = new String[]{"MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb",
             "MARIADB_DATABASE=zoo"};
@@ -352,8 +362,8 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_3_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_1;
     public final static String CONTAINER_3_NAME = "u03";
-    public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03";
-    public final static String CONTAINER_3_IP = "172.28.0.7";
+    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03";
+    public final static String CONTAINER_3_IP = "172.30.0.7";
     public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_3_HEALTHCHECK = new HealthCheck()
             .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb"));
@@ -373,8 +383,8 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_4_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_4_IMAGE = IMAGE_1;
     public final static String CONTAINER_4_NAME = "u04";
-    public final static String CONTAINER_4_INTERNALNAME = "fda-userdb-u04";
-    public final static String CONTAINER_4_IP = "172.28.0.8";
+    public final static String CONTAINER_4_INTERNALNAME = "dbrepo-userdb-u04";
+    public final static String CONTAINER_4_IP = "172.30.0.8";
     public final static Instant CONTAINER_4_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_4_HEALTHCHECK = new HealthCheck()
             .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb"));
@@ -394,9 +404,9 @@ public abstract class BaseUnitTest {
             .build();
 
     public final static Long CONTAINER_BROKER_ID = 5L;
-    public final static String CONTAINER_BROKER_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service";
-    public final static String CONTAINER_BROKER_IP = "172.29.0.2";
+    public final static String CONTAINER_BROKER_NAME = "dbrepo-broker-service";
+    public final static String CONTAINER_BROKER_INTERNAL_NAME = "dbrepo-broker-service";
+    public final static String CONTAINER_BROKER_IP = "172.31.0.2";
     public final static String CONTAINER_BROKER_HASH = "deadbeef";
     public final static Instant CONTAINER_BROKER_CREATED = Instant.now().minus(1, HOURS);
     public final static HealthCheck CONTAINER_BROKER_HEALTHCHECK = new HealthCheck()
@@ -418,7 +428,7 @@ public abstract class BaseUnitTest {
     public final static Long CONTAINER_ELASTIC_ID = 6L;
     public final static String CONTAINER_ELASTIC_NAME = "fda-elastic-service";
     public final static String CONTAINER_ELASTIC_INTERNAL_NAME = "search-mock-service";
-    public final static String CONTAINER_ELASTIC_IP = "172.29.0.3";
+    public final static String CONTAINER_ELASTIC_IP = "172.31.0.3";
     public final static String CONTAINER_ELASTIC_HASH = "deadbeef";
     public final static Instant CONTAINER_ELASTIC_CREATED = Instant.now().minus(1, HOURS);
 
@@ -434,6 +444,28 @@ public abstract class BaseUnitTest {
             .creator(USER_1)
             .build();
 
+    public final static Long CONTAINER_PROXY_ID = 7L;
+    public final static String CONTAINER_PROXY_NAME = "dbrepo-proxy";
+    public final static String CONTAINER_PROXY_INTERNAL_NAME = "dbrepo-proxy";
+    public final static String CONTAINER_PROXY_IP = "172.31.0.4";
+    public final static String CONTAINER_PROXY_HASH = "deadbeef";
+    public final static Instant CONTAINER_PROXY_CREATED = Instant.now().minus(1, HOURS);
+    public final static String[] CONTAINER_PROXY_ENV = new String[]{};
+    public final static HealthCheck CONTAINER_PROXY_HEALTHCHECK = new HealthCheck()
+            .withTest(List.of("CMD", "service", "nginx", "status"));
+
+    public final static Container CONTAINER_PROXY = Container.builder()
+            .id(CONTAINER_PROXY_ID)
+            .name(CONTAINER_PROXY_NAME)
+            .internalName(CONTAINER_PROXY_INTERNAL_NAME)
+            .imageId(IMAGE_PROXY_ID)
+            .image(IMAGE_PROXY)
+            .hash(CONTAINER_PROXY_HASH)
+            .ipAddress(CONTAINER_PROXY_IP)
+            .created(CONTAINER_PROXY_CREATED)
+            .creator(USER_1)
+            .build();
+
     public final static Long DATABASE_1_ID = 1L;
     public final static String DATABASE_1_NAME = "Weather";
     public final static String DATABASE_1_INTERNALNAME = "weather";
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 eac1924398..bf3df721ba 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 2f03e666f1..f91219b29e 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/RabbitMqConfig.java b/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java
index 0ee03e69ad..72ef54c966 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 4b3898d83a..f5126e08b4 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;
 
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 7b1e9ade2c..8f315d2b40 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 f323836cf2..42782640bd 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 38de6122bf..4cf2392ed0 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;
@@ -47,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;
 
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 a06089955e..9a649b2e39 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 36430b419c..5cf4aadd98 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;
 
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
index 1ddaac142a..79b0f37ba1 100644
--- 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
@@ -3,9 +3,6 @@ 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;
@@ -18,16 +15,18 @@ 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.ActiveProfiles;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.IOException;
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.when;
 
 
 @Log4j2
+@ActiveProfiles(profiles = "junit")
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
 @SpringBootTest
 @ExtendWith(SpringExtension.class)
@@ -39,9 +38,6 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest {
     @MockBean
     private IndexConfig indexConfig;
 
-    @MockBean
-    private BrokerServiceGateway brokerServiceGateway;
-
     @Autowired
     private Channel channel;
 
@@ -57,12 +53,6 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest {
     @Autowired
     private TableRepository tableRepository;
 
-    @Autowired
-    private RabbitMqListenerImpl rabbitMqListener;
-
-    @Autowired
-    private TableColumnRepository tableColumnRepository;
-
     @Autowired
     private H2Utils h2Utils;
 
@@ -73,12 +63,14 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest {
     private AmqpConfig amqpConfig;
 
     @Rule
-    public Timeout globalTimeout = Timeout.seconds(60);
+    public Timeout globalTimeout = Timeout.seconds(300);
 
     @BeforeAll
     public static void beforeAll() throws InterruptedException {
         afterAll();
+        /* create networks */
         DockerConfig.createAllNetworks();
+        /* create containers */
         DockerConfig.createContainer(null, CONTAINER_BROKER, 15672, CONTAINER_BROKER_ENV);
         DockerConfig.startContainer(CONTAINER_BROKER);
     }
@@ -104,7 +96,11 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    public void updateConsumers_succeeds() throws AmqpException, IOException, InterruptedException {
+    public void updateConsumers_succeeds() throws IOException, InterruptedException {
+
+        /* pre-condition */
+        assertEquals(0, getConsumers().size());
+        assertEquals(2, amqpConfig.getAmqpConsumers());
 
         /* mock */
         channel.exchangeDeclare(DATABASE_1_EXCHANGE, BuiltinExchangeType.FANOUT);
@@ -114,21 +110,23 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest {
         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());
+        Thread.sleep(30 * 1000) /* wait for scheduled insert */;
+        final List<ConsumerDto> response = getConsumers();
+        final List<ConsumerDto> consumers1 = response.stream().filter(c -> c.getQueue().getName().equals(TABLE_1_QUEUE_NAME)).collect(Collectors.toList());
+        assertEquals(2, consumers1.size());
+        final List<ConsumerDto> consumers2 = response.stream().filter(c -> c.getQueue().getName().equals(TABLE_2_QUEUE_NAME)).collect(Collectors.toList());
+        assertEquals(2, consumers2.size());
+        final List<ConsumerDto> consumers3 = response.stream().filter(c -> c.getQueue().getName().equals(TABLE_3_QUEUE_NAME)).collect(Collectors.toList());
+        assertEquals(2, consumers3.size());
+    }
+
+    private List<ConsumerDto> getConsumers() throws IOException {
+        return rabbitMqConfig.findAllConsumers()
+                .stream()
+                .filter(c -> List.of(TABLE_1_QUEUE_NAME, TABLE_2_QUEUE_NAME, TABLE_3_QUEUE_NAME).contains(c.getQueue().getName()))
+                .collect(Collectors.toList());
     }
 
 }
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 d8d59487f6..834eb21836 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.*;
@@ -45,9 +47,14 @@ public class ViewIdxRepositoryIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private UserRepository userRepository;
 
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 4000a15599..eddcffdc8e 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 29d3e0f2d8..ba53952bab 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 ba2db43d65..421304d117 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
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 0fe3b659ef..49a47646b2 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
@@ -8,6 +8,8 @@ import at.tuwien.config.DockerConfig;
 import at.tuwien.config.IndexConfig;
 import at.tuwien.config.ReadyConfig;
 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;
@@ -53,11 +55,16 @@ 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;
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 17e9cb979b..3307d1bf81 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.*;
@@ -51,9 +53,14 @@ public class StoreServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private Channel channel;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private TableRepository tableRepository;
 
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 14b294520f..87c8fa13f7 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;
 
@@ -94,6 +101,7 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
         /* metadata db */
         imageRepository.save(IMAGE_1);
         containerRepository.save(CONTAINER_1);
+        DATABASE_1.setTables(List.of());
         databaseRepository.save(DATABASE_1);
     }
 
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 69ce154d9f..4a523c0a23 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 d827ec5bfa..c2cf5c3008 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
@@ -9,13 +9,10 @@ import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.database.View;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.BrokerServiceGateway;
 import at.tuwien.listener.impl.RabbitMqListenerImpl;
 import at.tuwien.repository.elastic.ViewIdxRepository;
 import at.tuwien.repository.jpa.*;
-import com.github.dockerjava.api.command.CreateContainerResponse;
-import com.github.dockerjava.api.exception.NotModifiedException;
-import com.github.dockerjava.api.model.Bind;
-import com.github.dockerjava.api.model.Network;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.AfterAll;
@@ -30,12 +27,10 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.File;
 import java.sql.SQLException;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
-import static at.tuwien.config.DockerConfig.*;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
@@ -60,9 +55,14 @@ public class ViewServiceIntegrationTest extends BaseUnitTest {
     @MockBean
     private ViewIdxRepository viewIdxRepository;
 
+    /* keep */
     @MockBean
     private RabbitMqListenerImpl rabbitMqListener;
 
+    /* keep */
+    @MockBean
+    private BrokerServiceGateway brokerServiceGateway;
+
     @MockBean
     private DatabaseRepository databaseRepository;
 
diff --git a/fda-query-service/rest-service/src/test/resources/application.properties b/fda-query-service/rest-service/src/test/resources/application.properties
index aac636db15..4eea490a91 100644
--- a/fda-query-service/rest-service/src/test/resources/application.properties
+++ b/fda-query-service/rest-service/src/test/resources/application.properties
@@ -19,12 +19,14 @@ spring.jpa.show-sql=false
 
 # additional logging
 logging.level.root=error
-logging.level.at.tuwien.=info
+logging.level.at.tuwien.=trace
 
 # broker service
-spring.rabbitmq.host=broker-service
+spring.rabbitmq.host=dbrepo-broker-service
 spring.rabbitmq.username=guest
 spring.rabbitmq.password=guest
 
 # search service
-fda.elastic.endpoint=search-mock-service:9200
\ No newline at end of file
+fda.consumers=2
+fda.gateway.endpoint: http://localhost:15672
+fda.elastic.endpoint=dbrepo-search-service:9200
\ No newline at end of file
diff --git a/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv b/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv
deleted file mode 100644
index 9bfb33891d..0000000000
--- 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 8a5bc1c3f1..e8f0b9c364 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 16afe426ad..4629fbe4cc 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/MessageQueueListener.java b/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java
index ebdc5a4739..afac64a7a0 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,10 @@
 package at.tuwien.listener;
 
+import at.tuwien.exception.AmqpException;
+import org.springframework.scheduling.annotation.Scheduled;
+
 public interface MessageQueueListener {
+
+    @Scheduled(fixedDelay = 5000)
+    void updateConsumers() throws AmqpException;
 }
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 1423461dd1..bc45a78888 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
@@ -14,7 +14,6 @@ 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
@@ -35,6 +34,7 @@ public class RabbitMqListenerImpl implements MessageQueueListener {
         this.brokerServiceGateway = brokerServiceGateway;
     }
 
+    @Override
     @Scheduled(fixedDelay = 5000)
     @Transactional(readOnly = true)
     public void updateConsumers() throws AmqpException {
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 0000000000..7c49211efb
--- /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/ViewMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java
index 35bcfffb45..04234f583f 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/QueryService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
index 686e0c78ec..01924d9fb2 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
@@ -165,7 +165,7 @@ public interface QueryService {
     QueryResultDto viewFindAll(Long containerId, Long databaseId, View view,
                                Long page, Long size, Principal principal) throws ViewNotFoundException, DatabaseNotFoundException,
             ImageNotSupportedException, DatabaseConnectionException, ViewMalformedException, PaginationException,
-            ContainerNotFoundException, QueryMalformedException, UserNotFoundException;
+            ContainerNotFoundException, QueryMalformedException, UserNotFoundException, TableMalformedException;
 
     /**
      * Finds one query by container-database-query triple.
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 0bd5f0c992..0c84ec5bb7 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
@@ -101,7 +101,7 @@ 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 String statement = queryMapper.queryToRawTimestampedQuery(query.getQuery(), database, query.getCreated(), true, page, size);
         final QueryResultDto dto = executeNonPersistent(containerId, databaseId, statement, columns);
@@ -143,7 +143,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
         }
     }
 
-    private QueryResultDto executeNonPersistent(Long containerId, Long databaseId, String statement, List<TableColumn> columns) throws QueryMalformedException, DatabaseNotFoundException {
+    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());
@@ -156,14 +157,15 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             final ResultSet resultSet = preparedStatement.executeQuery();
             return queryMapper.resultListToQueryResultDto(columns, resultSet);
         } catch (SQLException e) {
-            log.error("Failed to map object: {}", e.getMessage());
-            throw new QueryMalformedException("Failed to map object", 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.getMessage(), e);
         } finally {
             dataSource.close();
         }
     }
 
-    private Long executeCountNonPersistent(Long containerId, Long databaseId, String statement) throws QueryMalformedException, TableMalformedException, DatabaseNotFoundException, QueryStoreException {
+    private Long executeCountNonPersistent(Long containerId, Long databaseId, String statement)
+            throws QueryMalformedException, TableMalformedException, DatabaseNotFoundException, QueryStoreException {
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
         final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
@@ -177,7 +179,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             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();
         }
@@ -187,8 +189,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
     @Transactional(readOnly = true)
     public 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 {
+            ImageNotSupportedException, TableMalformedException, QueryMalformedException {
         /* find */
         final Table table = tableService.find(containerId, databaseId, tableId);
         /* run query */
@@ -199,9 +200,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
     @Override
     @Transactional(readOnly = true)
     public QueryResultDto viewFindAll(Long containerId, Long databaseId, View view,
-                                      Long page, Long size, Principal principal) throws ViewNotFoundException, DatabaseNotFoundException,
-            ImageNotSupportedException, DatabaseConnectionException, ViewMalformedException, PaginationException,
-            ContainerNotFoundException, QueryMalformedException, UserNotFoundException {
+                                      Long page, Long size, Principal principal) throws DatabaseNotFoundException,
+            ImageNotSupportedException, QueryMalformedException, TableMalformedException {
         /* find */
         /* run query */
         String statement = queryMapper.viewToRawFindAllQuery(view, size, page);
@@ -231,9 +231,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
 
     @Transactional(readOnly = true)
     public QueryResultDto findAllView(Long containerId, Long databaseId, Long viewId, Instant timestamp, Long page,
-                                  Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
-            ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException,
-            ContainerNotFoundException, QueryMalformedException, UserNotFoundException {
+                                      Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, TableMalformedException, QueryMalformedException {
         /* find */
         final Table table = tableService.find(containerId, databaseId, viewId);
         /* run query */
@@ -244,9 +243,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
     @Override
     @Transactional(readOnly = true)
     public ExportResource tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
-            throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
-            DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException,
-            FileStorageException, QueryMalformedException, UserNotFoundException {
+            throws TableNotFoundException, DatabaseNotFoundException, FileStorageException, QueryMalformedException {
         final String filename = RandomStringUtils.randomAlphabetic(40) + ".csv";
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
@@ -266,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();
         }
@@ -319,7 +316,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
     @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);
@@ -334,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();
         }
@@ -351,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 */
@@ -364,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();
         }
@@ -397,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();
         }
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 ff9d2c1e77..d971603dd8 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -83,9 +83,9 @@ public abstract class BaseUnitTest {
 
     public final static String DATABASE_NET = "fda-userdb";
 
-    public final static String BROKER_NAME = "fda-broker-service";
-    public final static String BROKER_IP = "172.29.0.2";
-    public final static String BROKER_HOSTNAME = "broker-service";
+    public final static String BROKER_NAME = "dbrepo-broker-service";
+    public final static String BROKER_IP = "172.31.0.2";
+    public final static String BROKER_HOSTNAME = "dbrepo-broker-service";
     public final static Integer BROKER_MANAGEMENT_PORT = 15672;
     public final static String BROKER_IMAGE = "rabbitmq";
     public final static String BROKER_TAG = "3-management-alpine";
@@ -146,24 +146,24 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_1_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
     public final static String CONTAINER_1_NAME = "u01";
-    public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01";
-    public final static String CONTAINER_1_IP = "172.28.0.5";
+    public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
+    public final static String CONTAINER_1_IP = "172.30.0.5";
     public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS);
 
     public final static Long CONTAINER_2_ID = 2L;
     public final static String CONTAINER_2_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_1;
     public final static String CONTAINER_2_NAME = "u02";
-    public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02";
-    public final static String CONTAINER_2_IP = "172.28.0.6";
+    public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02";
+    public final static String CONTAINER_2_IP = "172.30.0.6";
     public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS);
 
     public final static Long CONTAINER_3_ID = 3L;
     public final static String CONTAINER_3_HASH = "deadbeef";
     public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_1;
     public final static String CONTAINER_3_NAME = "u03";
-    public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03";
-    public final static String CONTAINER_3_IP = "172.28.0.7";
+    public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03";
+    public final static String CONTAINER_3_IP = "172.30.0.7";
     public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS);
 
     public final static Long DATABASE_1_ID = 1L;
@@ -739,7 +739,7 @@ public abstract class BaseUnitTest {
     public final static String CONTAINER_NGINX_NET = "fda-public";
     public final static String CONTAINER_NGINX_NAME = "file-service";
     public final static String CONTAINER_NGINX_INTERNALNAME = "fda-test-file-service";
-    public final static String CONTAINER_NGINX_IP = "172.29.0.3";
+    public final static String CONTAINER_NGINX_IP = "172.31.0.3";
     public final static Instant CONTAINER_NGINX_CREATED = Instant.now().minus(3, HOURS);
 
     public final static Long CONCEPT_1_ID = 1L;
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java b/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java
index 6cf55041ba..26d1b50051 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 300e882c68..1b5a0ecb18 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 0592842109..49fc8fef9e 100644
--- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
+++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
@@ -98,14 +98,14 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
                 .withName("fda-userdb")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.28.0.0/16")))
+                                .withSubnet("172.30.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         dockerClient.createNetworkCmd()
                 .withName("fda-public")
                 .withIpam(new Network.Ipam()
                         .withConfig(new Network.Ipam.Config()
-                                .withSubnet("172.29.0.0/16")))
+                                .withSubnet("172.31.0.0/16")))
                 .withEnableIpv6(false)
                 .exec();
         /* create container */
diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java b/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
index 6caf0d930e..dfc90d2ea2 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 0c83f47701..a6a8dd571f 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 ccda5111b9..a4841b7947 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 43a88f37d8..0000000000
--- 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 402ce356e6..0000000000
--- 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 b7d21fc55b..0df37b3162 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 0000000000..ab94f978c1
--- /dev/null
+++ b/fda-ui/components/DatabaseList.vue
@@ -0,0 +1,192 @@
+<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 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,
+      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=100')
+        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 96227d2816..5e5f6772b1 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 c326f81505..456a8f6b08 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 350f5a1e50..c138b2e7dc 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 ef511dbd6e..b2aff93d4e 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/Persist.vue b/fda-ui/components/dialogs/Persist.vue
index f57c31ec22..a8595e18fd 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 218ec97969..311aac14f2 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)
     },
diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue
index 03887d4bed..c49740af9e 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,17 @@ 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, data } = error.response
+        if (status === 405) {
+          const table = this.database.tables.filter(t => t.id === Number(this.$route.params.table_id))[0]
+          console.debug('====>', table, this.$route.params.table_id)
+          this.$store.commit('SET_TABLE', table)
+        } else {
+          const { message } = data
+          console.error('Failed to load table', error)
+          this.$toast.error(`Failed to load table: ${message}`)
+        }
       }
       this.loading = false
     },
diff --git a/fda-ui/package.json b/fda-ui/package.json
index de4d543b89..1649177b07 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 6b48493049..b9224362e6 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 47c5a02fe7..4ca589d152 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 () {
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 63f3d69a7d..a22d9092ed 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 c532c2814e..b401b043bf 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>
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 50e51aaafa..9a27f6db5c 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 712dafbd36..72022b57c9 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/index.vue b/fda-ui/pages/container/index.vue
index f2036ed2d7..b442a2e51a 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 />
     <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
@@ -256,29 +89,8 @@ export default {
       this.createDbDialog = false
       if (event.success) {
         this.loadContainers()
-          .then(() => this.loadDatabases())
       }
-    },
-    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 af20390b04..809139658b 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 c063503b90..44ee3235cf 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 a6d5489897..a466a0f922 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 d777c2b568..2b88602a4e 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 1820f89fbf..15a86e980b 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 0000000000..03c3415564
--- /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 ee391d1d6d..399bd9485e 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 0000000000..1ddae6a394
--- /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 0000000000..b2fbc9868e
--- /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 0000000000..d25e27a274
--- /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 208280da77..0000000000
--- 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 af97f55145..1721491863 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 0000000000..4b6a0f0be0
--- /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 5e8dde7871..2cb3310639 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 e302f9ae08..421217b621 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"
-- 
GitLab