diff --git a/.docs/api/identity-service.md b/.docs/api/identity-service.md
index 1fe3454956aca84b3c38e174e1f16705afa5360b..e01ad63fc2bb3ac06d84dccf1d61765d84ddad87 100644
--- a/.docs/api/identity-service.md
+++ b/.docs/api/identity-service.md
@@ -12,10 +12,13 @@ author: Martin Weise
 
 ## Overview
 
-This service holds the user identities which we simply call identities in the following. It is integrated into the 
-[Auth Service](../auth-service) through an LDAP federation, allowing any identity to authenticate through the Auth
-Service. The LDAP protocol is not used for authentication. You can use your own identity provider, e.g. Active
-Directory.
+This optional service holds the user identities which we simply call identities in the following. It is integrated into
+the [Auth Service](../auth-service) through an LDAP federation, allowing any identity to authenticate through the Auth
+Service. The LDAP protocol is not used for authentication. 
+
+The Identity Service can be optionally replaced with your existing LDAP solution. Your LDAP solution should store
+users using the RFC 2798 [`InetOrgPerson`](https://datatracker.ietf.org/doc/html/rfc2798) schema which is standard
+to most LDAP solutions.
 
 ## Identities
 
@@ -23,6 +26,9 @@ Any identity is identified by its `entryUUID` by default in the Auth Service. No
 the Auth Service) may assign a different UUID to a user. DBRepo **always** uses the UUID provided through the Identity
 Service.
 
+The field `uid` is the username and is used for bind/unbind operations. The fields `cn` and `sn` are ignored by the
+Auth Service and can be empty `""`.
+
 ## Limitations
 
 * Limited support for scaling in Kubernetes, see the
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c934e6a459b9a43c4b63ac471c65f0794a32bff3..605b27a39cfd4da5bf682351ebe00dd2ba2e7669 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -100,6 +100,7 @@ build-data-service:
   dependencies:
     - build-metadata-service
   script:
+    - "mvn -f ./dbrepo-metadata-service/pom.xml clean install $MAVEN_OPTS -DskipTests"
     - "mvn -f ./dbrepo-data-service/pom.xml clean package $MAVEN_OPTS -DskipTests"
   # Compiled classes are needed for SonarQube in later stages
   artifacts:
@@ -169,8 +170,8 @@ verify-install-script:
     - bash install.sh
     - exit 0
 
-lint-helm:
-  image: docker.io/docker:24-dind
+lint-helm-chart:
+  image: docker.io/alpine:3.20
   stage: lint
   except:
     refs:
@@ -179,8 +180,9 @@ lint-helm:
     - build-metadata-service
   dependencies:
     - build-metadata-service
+  before_script:
+    - apk add helm
   script:
-    - apk add sed helm curl
     - helm lint ./helm/dbrepo
 
 test-metadata-service:
@@ -271,7 +273,7 @@ test-search-service:
   script:
     - "pip install pipenv"
     - "pipenv install gunicorn && pipenv install --dev --system --deploy"
-    - cd ./dbrepo-search-service/ && coverage run -m pytest test/test_opensearch_client.py --junitxml=report.xml && coverage html --omit="test/*" && coverage report --omit="test/*" > ./coverage.txt
+    - cd ./dbrepo-search-service/ && coverage run -m pytest test/test_opensearch_client.py --junitxml=report.xml && coverage html --omit="test/*,omlib/*" && coverage report --omit="test/*,omlib/*" > ./coverage.txt
     - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'"
   artifacts:
     when: always
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e6a6e8d951f9c9a486408f47827d7e49ed92820f..4e9c81e56350032ae19e8ced1b1d004c71fab418 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -35,4 +35,11 @@ a couple of days at maximum, one could go directly for a PR. It's fine.
 - [ ] Change the maven version in the metadata & data services:
   - `mvn -f ./dbrepo-metadata-service/pom.xml versions:set -DnewVersion=VERSION`
   - `mvn -f ./dbrepo-data-service/pom.xml versions:set -DnewVersion=VERSION`
-- [ ] Change the versions in `versions.json` for the generated website
\ No newline at end of file
+- [ ] Change the versions in `versions.json` for the generated website
+
+Then generate the REST API-, Python Library- and Helm Chart documentation:
+
+```bash
+# optional: pip install -r ./requirements.txt
+make gen-swagger-doc gen-lib-doc gen-helm-doc
+```
\ No newline at end of file
diff --git a/dbrepo-analyse-service/app.py b/dbrepo-analyse-service/app.py
index bfc8212864933c7ec8253825d5fbe4d5dc7e7b44..c006e5777b5a14cc64dde335ddbdad185f162bbb 100644
--- a/dbrepo-analyse-service/app.py
+++ b/dbrepo-analyse-service/app.py
@@ -185,8 +185,6 @@ app.config["JWT_PUBKEY"] = '-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKE
 app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://localhost/api/auth")
 app.config["AUTH_SERVICE_CLIENT"] = os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client")
 app.config["AUTH_SERVICE_CLIENT_SECRET"] = os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG")
-app.config["ADMIN_USERNAME"] = os.getenv('ADMIN_USERNAME', 'admin')
-app.config["ADMIN_PASSWORD"] = os.getenv('ADMIN_PASSWORD', 'admin')
 app.config["S3_ACCESS_KEY_ID"] = os.getenv('S3_ACCESS_KEY_ID', 'seaweedfsadmin')
 app.config["S3_ENDPOINT"] = os.getenv('S3_ENDPOINT', 'http://localhost:9000')
 app.config["S3_EXPORT_BUCKET"] = os.getenv('S3_EXPORT_BUCKET', 'dbrepo-download')
@@ -211,8 +209,6 @@ def verify_token(token: str):
 def verify_password(username: str, password: str) -> Any:
     if username is None or username == "" or password is None or password == "":
         return False
-    if username == app.config["ADMIN_USERNAME"] and password == app.config["ADMIN_PASSWORD"]:
-        return User(username=username, roles=["admin"])
     client = KeycloakClient()
     try:
         return client.verify_jwt(access_token=client.obtain_user_token(username=username, password=password))
diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json
index 270ca00a1f59dedc2b3f9b25b7c30c73064f7c82..87eb81e777ad6fef5b893cfabea4366d035ddb7a 100644
--- a/dbrepo-auth-service/dbrepo-realm.json
+++ b/dbrepo-auth-service/dbrepo-realm.json
@@ -66,6 +66,17 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "7ee1c424-11b0-46a9-b0ed-725e9b7fc40c",
+      "name" : "default-system-roles",
+      "description" : "${default-system-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "check-foreign-database-access", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-database-view-data", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "143ba359-5fa2-451e-8296-43ecf20bb251",
       "name" : "update-semantic-concept",
@@ -104,6 +115,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "74648f9a-777e-4ef9-b97b-4c5d749d862f",
+      "name" : "update-search-index",
+      "description" : "${update-search-index}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "22492b64-c633-48a0-9678-b28669f2885b",
       "name" : "execute-semantic-query",
@@ -131,14 +150,6 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
-    }, {
-      "id" : "79534da1-4c85-409e-810e-a7ce6d632b09",
-      "name" : "system",
-      "description" : "${system}",
-      "composite" : false,
-      "clientRole" : false,
-      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
-      "attributes" : { }
     }, {
       "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3",
       "name" : "view-database-view-data",
@@ -389,6 +400,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "b05e9b2b-748d-490b-949b-e78655bf7805",
+      "name" : "check-foreign-database-access",
+      "description" : "${check-foreign-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "c047d521-cec3-4444-86c4-aef098489b7b",
       "name" : "delete-maintenance-message",
@@ -397,6 +416,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "88f82262-be80-4d18-9fb4-5529da031f33",
+      "name" : "system",
+      "description" : "${system}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "e14ab76b-1c24-484d-ae2d-478b8457edea",
       "name" : "list-licenses",
@@ -646,6 +673,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "0c487c93-448f-4a82-8b9f-ebd8a0904bf8",
+      "name" : "find-foreign-user",
+      "description" : "${find-foreign-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "cf9735a9-fb70-4cc5-b5f4-75afc4e5654b",
       "name" : "modify-identifier-metadata",
@@ -1089,6 +1124,14 @@
     "realmRoles" : [ "default-researcher-roles" ],
     "clientRoles" : { },
     "subGroups" : [ ]
+  }, {
+    "id" : "2b9f94b4-d434-4a98-8eab-25678cfee983",
+    "name" : "system",
+    "path" : "/system",
+    "attributes" : { },
+    "realmRoles" : [ "default-system-roles" ],
+    "clientRoles" : { },
+    "subGroups" : [ ]
   } ],
   "defaultRole" : {
     "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
@@ -1107,7 +1150,7 @@
   "otpPolicyLookAheadWindow" : 1,
   "otpPolicyPeriod" : 30,
   "otpPolicyCodeReusable" : false,
-  "otpSupportedApplications" : [ "totpAppMicrosoftAuthenticatorName", "totpAppFreeOTPName", "totpAppGoogleName" ],
+  "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ],
   "webAuthnPolicyRpEntityName" : "keycloak",
   "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
   "webAuthnPolicyRpId" : "",
@@ -2095,7 +2138,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-property-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2121,7 +2164,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper" ]
       }
     } ],
     "org.keycloak.storage.UserStorageProvider" : [ {
@@ -2149,8 +2192,8 @@
           "config" : {
             "ldap.attribute" : [ "sn" ],
             "is.mandatory.in.ldap" : [ "true" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "false" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "lastName" ]
           }
         }, {
@@ -2185,17 +2228,17 @@
           "config" : {
             "membership.attribute.type" : [ "DN" ],
             "group.name.ldap.attribute" : [ "cn" ],
-            "preserve.group.inheritance" : [ "false" ],
             "membership.user.ldap.attribute" : [ "uid" ],
-            "groups.dn" : [ "cn=system,ou=users,dc=dbrepo,dc=at" ],
+            "preserve.group.inheritance" : [ "false" ],
+            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
             "mode" : [ "LDAP_ONLY" ],
             "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
-            "ignore.missing.groups" : [ "false" ],
             "membership.ldap.attribute" : [ "member" ],
-            "memberof.ldap.attribute" : [ "memberOf" ],
+            "ignore.missing.groups" : [ "false" ],
             "group.object.classes" : [ "groupOfNames" ],
-            "groups.path" : [ "/" ],
-            "drop.non.existing.groups.during.sync" : [ "false" ]
+            "memberof.ldap.attribute" : [ "memberOf" ],
+            "drop.non.existing.groups.during.sync" : [ "false" ],
+            "groups.path" : [ "/" ]
           }
         }, {
           "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb",
@@ -2205,8 +2248,8 @@
           "config" : {
             "ldap.attribute" : [ "modifyTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "true" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "modifyTimestamp" ]
           }
         }, {
@@ -2219,8 +2262,8 @@
             "attribute.force.default" : [ "false" ],
             "is.mandatory.in.ldap" : [ "true" ],
             "is.binary.attribute" : [ "false" ],
-            "always.read.value.from.ldap" : [ "false" ],
             "read.only" : [ "false" ],
+            "always.read.value.from.ldap" : [ "false" ],
             "user.model.attribute" : [ "username" ]
           }
         } ]
@@ -2229,16 +2272,16 @@
         "fullSyncPeriod" : [ "-1" ],
         "pagination" : [ "false" ],
         "startTls" : [ "false" ],
-        "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ],
         "connectionPooling" : [ "true" ],
+        "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ],
         "cachePolicy" : [ "DEFAULT" ],
         "useKerberosForPasswordAuthentication" : [ "false" ],
         "importEnabled" : [ "true" ],
         "enabled" : [ "true" ],
-        "usernameLDAPAttribute" : [ "uid" ],
-        "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
-        "bindCredential" : [ "adminpassword" ],
         "changedSyncPeriod" : [ "-1" ],
+        "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
+        "usernameLDAPAttribute" : [ "uid" ],
+        "bindCredential" : [ "admin" ],
         "lastSync" : [ "1719252666" ],
         "vendor" : [ "other" ],
         "uuidLDAPAttribute" : [ "entryUUID" ],
@@ -2304,7 +2347,7 @@
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "df1ebc5f-2037-43f5-9915-71eb4cd0ed7e",
+    "id" : "259dd7b6-01b7-433a-bda4-028857151ecd",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -2326,7 +2369,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "76ef2d26-2756-4ce1-904b-4be58e99b576",
+    "id" : "f94a4b6d-deaa-4505-be0f-544828436fa1",
     "alias" : "Authentication Options",
     "description" : "Authentication options.",
     "providerId" : "basic-flow",
@@ -2355,7 +2398,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "b0d74a54-cea7-48f2-a4c9-f35204488da6",
+    "id" : "542ca1d7-9627-4102-b843-98837ce433fb",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2377,7 +2420,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "07b964c7-4527-4071-9f7a-e50d6321d951",
+    "id" : "4f153b98-6851-440b-a022-0a14e67a9b2f",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2399,7 +2442,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "be69fd2d-1bf5-429e-9833-a76232a23904",
+    "id" : "3d791b35-d35c-40b2-bb3e-e806d72b27ee",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2421,7 +2464,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "e9d23d2a-d857-4547-a419-2fd850ed58e5",
+    "id" : "9b746104-9371-4c3f-b69f-9322cead1b08",
     "alias" : "Handle Existing Account",
     "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
     "providerId" : "basic-flow",
@@ -2443,7 +2486,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "75e1f120-8a28-4cc0-af60-26fa9d865975",
+    "id" : "7a164efe-c97b-4fbb-950d-7745359ba9a4",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2465,7 +2508,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "eeb37a0b-2f2f-47f5-9ee6-3da2c8b48ec0",
+    "id" : "4fdc5e1b-1b55-4662-8360-67d75fa22677",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2488,7 +2531,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "8637f64c-8b45-48b0-b3ba-c6e93225cce4",
+    "id" : "75893341-c338-44d8-ae27-a3fc7bfe8f2d",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2510,7 +2553,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "7ad56360-b344-4f26-9dea-1a718ed99d4e",
+    "id" : "89626b76-f4cf-4c46-934c-4408c225a44b",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2546,7 +2589,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "c6817917-1d21-4693-9171-b2e3dfde9582",
+    "id" : "4112115a-e7a7-44c2-9af5-65d538e4ba0d",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2582,7 +2625,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "7cd02437-6d05-486d-a7fe-4d1762895ded",
+    "id" : "f82a9b0a-2c0a-4cb1-96b2-6c78b0b1f14f",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2611,7 +2654,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "eb1d9721-b4a0-40a5-9236-b4fd95ca9024",
+    "id" : "3614e155-e8ce-4958-98fb-a27e4706cc70",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2626,7 +2669,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "219415d8-3bab-47a6-9d0c-8c1061ffb68a",
+    "id" : "506f9b96-5002-47c0-96e3-3830a0fcfa26",
     "alias" : "first broker login",
     "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
     "providerId" : "basic-flow",
@@ -2649,7 +2692,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ccbf8944-bd32-4aa1-a6f8-93513a3fa5a4",
+    "id" : "4b7a7e91-36db-4b27-8e2d-01a04a822980",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2671,7 +2714,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "805f972b-75ca-48c0-a390-752b32c0688a",
+    "id" : "f8ba3c2e-3952-4434-98e8-b892eea90e9e",
     "alias" : "http challenge",
     "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
     "providerId" : "basic-flow",
@@ -2693,7 +2736,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "2b15383f-ded1-4fb6-afdc-0c19f65dacc7",
+    "id" : "04c2fe01-5076-4aa4-9596-4efb4004195f",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2709,7 +2752,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "1c18c3c7-a191-426b-84a4-1ffec96562cc",
+    "id" : "d12f77e1-7733-44a2-98ff-fd75c784d721",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2745,7 +2788,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "cab07ead-2a48-4b0c-8916-2f89abe55720",
+    "id" : "91f6048c-a376-4809-8f37-c8d7a517830c",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2781,7 +2824,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "6e158077-d221-4695-b0d3-9528c5ba6bfd",
+    "id" : "7b8fb487-53b8-4533-a696-76bc05256cb1",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2797,13 +2840,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "fcb6cb09-fec5-4390-800c-00a3d49525ec",
+    "id" : "48372696-0579-45e5-b074-5e8dbdbbe7d6",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "68f9e765-81d4-47cd-b111-94d6723883c5",
+    "id" : "08df3b83-e522-42a7-9e24-9028b960bf39",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
diff --git a/dbrepo-data-db/README.md b/dbrepo-data-db/README.md
index 94eb341d841ea5150c920ada2461cf9f1302555f..c2dfb1b0c65e7e97903457dfafc7ed7d913d2b94 100644
--- a/dbrepo-data-db/README.md
+++ b/dbrepo-data-db/README.md
@@ -1 +1,5 @@
-# Data Database
\ No newline at end of file
+# Data Database
+
+S3 Import
+
+https://mariadb.com/kb/en/s3-storage-engine-system-variables/
\ No newline at end of file
diff --git a/dbrepo-data-db/enable_history_insert.cnf b/dbrepo-data-db/enable_history_insert.cnf
new file mode 100644
index 0000000000000000000000000000000000000000..7bced156c829b3dbd4d6221dfd9654045c6f501e
--- /dev/null
+++ b/dbrepo-data-db/enable_history_insert.cnf
@@ -0,0 +1 @@
+secure_timestamp="SUPER"
\ No newline at end of file
diff --git a/dbrepo-data-db/sidecar/app.py b/dbrepo-data-db/sidecar/app.py
index c88966bb00e789e8b102985a5abbdf4ec7034c90..40cb9fa4aab88e2478e9b7671043169c383e165c 100644
--- a/dbrepo-data-db/sidecar/app.py
+++ b/dbrepo-data-db/sidecar/app.py
@@ -119,8 +119,6 @@ app.config["JWT_PUBKEY"] = '-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKE
 app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://localhost/api/auth")
 app.config["AUTH_SERVICE_CLIENT"] = os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client")
 app.config["AUTH_SERVICE_CLIENT_SECRET"] = os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG")
-app.config["ADMIN_USERNAME"] = os.getenv('ADMIN_USERNAME', 'admin')
-app.config["ADMIN_PASSWORD"] = os.getenv('ADMIN_PASSWORD', 'admin')
 app.config["S3_ACCESS_KEY_ID"] = os.getenv('S3_ACCESS_KEY_ID', 'seaweedfsadmin')
 app.config["S3_ENDPOINT"] = os.getenv('S3_ENDPOINT', 'http://localhost:9000')
 app.config["S3_EXPORT_BUCKET"] = os.getenv('S3_EXPORT_BUCKET', 'dbrepo-download')
@@ -146,8 +144,6 @@ def verify_token(token: str):
 def verify_password(username: str, password: str) -> Any:
     if username is None or username == "" or password is None or password == "":
         return False
-    if username == app.config["ADMIN_USERNAME"] and password == app.config["ADMIN_PASSWORD"]:
-        return User(username=username, roles=["admin"])
     client = KeycloakClient()
     try:
         return client.verify_jwt(access_token=client.obtain_user_token(username=username, password=password))
@@ -178,7 +174,7 @@ def health():
 
 @app.route("/sidecar/import/<string:filename>", methods=["POST"], endpoint="sidecar_import")
 @metrics.gauge(name='dbrepo_sidecar_import_dataset', description='Time needed to import dataset from S3')
-@auth.login_required(role=['admin', 'import-database-data'])
+@auth.login_required(role=['import-database-data'])
 @swag_from("ds-yml/import.yml")
 def import_csv(filename):
     auth.current_user()
@@ -192,7 +188,7 @@ def import_csv(filename):
 
 @app.route("/sidecar/export/<string:filename>", methods=["POST"], endpoint="sidecar_export")
 @metrics.gauge(name='dbrepo_sidecar_export_dataset', description='Time needed to export dataset to S3')
-@auth.login_required(role=['admin', 'export-query-data', 'export-table-data'])
+@auth.login_required(role=['export-query-data', 'export-table-data'])
 @swag_from("ds-yml/export.yml")
 def import_csv(filename):
     logging.debug('endpoint export csv, filename=%s, body=%s', filename, request)
diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile
index d4016836d91bf88f09ad60279689d9b16b5d9bb8..806908a8affe8d64b0aa3d6927418eaed8cd1e1e 100644
--- a/dbrepo-data-service/Dockerfile
+++ b/dbrepo-data-service/Dockerfile
@@ -28,9 +28,9 @@ RUN apk add --no-cache curl bash jq
 
 WORKDIR /app
 
-USER 65534
+USER 1001
 
-COPY --from=build --chown=65534 ./rest-service/target/rest-service-*.jar ./data-service.jar
+COPY --from=build --chown=1001 ./rest-service/target/rest-service-*.jar ./data-service.jar
 
 # non-root port
 EXPOSE 8080
diff --git a/dbrepo-data-service/metrics.md b/dbrepo-data-service/metrics.md
index 425b58ad17e24683a606cf0a4cb9d3123412e4cf..8219898284d6a830e52f3f2f3ee4ee80dd635e52 100644
--- a/dbrepo-data-service/metrics.md
+++ b/dbrepo-data-service/metrics.md
@@ -2,18 +2,18 @@
 |-----------------------------|-------------------------------------------|
 | `dbrepo_message_receive`    | Received AMQP message from Broker Service |
 | `dbrepo_subset_create`      | Create subset                             |
-| `dbrepo_subset_data`        | Retrieved subset data                     |
+| `dbrepo_subset_data`        | Get subset data                           |
 | `dbrepo_subset_find`        | Find subset                               |
 | `dbrepo_subset_list`        | Find subsets                              |
 | `dbrepo_subset_persist`     | Persist subset                            |
-| `dbrepo_table_data_create`  | Insert a raw data tuple                   |
-| `dbrepo_table_data_delete`  | Delete table data                         |
-| `dbrepo_table_data_export`  | Export table data                         |
-| `dbrepo_table_data_history` | Find table history                        |
-| `dbrepo_table_data_import`  | Import data from a dataset                |
-| `dbrepo_table_data_list`    | Retrieve table data                       |
-| `dbrepo_table_data_update`  | Update a raw data tuple                   |
-| `dbrepo_table_schema_list`  | Find table schemas                        |
-| `dbrepo_table_statistic`    | Generate table statistic                  |
-| `dbrepo_view_data`          | Retrieve view data                        |
-| `dbrepo_view_schema_list`   | Find view schemas                         |
+| `dbrepo_table_data_create`  | Insert tuple                              |
+| `dbrepo_table_data_delete`  | Delete tuple                              |
+| `dbrepo_table_data_export`  | Get table data                            |
+| `dbrepo_table_data_history` | Get history                               |
+| `dbrepo_table_data_import`  | Import dataset                            |
+| `dbrepo_table_data_list`    | Get table data                            |
+| `dbrepo_table_data_update`  | Update tuple                              |
+| `dbrepo_table_schema_list`  | Find tables                               |
+| `dbrepo_table_statistic`    | Get table statistic                       |
+| `dbrepo_view_data`          | Get view data                             |
+| `dbrepo_view_schema_list`   | Find views                                |
diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml
index 76ead57517edb931164c3758dd1ea49c9d5c111a..fa6f32a02f94b182dbbe3b50ed6385521bcd03cb 100644
--- a/dbrepo-data-service/pom.xml
+++ b/dbrepo-data-service/pom.xml
@@ -173,6 +173,12 @@
             <artifactId>dbrepo-metadata-service-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <!-- Exceptions -->
+        <dependency>
+            <groupId>at.tuwien</groupId>
+            <artifactId>dbrepo-metadata-service-repositories</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <!-- AMPQ -->
         <dependency>
             <groupId>org.springframework.amqp</groupId>
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
index 4966e008424aa6e1f290c70b29e97d4b55e72273..133bee769c792602ae89114a218381dd913f5c93 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
@@ -41,7 +41,7 @@ public class AccessEndpoint {
     }
 
     @PostMapping("/{userId}")
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Give access",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -78,7 +78,7 @@ public class AccessEndpoint {
                                        @NotBlank @PathVariable("userId") UUID userId,
                                        @Valid @RequestBody UpdateDatabaseAccessDto data)
             throws NotAllowedException, DatabaseUnavailableException, DatabaseNotFoundException,
-            RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, ServiceException {
+            RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint give access to database, databaseId={}, userId={}", databaseId, userId);
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         final PrivilegedUserDto user = metadataServiceGateway.getPrivilegedUserById(userId);
@@ -97,7 +97,7 @@ public class AccessEndpoint {
     }
 
     @PutMapping("/{userId}")
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Update access",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -134,7 +134,7 @@ public class AccessEndpoint {
                                        @NotBlank @PathVariable("userId") UUID userId,
                                        @Valid @RequestBody UpdateDatabaseAccessDto access) throws NotAllowedException,
             DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
-            DatabaseMalformedException, ServiceException {
+            DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint modify access to database, databaseId={}, userId={}, access.type={}", databaseId, userId,
                 access.getType());
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
@@ -154,7 +154,7 @@ public class AccessEndpoint {
     }
 
     @DeleteMapping("/{userId}")
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Revoke access",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -190,7 +190,7 @@ public class AccessEndpoint {
     public ResponseEntity<Void> revoke(@NotBlank @PathVariable("databaseId") Long databaseId,
                                        @NotBlank @PathVariable("userId") UUID userId) throws NotAllowedException,
             DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
-            DatabaseMalformedException, ServiceException {
+            DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint revoke access to database, databaseId={}, userId={}", databaseId, userId);
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         final UserDto user = metadataServiceGateway.getUserById(userId);
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index 5397ba158477d9f30b05cf7707b489213dcc3920..9cefc57fa2b70db65daee6d4bc1d1ddd6434aa24 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -53,7 +53,7 @@ public class DatabaseEndpoint {
     }
 
     @PostMapping
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Create database",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -86,7 +86,7 @@ public class DatabaseEndpoint {
     })
     public ResponseEntity<DatabaseDto> create(@Valid @RequestBody CreateDatabaseDto data)
             throws DatabaseUnavailableException, RemoteUnavailableException, ContainerNotFoundException,
-            DatabaseMalformedException, QueryStoreCreateException, ServiceException {
+            DatabaseMalformedException, QueryStoreCreateException, MetadataServiceException {
         log.debug("endpoint create database, data.containerId={}, data.internalName={}, data.username={}",
                 data.getContainerId(), data.getInternalName(), data.getUsername());
         final PrivilegedContainerDto container = metadataServiceGateway.getContainerById(data.getContainerId());
@@ -108,7 +108,7 @@ public class DatabaseEndpoint {
     }
 
     @PutMapping("/{databaseId}")
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Update user password",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -134,7 +134,7 @@ public class DatabaseEndpoint {
     public ResponseEntity<Void> update(@NotBlank @PathVariable("databaseId") Long databaseId,
                                        @Valid @RequestBody UpdateUserPasswordDto data)
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
-            DatabaseMalformedException, ServiceException {
+            DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint update user password in database, databaseId={}, data.username={}", databaseId,
                 data.getUsername());
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java
index e75cd571eb49ee8bab55fb4b21cd925e9bd9948a..f4626deb93f9f1581be1ee5eab2fe748734ee4e6 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java
@@ -89,7 +89,7 @@ public class SubsetEndpoint {
                                                @RequestParam(name = "persisted", required = false) Boolean filterPersisted,
                                                Principal principal)
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
-            QueryNotFoundException, NotAllowedException, ServiceException {
+            QueryNotFoundException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}", databaseId, filterPersisted);
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         if (!database.getIsPublic()) {
@@ -156,7 +156,7 @@ public class SubsetEndpoint {
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
             QueryNotFoundException, FormatNotAvailableException, StorageUnavailableException, QueryMalformedException,
             SidecarExportException, StorageNotFoundException, NotAllowedException, UserNotFoundException,
-            ServiceException {
+            MetadataServiceException {
         String accept = httpServletRequest.getHeader("Accept");
         log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId,
                 subsetId, accept, timestamp);
@@ -260,7 +260,7 @@ public class SubsetEndpoint {
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
             QueryNotFoundException, StorageUnavailableException, QueryMalformedException, SidecarExportException,
             StorageNotFoundException, QueryStoreInsertException, TableMalformedException, PaginationException,
-            QueryNotSupportedException, NotAllowedException, UserNotFoundException, ServiceException {
+            QueryNotSupportedException, NotAllowedException, UserNotFoundException, MetadataServiceException {
         log.debug("endpoint create subset in database, databaseId={}, data.statement={}, principal.name={}, page={}, " +
                 "size={}, timestamp={}", databaseId, data.getStatement(), principal.getName(), page, size, timestamp);
         /* check */
@@ -337,7 +337,7 @@ public class SubsetEndpoint {
                                                   @RequestParam(required = false) Long size) throws PaginationException,
             DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException, QueryNotFoundException,
             DatabaseUnavailableException, TableMalformedException, QueryMalformedException, UserNotFoundException,
-            ServiceException {
+            MetadataServiceException {
         log.debug("endpoint re-execute query, databaseId={}, subsetId={}, principal.name={} page={}, size={}",
                 databaseId, subsetId, principal != null ? principal.getName() : null, page, size);
         endpointValidator.validateDataParams(page, size);
@@ -424,7 +424,7 @@ public class SubsetEndpoint {
                                             @NotNull @Valid @RequestBody QueryPersistDto data,
                                             @NotNull Principal principal) throws NotAllowedException,
             RemoteUnavailableException, DatabaseNotFoundException, QueryStorePersistException,
-            DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, ServiceException {
+            DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException {
         log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId,
                 queryId, data.getPersist(), principal.getName());
         metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
index a0200609a6001638615c7726279483f563585f97..7e95c7cfa94ae356a1e3d908c903bf7294f3621a 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
@@ -61,7 +61,7 @@ public class TableEndpoint {
     }
 
     @PostMapping
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Create table",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -95,7 +95,7 @@ public class TableEndpoint {
     public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                            @Valid @RequestBody TableCreateDto data) throws DatabaseNotFoundException,
             RemoteUnavailableException, TableMalformedException, DatabaseUnavailableException, TableExistsException,
-            TableNotFoundException, QueryMalformedException, ServiceException {
+            TableNotFoundException, QueryMalformedException, MetadataServiceException {
         log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName());
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         try {
@@ -108,7 +108,7 @@ public class TableEndpoint {
     }
 
     @DeleteMapping("/{tableId}")
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Delete table",
             security = {@SecurityRequirement(name = "basicAuth")},
             hidden = true)
@@ -137,7 +137,7 @@ public class TableEndpoint {
     public ResponseEntity<Void> delete(@NotBlank @PathVariable("databaseId") Long databaseId,
                                        @NotBlank @PathVariable("tableId") Long tableId)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
-            QueryMalformedException, ServiceException {
+            QueryMalformedException, MetadataServiceException {
         log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId);
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         try {
@@ -191,7 +191,7 @@ public class TableEndpoint {
                                                   @RequestParam(required = false) Long size,
                                                   Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
-            TableMalformedException, PaginationException, QueryMalformedException, ServiceException,
+            TableMalformedException, PaginationException, QueryMalformedException, MetadataServiceException,
             NotAllowedException {
         log.debug("endpoint find table data, databaseId={}, tableId={}, timestamp={}, page={}, size={}", databaseId,
                 tableId, timestamp, page, size);
@@ -268,7 +268,7 @@ public class TableEndpoint {
                                                @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException,
-            StorageNotFoundException, ServiceException {
+            StorageNotFoundException, MetadataServiceException {
         log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId);
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
@@ -319,7 +319,7 @@ public class TableEndpoint {
                                                @Valid @RequestBody TupleUpdateDto data,
                                                @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
-            TableMalformedException, QueryMalformedException, NotAllowedException, ServiceException {
+            TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
                 data.getKeys());
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
@@ -371,7 +371,7 @@ public class TableEndpoint {
                                                @Valid @RequestBody TupleDeleteDto data,
                                                @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
-            TableMalformedException, QueryMalformedException, NotAllowedException, ServiceException {
+            TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
                 data.getKeys());
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
@@ -424,7 +424,7 @@ public class TableEndpoint {
                                                             @NotNull @PathVariable("tableId") Long tableId,
                                                             @RequestParam(value = "size", required = false) Long size,
                                                             Principal principal) throws DatabaseUnavailableException,
-            RemoteUnavailableException, TableNotFoundException, NotAllowedException, ServiceException,
+            RemoteUnavailableException, TableNotFoundException, NotAllowedException, MetadataServiceException,
             PaginationException {
         log.debug("endpoint find table history, databaseId={}, tableId={}", databaseId, tableId);
         if (size != null && size <= 0) {
@@ -453,7 +453,7 @@ public class TableEndpoint {
     }
 
     @GetMapping
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Observed(name = "dbrepo_table_schema_list")
     @Operation(summary = "Find tables",
             hidden = true)
@@ -491,7 +491,7 @@ public class TableEndpoint {
     })
     public ResponseEntity<List<TableDto>> getSchema(@NotBlank @PathVariable("databaseId") Long databaseId)
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
-            DatabaseMalformedException, TableNotFoundException, QueryMalformedException, ServiceException {
+            DatabaseMalformedException, TableNotFoundException, MetadataServiceException {
         log.debug("endpoint inspect table schemas, databaseId={}", databaseId);
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         try {
@@ -540,7 +540,7 @@ public class TableEndpoint {
                                                           Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             NotAllowedException, StorageUnavailableException, QueryMalformedException, SidecarExportException,
-            StorageNotFoundException, ServiceException {
+            StorageNotFoundException, MetadataServiceException {
         log.debug("endpoint find table history, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp);
         /* parameters */
         if (timestamp == null) {
@@ -606,7 +606,7 @@ public class TableEndpoint {
                                               @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             QueryMalformedException, StorageNotFoundException, SidecarImportException, NotAllowedException,
-            ServiceException {
+            MetadataServiceException {
         log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation());
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
@@ -659,7 +659,7 @@ public class TableEndpoint {
     public ResponseEntity<TableStatisticDto> statistic(@NotBlank @PathVariable("databaseId") Long databaseId,
                                                        @NotBlank @PathVariable("tableId") Long tableId)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
-            ServiceException, TableMalformedException, QueryMalformedException {
+            MetadataServiceException, TableMalformedException, QueryMalformedException {
         log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId);
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         try {
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
index 3212b699a2789ca6e127c9132286f696142c57f2..e9dbfd5c3a7f3d59088f048398cd2c4f9d9d8f45 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
@@ -54,7 +54,7 @@ public class ViewEndpoint {
     }
 
     @GetMapping
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Observed(name = "dbrepo_view_schema_list")
     @Operation(summary = "Find views",
             hidden = true)
@@ -93,7 +93,7 @@ public class ViewEndpoint {
     public ResponseEntity<List<ViewDto>> getSchema(@NotBlank @PathVariable("databaseId") Long databaseId)
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
             ViewMalformedException, ViewNotFoundException, DatabaseMalformedException, ViewSchemaException,
-            ServiceException {
+            MetadataServiceException {
         log.debug("endpoint inspect view schemas, databaseId={}", databaseId);
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         try {
@@ -105,7 +105,7 @@ public class ViewEndpoint {
     }
 
     @PostMapping
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Create view",
             security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")},
             hidden = true)
@@ -138,7 +138,7 @@ public class ViewEndpoint {
     })
     public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                           @Valid @RequestBody ViewCreateDto data) throws DatabaseUnavailableException,
-            DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, ServiceException {
+            DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException {
         log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName());
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         try {
@@ -151,7 +151,7 @@ public class ViewEndpoint {
     }
 
     @DeleteMapping("/{viewId}")
-    @PreAuthorize("hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('system')")
     @Operation(summary = "Delete view",
             security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")},
             hidden = true)
@@ -182,7 +182,7 @@ public class ViewEndpoint {
     public ResponseEntity<Void> delete(@NotBlank @PathVariable("databaseId") Long databaseId,
                                        @NotBlank @PathVariable("viewId") Long viewId)
             throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException,
-            ViewMalformedException, ServiceException {
+            ViewMalformedException, MetadataServiceException {
         log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId);
         final PrivilegedViewDto view = metadataServiceGateway.getViewById(databaseId, viewId);
         try {
@@ -243,7 +243,7 @@ public class ViewEndpoint {
                                                   Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException,
             QueryMalformedException, ViewMalformedException, PaginationException, NotAllowedException,
-            ServiceException {
+            MetadataServiceException {
         log.debug("endpoint get view data, databaseId={}, viewId={}, page={}, size={}, timestamp={}", databaseId,
                 viewId, page, size, timestamp);
         endpointValidator.validateDataParams(page, size);
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java
deleted file mode 100644
index 18373423c5dd58d5236670a63989134132e4685d..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java
+++ /dev/null
@@ -1,235 +0,0 @@
-package at.tuwien.handlers;
-
-import at.tuwien.api.error.ApiErrorDto;
-import at.tuwien.exception.*;
-import io.swagger.v3.oas.annotations.Hidden;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.context.request.WebRequest;
-import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
-
-@Log4j2
-@ControllerAdvice
-public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(ContainerNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(ContainerNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
-    @ExceptionHandler(DatabaseMalformedException.class)
-    public ResponseEntity<ApiErrorDto> handle(DatabaseMalformedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(DatabaseNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(DatabaseNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler(DatabaseUnavailableException.class)
-    public ResponseEntity<ApiErrorDto> handle(DatabaseUnavailableException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_ACCEPTABLE)
-    @ExceptionHandler(FormatNotAvailableException.class)
-    public ResponseEntity<ApiErrorDto> handle(FormatNotAvailableException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.FORBIDDEN)
-    @ExceptionHandler(NotAllowedException.class)
-    public ResponseEntity<ApiErrorDto> handle(NotAllowedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler(PaginationException.class)
-    public ResponseEntity<ApiErrorDto> handle(PaginationException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler(QueryMalformedException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryMalformedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(QueryNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_IMPLEMENTED)
-    @ExceptionHandler(QueryNotSupportedException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryNotSupportedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
-    @ExceptionHandler(QueryStoreCreateException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryStoreCreateException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler(QueryStoreGCException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryStoreGCException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
-    @ExceptionHandler(QueryStoreInsertException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryStoreInsertException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
-    @ExceptionHandler(QueryStorePersistException.class)
-    public ResponseEntity<ApiErrorDto> handle(QueryStorePersistException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler(RemoteUnavailableException.class)
-    public ResponseEntity<ApiErrorDto> handle(RemoteUnavailableException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.BAD_GATEWAY)
-    @ExceptionHandler(ServiceConnectionException.class)
-    public ResponseEntity<ApiErrorDto> handle(ServiceConnectionException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler(ServiceException.class)
-    public ResponseEntity<ApiErrorDto> handle(ServiceException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler(SidecarExportException.class)
-    public ResponseEntity<ApiErrorDto> handle(SidecarExportException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler(SidecarImportException.class)
-    public ResponseEntity<ApiErrorDto> handle(SidecarImportException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(StorageNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(StorageNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler(StorageUnavailableException.class)
-    public ResponseEntity<ApiErrorDto> handle(StorageUnavailableException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.CONFLICT)
-    @ExceptionHandler(TableExistsException.class)
-    public ResponseEntity<ApiErrorDto> handle(TableExistsException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler(TableMalformedException.class)
-    public ResponseEntity<ApiErrorDto> handle(TableMalformedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(TableNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(TableNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.CONFLICT)
-    @ExceptionHandler(TableSchemaException.class)
-    public ResponseEntity<ApiErrorDto> handle(TableSchemaException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(UserNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(UserNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler(ViewMalformedException.class)
-    public ResponseEntity<ApiErrorDto> handle(ViewMalformedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler(ViewNotFoundException.class)
-    public ResponseEntity<ApiErrorDto> handle(ViewNotFoundException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    @Hidden
-    @ResponseStatus(code = HttpStatus.CONFLICT)
-    @ExceptionHandler(ViewSchemaException.class)
-    public ResponseEntity<ApiErrorDto> handle(ViewSchemaException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
-    }
-
-    private ResponseEntity<ApiErrorDto> generic_handle(Class<?> exceptionClass, String message) {
-        final HttpHeaders headers = new HttpHeaders();
-        headers.set("Content-Type", "application/problem+json");
-        final ResponseStatus annotation = exceptionClass.getAnnotation(ResponseStatus.class);
-        final ApiErrorDto response = ApiErrorDto.builder()
-                .status(annotation.code())
-                .message(message)
-                .code(annotation.reason())
-                .build();
-        return new ResponseEntity<>(response, headers, response.getStatus());
-    }
-
-}
diff --git a/dbrepo-data-service/rest-service/src/main/resources/application-local.yml b/dbrepo-data-service/rest-service/src/main/resources/application-local.yml
index 5a6dc187e80cde15b38961c77875d4e2fde0ff98..fc5445ce78e9a1f29ae6fd0f3d2d918dcb30a277 100644
--- a/dbrepo-data-service/rest-service/src/main/resources/application-local.yml
+++ b/dbrepo-data-service/rest-service/src/main/resources/application-local.yml
@@ -57,15 +57,14 @@ dbrepo:
     secretAccessKey: seaweedfsadmin
     importBucket: dbrepo-upload
     exportBucket: dbrepo-download
-    filePath: /tmp
-  admin:
+  system:
     username: admin
     password: admin
   jwt:
     public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB
   keycloak:
-    username: fda
-    password: fda
+    username: admin
+    password: admin
     client: dbrepo-client
     clientSecret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG
   defaultDateFormatId: 1
diff --git a/dbrepo-data-service/rest-service/src/main/resources/application.yml b/dbrepo-data-service/rest-service/src/main/resources/application.yml
index 93f31ab5ae3020352e56bea4c890fe81c26e7f31..2043395f307070c0e95b9d442d5baa9b7bb58951 100644
--- a/dbrepo-data-service/rest-service/src/main/resources/application.yml
+++ b/dbrepo-data-service/rest-service/src/main/resources/application.yml
@@ -59,9 +59,9 @@ dbrepo:
     importBucket: "${S3_IMPORT_BUCKET:dbrepo-upload}"
     exportBucket: "${S3_EXPORT_BUCKET:dbrepo-download}"
     filePath: "${S3_FILE_PATH:/tmp}"
-  admin:
-    username: "${ADMIN_USERNAME:admin}"
-    password: "${ADMIN_PASSWORD:admin}"
+  system:
+    username: "${SYSTEM_USERNAME:admin}"
+    password: "${SYSTEM_PASSWORD:admin}"
   jwt:
     public_key: "${JWT_PUBKEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}"
   keycloak:
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java
index 54af799db3fd021475222be7fac444ad83ed4535..8f73fa1b53b41be7d8cbfbe71f25a27c94ccbb01 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java
@@ -177,7 +177,8 @@ public class MariaDbConfig {
             if (set.next()) {
                 final Matcher matcher = Pattern.compile("GRANT (.*) ON.*").matcher(set.getString(1));
                 if (matcher.find()) {
-                    final List<String> privileges = Arrays.asList(matcher.group(1).split(","));;
+                    final List<String> privileges = Arrays.asList(matcher.group(1).split(","));
+                    ;
                     log.trace("found privileges: {}", privileges);
                     return privileges;
                 }
@@ -224,7 +225,7 @@ public class MariaDbConfig {
     public static Long mockUserQueryInsert(PrivilegedDatabaseDto database, String query, String username, String password)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
-        log.trace("connect to database {}", jdbc);
+        log.trace("connect to database: {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, username, password)) {
             final String call = "{call store_query(?,?,?)}";
             log.trace("prepare procedure '{}'", call);
@@ -255,7 +256,7 @@ public class MariaDbConfig {
 
     public static void insertQueryStore(PrivilegedDatabaseDto database, QueryDto query, UUID userId) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
-        log.trace("connect to database {}", jdbc);
+        log.trace("connect to database: {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
             final PreparedStatement prepareStatement = connection.prepareStatement(
                     "INSERT INTO qs_queries (created_by, query, query_normalized, is_persisted, query_hash, result_hash, result_number, created, executed) VALUES (?,?,?,?,?,?,?,?,?)");
@@ -332,13 +333,27 @@ public class MariaDbConfig {
     public static void execute(PrivilegedContainerDto container, String query)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort();
-        log.trace("connect to database {}", jdbc);
+        log.trace("connect to database: {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) {
             final Statement statement = connection.createStatement();
             statement.executeUpdate(query);
         }
     }
 
+    public static void dropQueryStore(PrivilegedDatabaseDto database)
+            throws SQLException {
+        final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
+        log.trace("connect to database: {}", jdbc);
+        try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
+            final Statement statement = connection.createStatement();
+            statement.executeUpdate("DROP SEQUENCE IF EXISTS `qs_queries_seq`;");
+            statement.executeUpdate("DROP TABLE IF EXISTS `qs_queries`;");
+            statement.executeUpdate("DROP PROCEDURE IF EXISTS `hash_table`;");
+            statement.executeUpdate("DROP PROCEDURE IF EXISTS `store_query`;");
+            statement.executeUpdate("DROP PROCEDURE IF EXISTS `_store_query`;");
+        }
+    }
+
     public static Map<String, List<Object>> describeTableSchema(PrivilegedTableDto table, String username, String password)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + table.getDatabase().getContainer().getHost() + ":" + table.getDatabase().getContainer().getPort() + "/" + table.getDatabase().getInternalName();
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java
index 0a69255f1056de6e8f02e671d6835f2daef2640b..1dc008dbebffdd0a02ef0ffb12a12b9f6e8e6f08 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java
@@ -42,9 +42,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_succeeds() throws UserNotFoundException, NotAllowedException, DatabaseUnavailableException,
-            DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, ServiceException {
+            DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -57,9 +57,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_alreadyAccess_fails() throws UserNotFoundException, DatabaseNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -74,9 +74,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -90,9 +90,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_userNotFound_fails() throws UserNotFoundException, DatabaseNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -118,9 +118,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void update_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
-            NotAllowedException, DatabaseUnavailableException, DatabaseMalformedException, ServiceException {
+            NotAllowedException, DatabaseUnavailableException, DatabaseMalformedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -143,9 +143,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void update_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -159,9 +159,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void update_userNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            UserNotFoundException, ServiceException {
+            UserNotFoundException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -177,9 +177,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void revoke_succeeds() throws UserNotFoundException, NotAllowedException, DatabaseUnavailableException,
-            DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, ServiceException,
+            DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, MetadataServiceException,
             SQLException {
 
         /* mock */
@@ -206,9 +206,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void revoke_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -222,9 +222,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void revoke_userNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            UserNotFoundException, ServiceException {
+            UserNotFoundException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
index aa424e3aa60a3e64d0b835254506706f1f8bc7b6..c2b04d5aa914b86ef3edde0ebdf5d82f130c1e40 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
@@ -52,9 +52,9 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException,
-            QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException, ServiceException {
+            QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException, MetadataServiceException {
 
         /* test */
         databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL);
@@ -63,7 +63,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void create_noRole_fails() throws RemoteUnavailableException, ContainerNotFoundException,
-            SQLException, QueryStoreCreateException, DatabaseMalformedException, ServiceException {
+            SQLException, QueryStoreCreateException, DatabaseMalformedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
@@ -84,9 +84,9 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_containerNotFound_fails() throws RemoteUnavailableException, ContainerNotFoundException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(ContainerNotFoundException.class)
@@ -100,9 +100,9 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_queryStore_fails() throws RemoteUnavailableException, ContainerNotFoundException, SQLException,
-            DatabaseMalformedException, QueryStoreCreateException, ServiceException {
+            DatabaseMalformedException, QueryStoreCreateException, MetadataServiceException {
 
         /* mock */
         doThrow(ContainerNotFoundException.class)
@@ -121,9 +121,9 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void update_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException,
-            DatabaseMalformedException, DatabaseNotFoundException, ServiceException {
+            DatabaseMalformedException, DatabaseNotFoundException, MetadataServiceException {
 
         /* test */
         databaseEndpoint.update(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
@@ -131,7 +131,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
-    public void update_noRole_fails() throws RemoteUnavailableException, DatabaseNotFoundException, ServiceException {
+    public void update_noRole_fails() throws RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -144,9 +144,9 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void update_databaseNotFound_fails() throws RemoteUnavailableException, DatabaseNotFoundException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -160,9 +160,9 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void update_password_fails() throws RemoteUnavailableException, DatabaseNotFoundException, SQLException,
-            DatabaseMalformedException, ServiceException {
+            DatabaseMalformedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java
index 6cdb0c6753488d84be16798636d46d42c139392f..c45454b8f3c3ac8238726755e0eda19c063ed1f8 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java
@@ -66,7 +66,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void findAllById_succeeds() throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException,
-            DatabaseNotFoundException, RemoteUnavailableException, SQLException, ServiceException {
+            DatabaseNotFoundException, RemoteUnavailableException, SQLException, MetadataServiceException {
 
         /* test */
         final List<QueryDto> response = generic_findAllById(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO, null);
@@ -98,7 +98,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void findById_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException,
             QueryNotFoundException, SidecarExportException, FormatNotAvailableException, StorageNotFoundException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
@@ -113,7 +113,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void findById_acceptCsv_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, NotAllowedException,
             QueryMalformedException, QueryNotFoundException, SidecarExportException, FormatNotAvailableException,
-            StorageNotFoundException, SQLException, ServiceException {
+            StorageNotFoundException, SQLException, MetadataServiceException {
         final ExportResourceDto mock = ExportResourceDto.builder()
                 .filename("deadbeef")
                 .resource(new InputStreamResource(InputStream.nullInputStream()))
@@ -134,7 +134,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void findById_timestamp_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, NotAllowedException,
             QueryMalformedException, QueryNotFoundException, SidecarExportException, FormatNotAvailableException,
-            StorageNotFoundException, SQLException, ServiceException {
+            StorageNotFoundException, SQLException, MetadataServiceException {
         final ExportResourceDto mock = ExportResourceDto.builder()
                 .filename("deadbeef")
                 .resource(new InputStreamResource(InputStream.nullInputStream()))
@@ -152,7 +152,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ServiceException {
+    public void findById_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -171,7 +171,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, SidecarExportException, QueryNotSupportedException, PaginationException,
             StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException,
             QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final ExecuteStatementDto request = ExecuteStatementDto.builder()
                 .statement(QUERY_5_STATEMENT)
                 .build();
@@ -207,7 +207,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
             TableMalformedException, NotAllowedException, SidecarExportException, QueryNotSupportedException,
             PaginationException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException,
             QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final ExecuteStatementDto request = ExecuteStatementDto.builder()
                 .statement(QUERY_5_STATEMENT)
                 .build();
@@ -227,7 +227,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
     public void create_databaseNotFound_fails() throws NotAllowedException, RemoteUnavailableException,
-            DatabaseNotFoundException, ServiceException {
+            DatabaseNotFoundException, MetadataServiceException {
         final ExecuteStatementDto request = ExecuteStatementDto.builder()
                 .statement(QUERY_5_STATEMENT)
                 .build();
@@ -260,7 +260,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_4_USERNAME, authorities = {"execute-query"})
-    public void create_noAccess_fails() throws NotAllowedException, RemoteUnavailableException, ServiceException {
+    public void create_noAccess_fails() throws NotAllowedException, RemoteUnavailableException, MetadataServiceException {
         final ExecuteStatementDto request = ExecuteStatementDto.builder()
                 .statement(QUERY_5_STATEMENT)
                 .build();
@@ -279,7 +279,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException,
-            DatabaseUnavailableException, PaginationException, ServiceException {
+            DatabaseUnavailableException, PaginationException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
@@ -308,7 +308,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     public void getData_onlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException,
-            DatabaseUnavailableException, PaginationException, ServiceException {
+            DatabaseUnavailableException, PaginationException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
@@ -332,7 +332,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME)
     public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException,
-            QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, ServiceException {
+            QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -358,7 +358,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getData_privateAnonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -373,7 +373,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME)
     public void getData_privateNoAccess_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -392,7 +392,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME)
     public void getData_privateOnlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException,
-            QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, ServiceException {
+            QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -416,7 +416,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"})
     public void persist_succeeds() throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException,
             QueryStorePersistException, SQLException, UserNotFoundException, QueryNotFoundException,
-            DatabaseUnavailableException, ServiceException {
+            DatabaseUnavailableException, MetadataServiceException {
         final QueryPersistDto request = QueryPersistDto.builder()
                 .persist(true)
                 .build();
@@ -451,7 +451,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"})
-    public void persist_noAccess_fails() throws NotAllowedException, RemoteUnavailableException, ServiceException {
+    public void persist_noAccess_fails() throws NotAllowedException, RemoteUnavailableException, MetadataServiceException {
         final QueryPersistDto request = QueryPersistDto.builder()
                 .persist(true)
                 .build();
@@ -470,7 +470,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"})
     public void persist_databaseNotFound_fails() throws NotAllowedException, RemoteUnavailableException,
-            DatabaseNotFoundException, ServiceException {
+            DatabaseNotFoundException, MetadataServiceException {
         final QueryPersistDto request = QueryPersistDto.builder()
                 .persist(true)
                 .build();
@@ -490,7 +490,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     protected List<QueryDto> generic_findAllById(Long databaseId, PrivilegedDatabaseDto database, Principal principal)
             throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException,
-            RemoteUnavailableException, SQLException, ServiceException {
+            RemoteUnavailableException, SQLException, MetadataServiceException {
 
         /* mock */
         if (database != null) {
@@ -514,7 +514,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                                     Principal principal) throws UserNotFoundException, DatabaseUnavailableException,
             StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException,
             DatabaseNotFoundException, SidecarExportException, RemoteUnavailableException, FormatNotAvailableException,
-            StorageNotFoundException, SQLException, ServiceException {
+            StorageNotFoundException, SQLException, MetadataServiceException {
 
         /* mock */
         when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, subsetId))
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java
index 022b043caadc66ec495402fb2f05afb1ccf711ce..29a33d1d9cbb3dd95a5640610d7620a36d1800db 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java
@@ -52,10 +52,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException,
             DatabaseNotFoundException, TableExistsException, RemoteUnavailableException, SQLException,
-            TableNotFoundException, QueryMalformedException, ServiceException {
+            TableNotFoundException, QueryMalformedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -79,9 +79,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -95,9 +95,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void delete_succeeds() throws RemoteUnavailableException, DatabaseUnavailableException,
-            TableNotFoundException, QueryMalformedException, SQLException, ServiceException {
+            TableNotFoundException, QueryMalformedException, SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
@@ -122,9 +122,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void delete_tableNotFound_fails() throws RemoteUnavailableException, TableNotFoundException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(TableNotFoundException.class)
@@ -140,7 +140,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException,
-            SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, ServiceException,
+            SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, MetadataServiceException,
             NotAllowedException {
 
         /* mock */
@@ -166,7 +166,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(TableNotFoundException.class)
@@ -183,7 +183,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void createTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
-            SQLException, StorageUnavailableException, StorageNotFoundException, ServiceException {
+            SQLException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -227,7 +227,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void createTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -249,7 +249,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void createTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -273,7 +273,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void createTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
-            StorageUnavailableException, StorageNotFoundException, ServiceException {
+            StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -294,7 +294,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void createTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -318,7 +318,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void createTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
-            StorageUnavailableException, StorageNotFoundException, ServiceException {
+            StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -340,7 +340,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -390,7 +390,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -415,7 +415,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -442,7 +442,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_writeOwnAccess_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -473,7 +473,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -500,7 +500,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -532,7 +532,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -574,7 +574,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -595,7 +595,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -618,7 +618,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, TableMalformedException, SQLException, QueryMalformedException,
-            DatabaseUnavailableException, ServiceException {
+            DatabaseUnavailableException, MetadataServiceException {
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -645,7 +645,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -668,7 +668,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 6L);
@@ -695,7 +695,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getHistory_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
-            RemoteUnavailableException, SQLException, NotAllowedException, ServiceException, PaginationException {
+            RemoteUnavailableException, SQLException, NotAllowedException, MetadataServiceException, PaginationException {
 
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
@@ -711,7 +711,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getHistory_privateNoRole_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
@@ -726,7 +726,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_4_USERNAME)
     public void getHistory_privateNoAccess_fails() throws NotAllowedException, RemoteUnavailableException,
-            TableNotFoundException, ServiceException {
+            TableNotFoundException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
@@ -744,7 +744,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(TableNotFoundException.class)
@@ -761,7 +761,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void exportData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, NotAllowedException,
             StorageUnavailableException, QueryMalformedException, SidecarExportException, RemoteUnavailableException,
-            StorageNotFoundException, SQLException, ServiceException {
+            StorageNotFoundException, SQLException, MetadataServiceException {
         final ExportResourceDto mock = ExportResourceDto.builder()
                 .filename("deadbeef")
                 .resource(new InputStreamResource(InputStream.nullInputStream()))
@@ -782,7 +782,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_4_USERNAME)
     public void exportData_privateNoAccess_fails() throws TableNotFoundException, NotAllowedException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
@@ -802,7 +802,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void importData_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             SidecarImportException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
-            StorageNotFoundException, SQLException, ServiceException {
+            StorageNotFoundException, SQLException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
@@ -844,7 +844,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void importData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
@@ -865,7 +865,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void importData_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
@@ -888,7 +888,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void importData_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException,
-            StorageNotFoundException, ServiceException {
+            StorageNotFoundException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
@@ -908,7 +908,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void importData_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
@@ -931,7 +931,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
     public void importData_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException,
-            StorageNotFoundException, ServiceException {
+            StorageNotFoundException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
index 9f7ad136a8dbed048cd85d3f097d1fa59bd5dac5..b9b814378e9bd537d42c421c3e3fab81d381443f 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
@@ -49,9 +49,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
-            SQLException, DatabaseUnavailableException, ServiceException {
+            SQLException, DatabaseUnavailableException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -67,7 +67,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -82,9 +82,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -98,9 +98,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void delete_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
-            SQLException, DatabaseUnavailableException, ViewNotFoundException, ServiceException {
+            SQLException, DatabaseUnavailableException, ViewNotFoundException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -117,7 +117,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void delete_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
-            SQLException, ServiceException {
+            SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
@@ -133,9 +133,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void delete_databaseNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(ViewNotFoundException.class)
@@ -152,7 +152,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
     public void getData_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException,
             SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID))
@@ -182,7 +182,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
     public void getData_onlyHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
             ViewMalformedException, SQLException, DatabaseUnavailableException, QueryMalformedException,
-            PaginationException, NotAllowedException, ServiceException {
+            PaginationException, NotAllowedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID))
@@ -209,7 +209,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
     public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         doThrow(ViewNotFoundException.class)
@@ -225,7 +225,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"view-database-view-data"})
     public void getData_privateNoAccess_fails() throws RemoteUnavailableException, ViewNotFoundException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_3_ID))
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java
index 30a4d31cfbb288b58817bc52d803d913fa353421..b00f871d5ca92797197e40b898ce95c94463b807 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java
@@ -41,7 +41,8 @@ public class DataDatabaseGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void importFile_succeeds() throws RemoteUnavailableException, StorageNotFoundException, ServiceException {
+    public void importFile_succeeds() throws RemoteUnavailableException, StorageNotFoundException,
+            SidecarImportException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class)))
@@ -75,7 +76,7 @@ public class DataDatabaseGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(SidecarImportException.class, () -> {
             dataDatabaseSidecarGateway.importFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename");
         });
     }
@@ -95,7 +96,8 @@ public class DataDatabaseGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void exportFile_succeeds() throws RemoteUnavailableException, StorageNotFoundException, ServiceException {
+    public void exportFile_succeeds() throws RemoteUnavailableException, StorageNotFoundException,
+            SidecarExportException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class)))
@@ -129,7 +131,7 @@ public class DataDatabaseGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(SidecarExportException.class, () -> {
             dataDatabaseSidecarGateway.exportFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename");
         });
     }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java
index 0fd20a8025bc209df9c645f4d2b01329660dbf03..b87793a8bcd00c499b74de68748c001750430584 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java
@@ -1,9 +1,6 @@
 package at.tuwien.gateway;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceException;
-import at.tuwien.exception.StorageNotFoundException;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -15,16 +12,11 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestTemplate;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.when;
 
 @Log4j2
@@ -36,9 +28,6 @@ public class InterceptorUnitTest extends AbstractUnitTest {
     @Qualifier("keycloakRestTemplate")
     private RestTemplate restTemplate;
 
-    @Autowired
-    private DataDatabaseSidecarGateway dataDatabaseSidecarGateway;
-
     @BeforeEach
     public void beforeEach() {
         genesis();
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakSidecarGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakSidecarGatewayUnitTest.java
deleted file mode 100644
index 2a02e03466d57116c3c529d5750229e80b015b26..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakSidecarGatewayUnitTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package at.tuwien.gateway;
-
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceConnectionException;
-import at.tuwien.exception.ServiceException;
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-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.http.HttpEntity;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.when;
-
-@Log4j2
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class KeycloakSidecarGatewayUnitTest extends AbstractUnitTest {
-
-    @MockBean
-    @Qualifier("restTemplate")
-    private RestTemplate restTemplate;
-
-    @Autowired
-    private KeycloakGateway keycloakGateway;
-
-    @BeforeEach
-    public void beforeEach() {
-        genesis();
-    }
-
-    @Test
-    public void obtainUserToken_succeeds() throws ServiceException, RemoteUnavailableException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.ok()
-                        .build());
-
-        /* test */
-        final TokenDto response = keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-    }
-
-    @Test
-    public void obtainUserToken_unavailable_fails() {
-
-        /* mock */
-        doThrow(HttpServerErrorException.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(RemoteUnavailableException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-    @Test
-    public void obtainUserToken_badRequest_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.BadRequest.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(ServiceException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-    @Test
-    public void obtainUserToken_statusCode_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        assertThrows(ServiceException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java
index 1ba4978788d7ee5d05d881d397a453086eaed41c..c224af4cb28604c2554da1942a782932db8d7390 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java
@@ -53,7 +53,8 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void getTableById_succeeds() throws TableNotFoundException, RemoteUnavailableException, ServiceException {
+    public void getTableById_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Type", IMAGE_1_JDBC);
         headers.set("X-Host", CONTAINER_1_HOST);
@@ -119,7 +120,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .body(TABLE_1_DTO));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID);
         });
     }
@@ -139,7 +140,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                             .headers(headers)
                             .body(TABLE_1_DTO));
             /* test */
-            assertThrows(ServiceException.class, () -> {
+            assertThrows(MetadataServiceException.class, () -> {
                 metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID);
             });
         }
@@ -164,14 +165,14 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID);
         });
     }
 
     @Test
     public void getDatabaseByInternalName_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class)))
@@ -206,7 +207,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .body(new PrivilegedDatabaseDto[]{DATABASE_1_PRIVILEGED_DTO}));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME);
         });
     }
@@ -220,7 +221,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME);
         });
     }
@@ -240,7 +241,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void getDatabaseById_succeeds() throws RemoteUnavailableException, ServiceException,
+    public void getDatabaseById_succeeds() throws RemoteUnavailableException, MetadataServiceException,
             DatabaseNotFoundException {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
@@ -294,7 +295,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getDatabaseById(DATABASE_1_ID);
         });
     }
@@ -312,7 +313,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getDatabaseById(DATABASE_1_ID);
         });
     }
@@ -332,14 +333,14 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                             .headers(headers)
                             .build());
             /* test */
-            assertThrows(ServiceException.class, () -> {
+            assertThrows(MetadataServiceException.class, () -> {
                 metadataServiceGateway.getDatabaseById(DATABASE_1_ID);
             });
         }
     }
 
     @Test
-    public void getContainerById_succeeds() throws RemoteUnavailableException, ContainerNotFoundException, ServiceException {
+    public void getContainerById_succeeds() throws RemoteUnavailableException, ContainerNotFoundException, MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
@@ -392,7 +393,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getContainerById(CONTAINER_1_ID);
         });
     }
@@ -412,7 +413,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                             .build());
 
             /* test */
-            assertThrows(ServiceException.class, () -> {
+            assertThrows(MetadataServiceException.class, () -> {
                 metadataServiceGateway.getContainerById(CONTAINER_1_ID);
             });
         }
@@ -431,13 +432,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getContainerById(CONTAINER_1_ID);
         });
     }
 
     @Test
-    public void getViewById_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ServiceException {
+    public void getViewById_succeeds() throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Type", IMAGE_1_JDBC);
         headers.set("X-Host", CONTAINER_1_HOST);
@@ -494,7 +495,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID);
         });
     }
@@ -514,7 +515,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                             .build());
 
             /* test */
-            assertThrows(ServiceException.class, () -> {
+            assertThrows(MetadataServiceException.class, () -> {
                 metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID);
             });
         }
@@ -537,13 +538,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID);
         });
     }
 
     @Test
-    public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, ServiceException {
+    public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)))
@@ -592,7 +593,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getUserById(USER_1_ID);
         });
     }
@@ -606,14 +607,14 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getUserById(USER_1_ID);
         });
     }
 
     @Test
     public void getPrivilegedUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException,
-            ServiceException {
+            MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
@@ -668,7 +669,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
         });
     }
@@ -688,7 +689,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                             .build());
 
             /* test */
-            assertThrows(ServiceException.class, () -> {
+            assertThrows(MetadataServiceException.class, () -> {
                 metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
             });
         }
@@ -707,13 +708,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
         });
     }
 
     @Test
-    public void getAccess_succeeds() throws RemoteUnavailableException, NotAllowedException, ServiceException {
+    public void getAccess_succeeds() throws RemoteUnavailableException, NotAllowedException, MetadataServiceException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class)))
@@ -775,7 +776,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID);
         });
     }
@@ -789,13 +790,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID);
         });
     }
 
     @Test
-    public void getIdentifiers_witSubset_succeeds() throws RemoteUnavailableException, DatabaseNotFoundException, ServiceException {
+    public void getIdentifiers_witSubset_succeeds() throws RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class)))
@@ -808,7 +809,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void getIdentifiers_succeeds() throws RemoteUnavailableException, DatabaseNotFoundException, ServiceException {
+    public void getIdentifiers_succeeds() throws RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class)))
@@ -857,7 +858,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID);
         });
     }
@@ -871,13 +872,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID);
         });
     }
 
     @Test
-    public void updateTableStatistics_succeeds() throws RemoteUnavailableException, ServiceException, TableNotFoundException {
+    public void updateTableStatistics_succeeds() throws RemoteUnavailableException, MetadataServiceException, TableNotFoundException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), eq(HttpEntity.EMPTY), eq(Void.class)))
@@ -925,7 +926,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(MetadataServiceException.class, () -> {
             metadataServiceGateway.updateTableStatistics(DATABASE_1_ID, TABLE_1_ID);
         });
     }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java
deleted file mode 100644
index 9075ec2a02d0420b9fe0cec8c307a9dc8ac1c13e..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package at.tuwien.handlers;
-
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.HttpStatus;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-
-import static at.tuwien.test.utils.EndpointUtils.getErrorCodes;
-import static at.tuwien.test.utils.EndpointUtils.getExceptions;
-
-@Log4j2
-@ExtendWith(SpringExtension.class)
-@SpringBootTest
-public class ApiExceptionHandlerTest extends AbstractUnitTest {
-
-    @Test
-    public void handle_succeeds() throws ClassNotFoundException, IOException {
-        final List<Method> handlers = Arrays.asList(ApiExceptionHandler.class.getMethods());
-        final List<String> errorCodes = getErrorCodes();
-
-        /* test */
-        for (Class<?> exception : getExceptions()) {
-            final Optional<Method> optional = handlers.stream().filter(h -> Arrays.asList(h.getParameterTypes()).contains(exception)).findFirst();
-            if (optional.isEmpty()) {
-                Assertions.fail("Exception " + exception.getName() + " does not have a corresponding handle method in the endpoint");
-            }
-            final Method method = optional.get();
-            /* exception */
-            Assertions.assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).code());
-            Assertions.assertNotEquals(exception.getDeclaredAnnotation(ResponseStatus.class).code(), HttpStatus.INTERNAL_SERVER_ERROR);
-            Assertions.assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).reason(), "Exception " + exception.getName() + " does not provide a reason code");
-            Assertions.assertTrue(errorCodes.contains(exception.getDeclaredAnnotation(ResponseStatus.class).reason()), "Exception code " + exception.getDeclaredAnnotation(ResponseStatus.class).reason() + " does have a reason code mapped in localized ui error messages");
-            /* handler method */
-            Assertions.assertEquals(method.getDeclaredAnnotation(ResponseStatus.class).code(), exception.getDeclaredAnnotation(ResponseStatus.class).code());
-        }
-    }
-}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
index dec1fcc0282993ba0a7b527dc4dda7088fc0e4a5..88bad7b06124df10f5a3cec690e993ac5b8ffcd5 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
@@ -2,8 +2,8 @@ package at.tuwien.listener;
 
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.exception.MetadataServiceException;
 import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceException;
 import at.tuwien.exception.TableNotFoundException;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.test.AbstractUnitTest;
@@ -63,7 +63,7 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest {
 
     @Test
     public void onMessage_succeeds(CapturedOutput output) throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
         final Message request = buildMessage("dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>());
 
         /* mock */
@@ -78,7 +78,7 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest {
     @Test
     @Disabled
     public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
         final Message request = buildMessage("dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>());
 
         /* mock */
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
index ab4a171c8915440055934c904247832ce0cf7549..648e36caa938f11e564ce772b00c25ba24d18281 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
@@ -2,8 +2,8 @@ package at.tuwien.listener;
 
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.exception.MetadataServiceException;
 import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceException;
 import at.tuwien.exception.TableNotFoundException;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.test.AbstractUnitTest;
@@ -76,7 +76,7 @@ public class DefaultListenerUnitTest extends AbstractUnitTest {
 
     @Test
     public void onMessage_messageMalformed_fails(CapturedOutput output) throws TableNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
         final Message request = buildMessage("dbrepo.1.1", "{,}", new HashMap<>());
 
         /* mock */
@@ -90,7 +90,7 @@ public class DefaultListenerUnitTest extends AbstractUnitTest {
 
     @Test
     public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
         final Message request = buildMessage("dbrepo.1.1", "{\"id\":1}", new HashMap<>());
 
         /* mock */
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
index e53f6ad88f92095ae405d586d39a399e0a6b0304..c89d53282ce3086cb28a88125b07549780b83d6b 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
@@ -9,6 +9,7 @@ import at.tuwien.mapper.MariaDbMapper;
 import at.tuwien.mapper.MariaDbMapperImpl;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -38,6 +39,11 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest {
     @Autowired
     private MariaDbMapper mariaDbMapper;
 
+    @BeforeAll
+    public static void beforeAll() throws InterruptedException {
+        Thread.sleep(1000) /* wait for test container some more */;
+    }
+
     @BeforeEach
     public void beforeEach() throws SQLException {
         genesis();
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
index 4bfa5b443a19ed6bf7af2c55183fd94fa0366baf..bd57eafacc47a1107e309be0fba94de75371bc95 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
@@ -3,13 +3,14 @@ package at.tuwien.service;
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
 import at.tuwien.exception.ContainerNotFoundException;
+import at.tuwien.exception.MetadataServiceException;
 import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceException;
 import at.tuwien.exception.TableNotFoundException;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.service.impl.QueueServiceRabbitMqImpl;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -42,6 +43,11 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest {
     @Container
     private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
 
+    @BeforeAll
+    public static void beforeAll() throws InterruptedException {
+        Thread.sleep(1000) /* wait for test container some more */;
+    }
+
     @BeforeEach
     public void beforeEach() throws SQLException {
         genesis();
@@ -51,8 +57,8 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void insert_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, ServiceException {
+    public void insert_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
+            TableNotFoundException, MetadataServiceException {
         final Map<String, Object> request = new HashMap<>() {{
             put("id", 4L);
             put("date", "2023-10-03");
@@ -61,9 +67,6 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest {
             put("rainfall", 0.2);
         }};
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -75,16 +78,13 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void insert_onlyMandatoryFields_succeeds() throws InterruptedException, SQLException,
-            RemoteUnavailableException, TableNotFoundException, ServiceException {
+    public void insert_onlyMandatoryFields_succeeds() throws SQLException, RemoteUnavailableException,
+            TableNotFoundException, MetadataServiceException {
         final Map<String, Object> request = new HashMap<>() {{
             put("id", 5L);
             put("date", "2023-10-04");
         }};
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java
index d13a37531b06e3572547b1f472e970ada78a7faa..aeaae0ecf2626ff88027a210bd8e24a5c66d4ede 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java
@@ -1,14 +1,21 @@
 package at.tuwien.service;
 
+import at.tuwien.ExportResourceDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.database.query.QueryResultDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.config.S3Config;
 import at.tuwien.exception.*;
+import at.tuwien.gateway.DataDatabaseSidecarGateway;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.test.AbstractUnitTest;
+import com.google.common.hash.Hashing;
 import lombok.extern.log4j.Log4j2;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -20,15 +27,19 @@ import org.testcontainers.containers.MariaDBContainer;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.math.BigInteger;
+import java.nio.charset.Charset;
 import java.sql.SQLException;
 import java.time.Instant;
 import java.util.List;
 import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.when;
 
 @Log4j2
@@ -43,9 +54,18 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     @MockBean
     private MetadataServiceGateway metadataServiceGateway;
 
+    @MockBean
+    private DataDatabaseSidecarGateway dataDatabaseSidecarGateway;
+
+    @MockBean
+    private StorageService storageService;
+
     @Container
     private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
 
+    @Autowired
+    private S3Config s3Config;
+
     @BeforeEach
     public void beforeEach() throws SQLException {
         genesis();
@@ -56,8 +76,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     public void execute_succeeds() throws QueryStoreInsertException, TableMalformedException, SQLException,
-            QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException,
-            RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+            QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException,
+            MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -96,9 +116,9 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void execute_joinWithAlias_succeeds() throws QueryStoreInsertException, TableMalformedException, SQLException,
-            QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException,
-            RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+    public void execute_joinWithAlias_succeeds() throws QueryStoreInsertException, TableMalformedException,
+            SQLException, QueryNotFoundException, UserNotFoundException, NotAllowedException,
+            RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -126,8 +146,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     public void execute_oneResult_succeeds() throws QueryStoreInsertException, TableMalformedException, SQLException,
-            QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException,
-            RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+            QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException,
+            MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -157,8 +177,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     public void execute_oneResultPagination_succeeds() throws QueryStoreInsertException, TableMalformedException,
-            SQLException, QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException,
-            RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+            SQLException, QueryNotFoundException, UserNotFoundException, NotAllowedException,
+            RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -187,8 +207,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findAll_succeeds() throws SQLException, QueryNotFoundException, InterruptedException,
-            NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+    public void findAll_succeeds() throws SQLException, QueryNotFoundException, NotAllowedException,
+            RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* test */
         final List<QueryDto> response = findAll_generic(null);
@@ -198,8 +218,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findAll_onlyPersisted_succeeds() throws SQLException, QueryNotFoundException, InterruptedException,
-            NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+    public void findAll_onlyPersisted_succeeds() throws SQLException, QueryNotFoundException, NotAllowedException,
+            RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* test */
         final List<QueryDto> response = findAll_generic(true);
@@ -208,8 +228,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findAll_onlyNonPersisted_succeeds() throws SQLException, QueryNotFoundException, InterruptedException,
-            NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+    public void findAll_onlyNonPersisted_succeeds() throws SQLException, QueryNotFoundException, NotAllowedException,
+            RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, InterruptedException {
 
         /* test */
         final List<QueryDto> response = findAll_generic(false);
@@ -218,9 +238,9 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findById_succeeds() throws SQLException, QueryNotFoundException, InterruptedException,
-            UserNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException,
-            DatabaseNotFoundException {
+    public void findById_succeeds() throws SQLException, QueryNotFoundException, UserNotFoundException,
+            NotAllowedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException,
+            InterruptedException {
 
         /* test */
         findById_generic(QUERY_1_ID);
@@ -236,9 +256,9 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void persist_succeeds() throws SQLException, InterruptedException, QueryStorePersistException,
-            QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException,
-            ServiceException, DatabaseNotFoundException {
+    public void persist_succeeds() throws SQLException, QueryStorePersistException, QueryNotFoundException,
+            UserNotFoundException, NotAllowedException, RemoteUnavailableException, MetadataServiceException,
+            DatabaseNotFoundException, InterruptedException {
 
         /* mock */
         when(metadataServiceGateway.getUserById(QUERY_2_CREATED_BY))
@@ -252,9 +272,9 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void persist_unPersist_succeeds() throws SQLException, InterruptedException, QueryStorePersistException,
-            QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException,
-            ServiceException, DatabaseNotFoundException {
+    public void persist_unPersist_succeeds() throws SQLException, QueryStorePersistException, QueryNotFoundException,
+            UserNotFoundException, NotAllowedException, RemoteUnavailableException, MetadataServiceException,
+            DatabaseNotFoundException, InterruptedException {
 
         /* mock */
         when(metadataServiceGateway.getUserById(QUERY_1_CREATED_BY))
@@ -267,9 +287,40 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
         assertFalse(response.getIsPersisted());
     }
 
-    protected void findById_generic(Long queryId) throws InterruptedException, NotAllowedException,
-            RemoteUnavailableException, SQLException, UserNotFoundException, QueryNotFoundException, ServiceException,
-            DatabaseNotFoundException {
+    @Test
+    public void createQueryStore_succeeds() throws SQLException, QueryStoreCreateException, InterruptedException {
+
+        /* mock */
+        MariaDbConfig.dropQueryStore(DATABASE_1_PRIVILEGED_DTO);
+
+        /* test */
+        createQueryStore_generic(DATABASE_1_INTERNALNAME);
+    }
+
+    @Test
+    public void createQueryStore_fails() {
+
+        /* test */
+        assertThrows(QueryStoreCreateException.class, () -> {
+            createQueryStore_generic(DATABASE_1_INTERNALNAME);
+        });
+    }
+
+    @Test
+    public void export_succeeds() throws SQLException, StorageUnavailableException, QueryMalformedException,
+            SidecarExportException, MetadataServiceException, RemoteUnavailableException, IOException,
+            StorageNotFoundException, InterruptedException {
+
+        /* mock */
+        MariaDbConfig.dropQueryStore(DATABASE_1_PRIVILEGED_DTO);
+
+        /* test */
+        export_generic();
+    }
+
+    protected void findById_generic(Long queryId) throws NotAllowedException, RemoteUnavailableException, SQLException,
+            UserNotFoundException, QueryNotFoundException, MetadataServiceException, DatabaseNotFoundException,
+            InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -287,9 +338,9 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
         assertEquals(DATABASE_1_ID, response.getDatabaseId());
     }
 
-    protected List<QueryDto> findAll_generic(Boolean filterPersisted) throws InterruptedException, SQLException,
-            QueryNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException,
-            DatabaseNotFoundException {
+    protected List<QueryDto> findAll_generic(Boolean filterPersisted) throws SQLException, QueryNotFoundException,
+            NotAllowedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException,
+            InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -305,8 +356,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     }
 
     protected void persist_generic(Long queryId, List<IdentifierDto> identifiers, Boolean persist)
-            throws InterruptedException, RemoteUnavailableException, SQLException, QueryStorePersistException,
-            ServiceException, DatabaseNotFoundException {
+            throws RemoteUnavailableException, SQLException, QueryStorePersistException, MetadataServiceException,
+            DatabaseNotFoundException, InterruptedException {
 
         /* pre-condition */
         Thread.sleep(1000) /* wait for test container some more */;
@@ -321,4 +372,38 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
         queryService.persist(DATABASE_1_PRIVILEGED_DTO, queryId, persist);
     }
 
+    protected void createQueryStore_generic(String databaseName) throws SQLException, QueryStoreCreateException,
+            InterruptedException {
+
+        /* pre-condition */
+        Thread.sleep(1000) /* wait for test container some more */;
+
+        /* test */
+        queryService.createQueryStore(CONTAINER_1_PRIVILEGED_DTO, databaseName);
+        final List<Map<String, Object>> response = MariaDbConfig.listQueryStore(DATABASE_1_PRIVILEGED_DTO);
+        assertEquals(0, response.size());
+    }
+
+    protected void export_generic() throws StorageUnavailableException, SQLException,
+            QueryMalformedException, SidecarExportException, MetadataServiceException, RemoteUnavailableException,
+            StorageNotFoundException, IOException, InterruptedException {
+        final String filename = "68b329da9893e34099c7d8ad5cb9c940";
+
+        /* pre-condition */
+        Thread.sleep(1000) /* wait for test container some more */;
+
+        /* mock */
+        FileUtils.deleteQuietly(new File(s3Config.getS3FilePath() + "/" + filename));
+        doNothing()
+                .when(dataDatabaseSidecarGateway)
+                .exportFile(anyString(), anyInt(), eq(filename));
+        when(storageService.getResource(anyString()))
+                .thenReturn(EXPORT_RESOURCE_DTO);
+
+        /* test */
+        final ExportResourceDto response = queryService.export(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, Instant.now(), filename);
+        assertEquals(filename, response.getFilename());
+        assertNotNull(response.getResource().getInputStream());
+    }
+
 }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
index 86a0442ef60a4dc80365c48b8567a15ad04f9e85..65ec32c0d501524028e7caef05cb58e997d19446 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java
@@ -25,6 +25,7 @@ import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.io.FileUtils;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -74,6 +75,11 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     @Container
     private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
 
+    @BeforeAll
+    public static void beforeAll() throws InterruptedException {
+        Thread.sleep(1000) /* wait for test container some more */;
+    }
+
     @BeforeEach
     public void beforeEach() throws SQLException {
         genesis();
@@ -84,9 +90,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            ServiceException {
+    public void updateTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
+            TableNotFoundException, TableMalformedException, QueryMalformedException, MetadataServiceException {
         /* modify row based on primary key */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -100,9 +105,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -120,9 +122,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_modifyPrimaryKey_succeeds() throws InterruptedException, SQLException,
-            RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException,
-            QueryMalformedException, ServiceException {
+    public void updateTuple_modifyPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException,
+            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
+            MetadataServiceException {
         /* modify row primary key based on primary key */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -137,9 +139,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -157,9 +156,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_missingPrimaryKey_succeeds() throws InterruptedException, SQLException,
-            RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException,
-            QueryMalformedException, ServiceException {
+    public void updateTuple_missingPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException,
+            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
+            MetadataServiceException {
         /* modify row based on non-primary key column */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -173,9 +172,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -193,9 +189,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_notInOrder_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException,
+    public void updateTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException,
             ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            ServiceException {
+            MetadataServiceException {
         /* modify row based on non-primary key column */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -209,9 +205,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -229,9 +222,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTuple_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            StorageUnavailableException, StorageNotFoundException, ServiceException {
+    public void createTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
+            TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException,
+            StorageNotFoundException, MetadataServiceException {
         /* add row with primary key */
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -243,9 +236,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -263,9 +253,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTuple_notInOrder_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException,
+    public void createTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException,
             ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            StorageUnavailableException, StorageNotFoundException, ServiceException {
+            StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         /* add row with primary key */
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -277,9 +267,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -297,9 +284,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void deleteTuple_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            ServiceException {
+    public void deleteTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
+            TableNotFoundException, TableMalformedException, QueryMalformedException, MetadataServiceException {
         /* delete row based on primary key */
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
@@ -307,9 +293,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -323,9 +306,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void deleteTuple_withoutPrimaryKey_succeeds() throws InterruptedException, SQLException,
-            RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException,
-            QueryMalformedException, ServiceException {
+    public void deleteTuple_withoutPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException,
+            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
+            MetadataServiceException {
         /* remove row based on non-primary key */
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
@@ -334,9 +317,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
@@ -350,8 +330,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void getSchemas_succeeds() throws TableNotFoundException, SQLException, QueryMalformedException,
-            DatabaseMalformedException {
+    public void getSchemas_succeeds() throws TableNotFoundException, SQLException, DatabaseMalformedException {
 
         /* test */
         final List<TableDto> response = tableService.getSchemas(DATABASE_1_PRIVILEGED_DTO);
@@ -462,7 +441,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     public void create_succeeds() throws TableNotFoundException, TableMalformedException, SQLException,
-            QueryMalformedException, TableExistsException {
+            TableExistsException {
 
         /* test */
         final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO);
@@ -538,7 +517,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     public void create_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException,
-            QueryMalformedException, TableExistsException {
+            TableExistsException {
 
         /* mock */
         MariaDbConfig.dropTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNALNAME);
@@ -665,8 +644,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void importDataset_withSeparatorAndQuoteAndNullElement_succeeds() throws SidecarImportException, ServiceException, SQLException,
-            QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, IOException {
+    public void importDataset_withSeparatorAndQuoteAndNullElement_succeeds() throws SidecarImportException,
+            SQLException, QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, IOException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .location("weather_aus.csv")
                 .separator(';')
@@ -688,8 +667,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void importDataset_malformedData_fails() throws ServiceException, RemoteUnavailableException, StorageNotFoundException,
-            IOException {
+    public void importDataset_malformedData_fails() throws RemoteUnavailableException, StorageNotFoundException,
+            IOException, SidecarImportException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .location("weather_aus.csv")
                 .separator(';')
@@ -712,9 +691,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void exportDataset_succeeds() throws ServiceException, SQLException,
-            QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException,
-            SidecarExportException {
+    public void exportDataset_succeeds() throws SQLException, QueryMalformedException, RemoteUnavailableException,
+            StorageNotFoundException, StorageUnavailableException, SidecarExportException {
         final ExportResourceDto mock = ExportResourceDto.builder()
                 .filename("weather_aus.csv")
                 .resource(new InputStreamResource(InputStream.nullInputStream()))
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..13806e93ddd1cbeb7a8e1c0ab4e0fe38db0830ad
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java
@@ -0,0 +1,40 @@
+package at.tuwien.utils;
+
+import at.tuwien.test.BaseTest;
+import org.junit.jupiter.api.Test;
+
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class UserUtilTest extends BaseTest {
+
+    @Test
+    public void hasRole_succeeds() {
+        assertTrue(UserUtil.hasRole(USER_1_PRINCIPAL, "find-container"));
+    }
+
+    @Test
+    public void hasRole_principalMissing_fails() {
+        assertFalse(UserUtil.hasRole(null, "find-container"));
+    }
+
+    @Test
+    public void hasRole_roleMissing_fails() {
+        assertFalse(UserUtil.hasRole(USER_1_PRINCIPAL, null));
+    }
+
+    @Test
+    public void getId_succeeds() {
+        assertEquals(USER_1_ID, UserUtil.getId(USER_1_PRINCIPAL));
+    }
+
+    @Test
+    public void getId_principalMissing_fails() {
+        assertNull(UserUtil.getId(null));
+    }
+
+    @Test
+    public void getId_roleMissing_fails() {
+        assertNull(UserUtil.getId(USER_LOCAL_ADMIN_PRINCIPAL));
+    }
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b12313dfe957d0f02f05c58bfce1066979973d07
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java
@@ -0,0 +1,101 @@
+package at.tuwien.validation;
+
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.exception.PaginationException;
+import at.tuwien.exception.QueryNotSupportedException;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@AutoConfigureObservability
+@MockAmqp
+public class EndpointValidatorUnitTest extends AbstractUnitTest {
+
+    @Autowired
+    private EndpointValidator endpointValidator;
+
+    @Test
+    public void validateDataParams_succeeds() throws Exception {
+
+        /* test */
+        endpointValidator.validateDataParams(null, null);
+    }
+
+    @Test
+    public void validateDataParams_onlyPage_fails() {
+
+        /* test */
+        assertThrows(PaginationException.class, () -> {
+            endpointValidator.validateDataParams(0L, null);
+        });
+    }
+
+    @Test
+    public void validateDataParams_negativePage_fails() {
+
+        /* test */
+        assertThrows(PaginationException.class, () -> {
+            endpointValidator.validateDataParams(-1L, 10L);
+        });
+    }
+
+    @Test
+    public void validateDataParams_onlySize_fails() {
+
+        /* test */
+        assertThrows(PaginationException.class, () -> {
+            endpointValidator.validateDataParams(null, 10L);
+        });
+    }
+
+    @Test
+    public void validateDataParams_zeroSize_fails() {
+
+        /* test */
+        assertThrows(PaginationException.class, () -> {
+            endpointValidator.validateDataParams(0L, 0L);
+        });
+    }
+
+    @Test
+    public void validateForbiddenStatements_succeeds() throws QueryNotSupportedException {
+
+        /* test */
+        endpointValidator.validateForbiddenStatements("SELECT country FROM some_table");
+    }
+
+    @Test
+    public void validateForbiddenStatements_fails() {
+
+        /* test */
+        assertThrows(QueryNotSupportedException.class, () -> {
+            endpointValidator.validateForbiddenStatements("SELECT COUNT(id) FROM some_table");
+        });
+    }
+
+    @Test
+    public void validateForbiddenStatements_lowercase_fails() {
+
+        /* test */
+        assertThrows(QueryNotSupportedException.class, () -> {
+            endpointValidator.validateForbiddenStatements("SELECT COUNT(id) FROM some_table");
+        });
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/resources/application.properties b/dbrepo-data-service/rest-service/src/test/resources/application.properties
index 07eb7f642bd62128618f3d0b86d04c0ba4743644..764d9609c99fb1609b24d6d7f61d6d8d6b06ec00 100644
--- a/dbrepo-data-service/rest-service/src/test/resources/application.properties
+++ b/dbrepo-data-service/rest-service/src/test/resources/application.properties
@@ -29,4 +29,4 @@ spring.rabbitmq.password=guest
 
 # s3
 dbrepo.s3.accessKeyId=minioadmin
-dbrepo.s3.secretAccessKey=minioadmin
\ No newline at end of file
+dbrepo.s3.secretAccessKey=minioadmin
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
index 8aa52308bf3f237a0f84cca7d0f3a34edd1d32c3..80fdd15f1daff7625508eb8d46d9b54332a5150f 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
@@ -1,8 +1,6 @@
 package at.tuwien.auth;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.user.UserDetailsDto;
-import at.tuwien.config.GatewayConfig;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import jakarta.servlet.ServletException;
@@ -13,45 +11,30 @@ import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.stereotype.Component;
 
-import java.util.List;
-
 @Log4j2
 @Component
 public class BasicAuthenticationProvider implements AuthenticationManager {
 
-    private final GatewayConfig gatewayConfig;
     private final AuthTokenFilter authTokenFilter;
     private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public BasicAuthenticationProvider(GatewayConfig gatewayConfig, AuthTokenFilter authTokenFilter,
-                                       KeycloakGateway keycloakGateway) {
-        this.gatewayConfig = gatewayConfig;
+    public BasicAuthenticationProvider(AuthTokenFilter authTokenFilter, KeycloakGateway keycloakGateway) {
         this.authTokenFilter = authTokenFilter;
         this.keycloakGateway = keycloakGateway;
     }
 
     @Override
     public Authentication authenticate(Authentication auth) throws AuthenticationException {
-        if (auth.getName().equals(gatewayConfig.getAdminUsername())
-                && auth.getCredentials().toString().equals(gatewayConfig.getAdminPassword())) {
-            log.trace("current user is {}: skip authentication", gatewayConfig.getAdminUsername());
-            final UserDetails userDetails = UserDetailsDto.builder()
-                    .username(auth.getName())
-                    .authorities(List.of(new SimpleGrantedAuthority("admin")))
-                    .build();
-            return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
-        }
-        log.trace("current user is {}: begin authentication", auth.getName());
         try {
             final TokenDto tokenDto = keycloakGateway.obtainUserToken(auth.getName(), auth.getCredentials().toString());
             final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken());
             return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
-        } catch (ServletException | RemoteUnavailableException | ServiceException e) {
+        } catch (ServletException | CredentialsInvalidException | AccountNotSetupException |
+                 AuthServiceConnectionException e) {
             throw new BadCredentialsException("Failed to authenticate with authentication service", e);
         }
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..20955bcdb36912e3f8dd4ed695a4e688f1177ccf
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
@@ -0,0 +1,45 @@
+package at.tuwien.auth;
+
+import at.tuwien.api.keycloak.TokenDto;
+import at.tuwien.config.GatewayConfig;
+import at.tuwien.exception.*;
+import at.tuwien.gateway.KeycloakGateway;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+import java.util.List;
+
+@Log4j2
+public class InternalRequestInterceptor implements ClientHttpRequestInterceptor {
+
+    private final GatewayConfig gatewayConfig;
+    private final KeycloakGateway keycloakGateway;
+
+    public InternalRequestInterceptor(GatewayConfig gatewayConfig, KeycloakGateway keycloakGateway) {
+        this.gatewayConfig = gatewayConfig;
+        this.keycloakGateway = keycloakGateway;
+    }
+
+    @Override
+    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
+            throws IOException {
+        final HttpHeaders headers = request.getHeaders();
+        headers.setAccept(List.of(MediaType.APPLICATION_JSON));
+        try {
+            final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(),
+                    gatewayConfig.getSystemPassword());
+            headers.setBearerAuth(token.getAccessToken());
+            log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername());
+        } catch (AuthServiceConnectionException | CredentialsInvalidException | AccountNotSetupException e) {
+            log.error("Failed to obtain token for internal user: {}", gatewayConfig.getSystemUsername());
+            throw new IOException("Failed to obtain token for internal user", e);
+        }
+        return execution.execute(request, body);
+    }
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
index b04aff18ce5a49d68c01519a97b3550b14bddc6e..6ebd6744576fd034db2faf569ffb764e43d9c7f8 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -1,19 +1,16 @@
 package at.tuwien.config;
 
+import at.tuwien.auth.InternalRequestInterceptor;
+import at.tuwien.gateway.KeycloakGateway;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.ClientHttpRequestInterceptor;
-import org.springframework.http.client.support.BasicAuthenticationInterceptor;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.DefaultUriBuilderFactory;
 
-import java.util.List;
-
 @Log4j2
 @Getter
 @Configuration
@@ -22,30 +19,26 @@ public class GatewayConfig {
     @Value("${dbrepo.endpoints.metadataService}")
     private String metadataEndpoint;
 
-    @Value("${dbrepo.admin.username}")
-    private String adminUsername;
+    @Value("${dbrepo.system.username}")
+    private String systemUsername;
+
+    @Value("${dbrepo.system.password}")
+    private String systemPassword;
 
-    @Value("${dbrepo.admin.password}")
-    private String adminPassword;
+    private final KeycloakGateway keycloakGateway;
+
+    @Autowired
+    public GatewayConfig(KeycloakGateway keycloakGateway) {
+        this.keycloakGateway = keycloakGateway;
+    }
 
     @Bean
     public RestTemplate restTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(metadataEndpoint));
-        log.debug("add basic authentication for metadata service: username={}, password=(hidden)", adminUsername);
         restTemplate.getInterceptors()
-                .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword),
-                        clientHttpRequestInterceptor()));
+                .add(new InternalRequestInterceptor(this, keycloakGateway));
         return restTemplate;
     }
 
-    @Bean
-    public ClientHttpRequestInterceptor clientHttpRequestInterceptor() {
-        return (request, body, execution) -> {
-            final HttpHeaders headers = request.getHeaders();
-            headers.setAccept(List.of(MediaType.APPLICATION_JSON));
-            return execution.execute(request, body);
-        };
-    }
-
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
index 4d258d496aa6ebe825ac2d84a1f00a1b4f9c0298..e0d7d0321513387f1e1c9c235c1c4b51e309be1d 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
@@ -2,16 +2,12 @@ package at.tuwien.config;
 
 import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.client.ClientHttpRequestInterceptor;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.DefaultUriBuilderFactory;
 
-import java.util.List;
-
 @Getter
 @Configuration
 public class KeycloakConfig {
@@ -31,20 +27,12 @@ public class KeycloakConfig {
     @Value("${dbrepo.keycloak.clientSecret}")
     private String keycloakClientSecret;
 
-    private final ClientHttpRequestInterceptor clientHttpRequestInterceptor;
-
-    @Autowired
-    public KeycloakConfig(ClientHttpRequestInterceptor clientHttpRequestInterceptor) {
-        this.clientHttpRequestInterceptor = clientHttpRequestInterceptor;
-    }
-
     @Bean("keycloakRestTemplate")
     public RestTemplate brokerRestTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
         restTemplate.getInterceptors()
-                .addAll(List.of(new KeycloakInterceptor(keycloakUsername, keycloakPassword, keycloakEndpoint),
-                        clientHttpRequestInterceptor));
+                .add(new KeycloakInterceptor(keycloakUsername, keycloakPassword, keycloakEndpoint));
         return restTemplate;
     }
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
index 2aa39d5d4354912cd2101861328341f00725c3d3..1560c14b7aaa6272c76515a734a1ad99f7075222 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
@@ -43,8 +43,7 @@ public class WebSecurityConfig {
     }
 
     @Bean
-    public SecurityFilterChain filterChain(HttpSecurity http, KeycloakGateway keycloakGateway,
-                                           GatewayConfig gatewayConfig)
+    public SecurityFilterChain filterChain(HttpSecurity http, KeycloakGateway keycloakGateway)
             throws Exception {
         final OrRequestMatcher internalEndpoints = new OrRequestMatcher(
                 new AntPathRequestMatcher("/actuator/**", "GET"),
@@ -86,8 +85,8 @@ public class WebSecurityConfig {
         http.addFilterBefore(authTokenFilter(),
                 UsernamePasswordAuthenticationFilter.class
         );
-        http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(gatewayConfig,
-                        authTokenFilter(), keycloakGateway)),
+        http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(authTokenFilter(),
+                        keycloakGateway)),
                 UsernamePasswordAuthenticationFilter.class
         );
         return http.build();
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ContainerNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ContainerNotFoundException.java
deleted file mode 100644
index 8d3b2b2243f220da74d0635ce24ec43a3583e03f..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ContainerNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.container.missing")
-public class ContainerNotFoundException extends Exception {
-
-    public ContainerNotFoundException(String message) {
-        super(message);
-    }
-
-    public ContainerNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public ContainerNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java
deleted file mode 100644
index ff4ce77cf2b00c229f0b5ccec991efbcb81b3d1c..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.database.missing")
-public class DatabaseNotFoundException extends Exception {
-
-    public DatabaseNotFoundException(String message) {
-        super(message);
-    }
-
-    public DatabaseNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public DatabaseNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/FormatNotAvailableException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/FormatNotAvailableException.java
deleted file mode 100644
index d46b7b2baaee08ddbec3bb3682e9f9b640498e85..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/FormatNotAvailableException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-import java.io.IOException;
-
-@ResponseStatus(code = HttpStatus.NOT_ACCEPTABLE, reason = "error.subset.format")
-public class FormatNotAvailableException extends IOException {
-
-    public FormatNotAvailableException(String msg) {
-        super(msg);
-    }
-
-    public FormatNotAvailableException(String msg, Throwable thr) {
-        super(msg + ": " + thr.getLocalizedMessage(), thr);
-    }
-
-    public FormatNotAvailableException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/NotAllowedException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/NotAllowedException.java
deleted file mode 100644
index 33b2f7f9e3daa933c35bb947332fd30c30c94c82..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/NotAllowedException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.FORBIDDEN, reason = "error.request.forbidden")
-public class NotAllowedException extends Exception {
-
-    public NotAllowedException(String message) {
-        super(message);
-    }
-
-    public NotAllowedException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public NotAllowedException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/PaginationException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/PaginationException.java
deleted file mode 100644
index 53446bdb646dabd621510fe543380a936b3d290d..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/PaginationException.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "error.pagination.malformed")
-public class PaginationException extends Exception {
-
-    public PaginationException(String msg) {
-        super(msg);
-    }
-
-    public PaginationException(String msg, Throwable thr) {
-        super(msg + ": " + thr.getLocalizedMessage(), thr);
-    }
-
-    public PaginationException(Throwable thr) {
-        super(thr);
-    }
-
-}
-
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java
deleted file mode 100644
index d55be584cf25a3acdc403617971fe08baee82721..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.query.missing")
-public class QueryNotFoundException extends Exception {
-
-    public QueryNotFoundException(String message) {
-        super(message);
-    }
-
-    public QueryNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public QueryNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/StorageNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/StorageNotFoundException.java
deleted file mode 100644
index bbb780ea919d33c64c34f719f99c5ed30eae326a..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/StorageNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.storage.missing")
-public class StorageNotFoundException extends Exception {
-
-    public StorageNotFoundException(String message) {
-        super(message);
-    }
-
-    public StorageNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public StorageNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableExistsException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableExistsException.java
deleted file mode 100644
index fdc23ad7d3a254ed02cbefd49ba733aac3e277bd..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableExistsException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.CONFLICT, reason = "error.table.exists")
-public class TableExistsException extends Exception {
-
-    public TableExistsException(String message) {
-        super(message);
-    }
-
-    public TableExistsException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public TableExistsException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableNotFoundException.java
deleted file mode 100644
index 199ce9c74cc0ba8f37b2ad55eb86cd2c6877a2ab..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.table.missing")
-public class TableNotFoundException extends Exception {
-
-    public TableNotFoundException(String message) {
-        super(message);
-    }
-
-    public TableNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public TableNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/UserNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/UserNotFoundException.java
deleted file mode 100644
index 5aeabab27de7abf68f88df1346019e398dc921e6..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/UserNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.user.missing")
-public class UserNotFoundException extends Exception {
-
-    public UserNotFoundException(String message) {
-        super(message);
-    }
-
-    public UserNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public UserNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewNotFoundException.java b/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewNotFoundException.java
deleted file mode 100644
index 7ba64c5e8fc0ddb90c5845d483105c849ac4bd78..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewNotFoundException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package at.tuwien.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "error.view.missing")
-public class ViewNotFoundException extends Exception {
-
-    public ViewNotFoundException(String message) {
-        super(message);
-    }
-
-    public ViewNotFoundException(String message, Throwable thr) {
-        super(message, thr);
-    }
-
-    public ViewNotFoundException(Throwable thr) {
-        super(thr);
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java
index ecac6865f6e4704b915e10016afe8a5b25afaa63..23dc08a55d366f6560bcbaafbf6c79a94dfc2af3 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java
@@ -3,9 +3,28 @@ package at.tuwien.gateway;
 import at.tuwien.exception.*;
 
 public interface DataDatabaseSidecarGateway {
+
+    /**
+     * Imports a given dataset name into the given database.
+     * @param hostname The database hostname.
+     * @param port The database port.
+     * @param filename The dataset name.
+     * @throws StorageNotFoundException The dataset name was not found in the storage service.
+     * @throws RemoteUnavailableException Connection to the sidecar could not be established.
+     * @throws SidecarImportException The sidecar failed to import the dataset.
+     */
     void importFile(String hostname, Integer port, String filename) throws StorageNotFoundException,
-            RemoteUnavailableException, ServiceException;
+            RemoteUnavailableException, SidecarImportException;
 
+    /**
+     * Exports a given dataset name from the given database.
+     * @param hostname The database hostname.
+     * @param port The database port.
+     * @param filename The dataset name.
+     * @throws StorageNotFoundException The dataset name was not found in the storage service.
+     * @throws RemoteUnavailableException Connection to the sidecar could not be established.
+     * @throws SidecarExportException The sidecar failed to export the dataset.
+     */
     void exportFile(String hostname, Integer port, String filename) throws StorageNotFoundException,
-            ServiceException, RemoteUnavailableException;
+            SidecarExportException, RemoteUnavailableException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
index 1058119a25c8b5de2affbc05b72cd9417c7887a7..9e6a5f56bda37fc1b3d9af9fca8158a5fcce27f7 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
@@ -1,14 +1,13 @@
 package at.tuwien.gateway;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceConnectionException;
-import at.tuwien.exception.ServiceException;
-
-import javax.naming.ServiceUnavailableException;
+import at.tuwien.exception.AccountNotSetupException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.CredentialsInvalidException;
 
 public interface KeycloakGateway {
 
-    TokenDto obtainUserToken(String username, String password) throws RemoteUnavailableException, ServiceException;
+    TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException,
+            CredentialsInvalidException, AccountNotSetupException;
 
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java
index 4c01a40a447954ae666bf7ef9d330b5879b85e59..d16c8c8eba81efd22a64757a6dd1eb51dc56318f 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java
@@ -24,10 +24,10 @@ public interface MetadataServiceGateway {
      * @return The container with privileged connection information, if successful.
      * @throws ContainerNotFoundException  The table was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
-            ContainerNotFoundException, ServiceException;
+            ContainerNotFoundException, MetadataServiceException;
 
     /**
      * Get a database with given id from the metadata service.
@@ -36,10 +36,10 @@ public interface MetadataServiceGateway {
      * @return The database, if successful.
      * @throws DatabaseNotFoundException  The database was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException;
+            MetadataServiceException;
 
     /**
      * Get a database with given internal name from the metadata service.
@@ -48,10 +48,10 @@ public interface MetadataServiceGateway {
      * @return The database, if successful.
      * @throws DatabaseNotFoundException  The database was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException,
-            RemoteUnavailableException, ServiceException;
+            RemoteUnavailableException, MetadataServiceException;
 
     /**
      * Get a table with given database id and table id from the metadata service.
@@ -61,10 +61,10 @@ public interface MetadataServiceGateway {
      * @return The table, if successful.
      * @throws TableNotFoundException     The table was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException,
-            ServiceException;
+            MetadataServiceException;
 
     /**
      * Get a view with given database id and view id from the metadata service.
@@ -73,10 +73,10 @@ public interface MetadataServiceGateway {
      * @return The view, if successful.
      * @throws ViewNotFoundException     The view was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException,
-            ServiceException;
+            MetadataServiceException;
 
     /**
      * Get a user with given user id from the metadata service.
@@ -85,9 +85,9 @@ public interface MetadataServiceGateway {
      * @return The user, if successful.
      * @throws RemoteUnavailableException The remote service is not available and invalid data was returned.
      * @throws UserNotFoundException      The user was not found in the metadata service.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
-    UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, ServiceException;
+    UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException;
 
     /**
      * Get a user with given user id from the metadata service.
@@ -96,10 +96,10 @@ public interface MetadataServiceGateway {
      * @return The user, if successful.
      * @throws RemoteUnavailableException The remote service is not available and invalid data was returned.
      * @throws UserNotFoundException      The user was not found in the metadata service.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
-            ServiceException;
+            MetadataServiceException;
 
     /**
      * Get database access for a given user and database id from the metadata service.
@@ -108,10 +108,10 @@ public interface MetadataServiceGateway {
      * @return The database access, if successful.
      * @throws RemoteUnavailableException The remote service is not available and invalid data was returned.
      * @throws NotAllowedException The access to this database is denied for the given user.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
     DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, NotAllowedException,
-            ServiceException;
+            MetadataServiceException;
 
     /**
      * Get a list of identifiers for a given database id and optional subset id.
@@ -120,9 +120,9 @@ public interface MetadataServiceGateway {
      * @return The list of identifiers.
      * @throws RemoteUnavailableException The remote service is not available and invalid data was returned.
      * @throws DatabaseNotFoundException The database was not found.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
-    List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws ServiceException,
+    List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws MetadataServiceException,
             RemoteUnavailableException, DatabaseNotFoundException;
 
     /**
@@ -131,7 +131,7 @@ public interface MetadataServiceGateway {
      * @param tableId The table id.
      * @throws RemoteUnavailableException The remote service is not available and invalid data was returned.
      * @throws TableNotFoundException The table was not found.
-     * @throws ServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException The remote service returned invalid data.
      */
-    void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, ServiceException, RemoteUnavailableException;
+    void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, MetadataServiceException, RemoteUnavailableException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java
index b3e7c3bd41545e07b344406d00b29e9daecd0aab..841aace47460c99a09a5d1cff0a26cf03bed1ce9 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java
@@ -24,13 +24,13 @@ public class DataDatabaseSidecarGatewayImpl implements DataDatabaseSidecarGatewa
 
     @Override
     public void importFile(String hostname, Integer port, String filename) throws StorageNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, SidecarImportException {
         final ResponseEntity<Void> response;
         final String url = "http://" + hostname + ":" + port + "/sidecar/import/" + filename;
         log.debug("import file into data database sidecar");
         try {
             response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(null), Void.class);
-        } catch (ResourceAccessException | HttpServerErrorException e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to import dataset with filename: {}: {}", filename, e.getMessage());
             throw new RemoteUnavailableException("Failed to import dataset: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest e) {
@@ -39,19 +39,19 @@ public class DataDatabaseSidecarGatewayImpl implements DataDatabaseSidecarGatewa
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to import dataset with filename: {}: service responded unsuccessful: {}", filename, response.getStatusCode());
-            throw new ServiceException("Failed to import dataset: service responded unsuccessful: " + response.getStatusCode());
+            throw new SidecarImportException("Failed to import dataset: service responded unsuccessful: " + response.getStatusCode());
         }
     }
 
     @Override
     public void exportFile(String hostname, Integer port, String filename) throws StorageNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, SidecarExportException {
         final ResponseEntity<Void> response;
         final String url = "http://" + hostname + ":" + port + "/sidecar/export/" + filename;
         log.debug("export file from data database sidecar: {}", url);
         try {
             response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(null), Void.class);
-        } catch (ResourceAccessException | HttpServerErrorException e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to export dataset with filename: {}: {}", filename, e.getMessage());
             throw new RemoteUnavailableException("Failed to export dataset: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest e) {
@@ -60,7 +60,7 @@ public class DataDatabaseSidecarGatewayImpl implements DataDatabaseSidecarGatewa
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to export dataset with filename: {}: service responded unsuccessful: {}", filename, response.getStatusCode());
-            throw new ServiceException("Failed to export dataset: service responded unsuccessful: " + response.getStatusCode());
+            throw new SidecarExportException("Failed to export dataset: service responded unsuccessful: " + response.getStatusCode());
         }
     }
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
index 545e259097951b3ed79d34c73bef72ccd2270b6b..f95bb3fe76a1e95786fae0b109ee7c1619954209 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
@@ -1,61 +1,69 @@
 package at.tuwien.gateway.impl;
 
+import at.tuwien.api.auth.KeycloakErrorDto;
 import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.config.KeycloakConfig;
-import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.ServiceConnectionException;
-import at.tuwien.exception.ServiceException;
+import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.*;
 import org.springframework.stereotype.Service;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 
 @Log4j2
 @Service
 public class KeycloakGatewayImpl implements KeycloakGateway {
 
-    private final RestTemplate restTemplate;
     private final KeycloakConfig keycloakConfig;
 
     @Autowired
-    public KeycloakGatewayImpl(RestTemplate restTemplate, KeycloakConfig keycloakConfig) {
-        this.restTemplate = restTemplate;
+    public KeycloakGatewayImpl(KeycloakConfig keycloakConfig) {
         this.keycloakConfig = keycloakConfig;
     }
 
     @Override
-    public TokenDto obtainUserToken(String username, String password) throws RemoteUnavailableException, ServiceException {
+    public TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException,
+            CredentialsInvalidException, AccountNotSetupException {
         final HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
         final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
         payload.add("username", username);
         payload.add("password", password);
         payload.add("grant_type", "password");
-        payload.add("scope", "openid roles attributes");
+        payload.add("scope", "openid roles");
         payload.add("client_id", keycloakConfig.getKeycloakClient());
         payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
         final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/dbrepo/protocol/openid-connect/token";
-        log.debug("request user token from url {}", url);
+        log.trace("request user token from url: {}", url);
+        log.trace("request username: {}", username);
+        log.trace("request password: {}", password != null ? "(set)" : "(not set)");
+        log.trace("request client_id: {}", keycloakConfig.getKeycloakClient());
+        log.trace("request client_secret: {}", keycloakConfig.getKeycloakClientSecret());
         final ResponseEntity<TokenDto> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
+            response = new RestTemplate()
+                    .exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to obtain user token: {}", e.getMessage());
-            throw new RemoteUnavailableException("Failed to obtain user token: " + e.getMessage(), e);
-        } catch (Exception e) {
-            log.error("Failed to obtain user token: unexpected response: {}", e.getMessage(), e);
-            throw new ServiceException("Failed to obtain user token: unexpected response: " + e.getMessage(), e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.OK)) {
-            log.error("Failed to obtain user token: service responded unsuccessful: {}", response.getStatusCode());
-            throw new ServiceException("obtain user token: service responded unsuccessful: " + response.getStatusCode());
+            throw new AuthServiceConnectionException("Service unavailable", e);
+        } catch (HttpClientErrorException.BadRequest e) {
+            if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) {
+                final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
+                if (error != null && error.getError().equals("invalid_grant")) {
+                    log.error("Failed to obtain user token: {}", error.getErrorDescription());
+                    throw new AccountNotSetupException(error.getErrorDescription());
+                }
+            }
+            log.error("Failed to obtain user token: bad request");
+            throw new CredentialsInvalidException("Bad request", e);
+        } catch (HttpClientErrorException.Unauthorized e) {
+            log.error("Failed to obtain user token: invalid credentials");
+            throw new CredentialsInvalidException("Invalid credentials", e);
         }
         return response.getBody();
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java
index 1fcf3e50ee3df4487eae8492867aa4952413c699..a3fda6482c2d18cb75bab577644f8ce630314e6e 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java
@@ -46,7 +46,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
-            ContainerNotFoundException, ServiceException {
+            ContainerNotFoundException, MetadataServiceException {
         final ResponseEntity<ContainerDto> response;
         try {
             response = restTemplate.exchange("/api/container/" + containerId, HttpMethod.GET, HttpEntity.EMPTY,
@@ -60,15 +60,15 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (response.getStatusCode() != HttpStatus.OK) {
             log.error("Failed to find container with id {}: service responded unsuccessful: {}", containerId, response.getStatusCode());
-            throw new ServiceException("Failed to find container: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find container: service responded unsuccessful: " + response.getStatusCode());
         }
         if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) {
             log.error("Failed to find all privileged container headers");
-            throw new ServiceException("Failed to find all privileged container headers");
+            throw new MetadataServiceException("Failed to find all privileged container headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find container with id {}: body is empty", containerId);
-            throw new ServiceException("Failed to find container with id " + containerId + ": body is empty");
+            throw new MetadataServiceException("Failed to find container with id " + containerId + ": body is empty");
         }
         final PrivilegedContainerDto container = metadataMapper.containerDtoToPrivilegedContainerDto(response.getBody());
         container.setUsername(response.getHeaders().get("X-Username").get(0));
@@ -78,7 +78,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
-            ServiceException {
+            MetadataServiceException {
         final ResponseEntity<PrivilegedDatabaseDto> response;
         try {
             response = restTemplate.exchange("/api/database/" + id, HttpMethod.GET, HttpEntity.EMPTY,
@@ -92,15 +92,15 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (response.getStatusCode() != HttpStatus.OK) {
             log.error("Failed to find database with id {}: service responded unsuccessful: {}", id, response.getStatusCode());
-            throw new ServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode());
         }
         if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) {
             log.error("Failed to find all privileged database headers");
-            throw new ServiceException("Failed to find all privileged database headers");
+            throw new MetadataServiceException("Failed to find all privileged database headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find database with id {}: body is empty", id);
-            throw new ServiceException("Failed to find database with id " + id + ": body is empty");
+            throw new MetadataServiceException("Failed to find database with id " + id + ": body is empty");
         }
         final PrivilegedDatabaseDto database = response.getBody();
         database.getContainer().setUsername(response.getHeaders().get("X-Username").get(0));
@@ -111,7 +111,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
         final ResponseEntity<PrivilegedDatabaseDto[]> response;
         try {
             response = restTemplate.exchange("/api/database/", HttpMethod.GET, HttpEntity.EMPTY, PrivilegedDatabaseDto[].class);
@@ -121,7 +121,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK) || response.getBody() == null) {
             log.error("Failed to find database with internal name {}: service responded unsuccessful: {}", internalName, response.getStatusCode());
-            throw new ServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode());
         }
         if (response.getBody().length != 1) {
             log.error("Failed to find database with internal name {}: body is empty", internalName);
@@ -132,7 +132,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException,
-            RemoteUnavailableException, ServiceException {
+            RemoteUnavailableException, MetadataServiceException {
         final ResponseEntity<TableDto> response;
         try {
             response = restTemplate.exchange("/api/database/" + databaseId + "/table/" + id, HttpMethod.GET, HttpEntity.EMPTY, TableDto.class);
@@ -145,15 +145,15 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find table with id {}: service responded unsuccessful: {}", id, response.getStatusCode());
-            throw new ServiceException("Failed to find table: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find table: service responded unsuccessful: " + response.getStatusCode());
         }
         if (!response.getHeaders().keySet().containsAll(List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port"))) {
             log.error("Failed to find all privileged table headers");
-            throw new ServiceException("Failed to find all privileged table headers");
+            throw new MetadataServiceException("Failed to find all privileged table headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find table with id {}: body is empty", id);
-            throw new ServiceException("Failed to find table with id " + id + ": body is empty");
+            throw new MetadataServiceException("Failed to find table with id " + id + ": body is empty");
         }
         final PrivilegedTableDto table = metadataMapper.tableDtoToPrivilegedTableDto(response.getBody());
         table.getDatabase().getContainer().getImage().setJdbcMethod(response.getHeaders().get("X-Type").get(0));
@@ -170,7 +170,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException,
-            ViewNotFoundException, ServiceException {
+            ViewNotFoundException, MetadataServiceException {
         final ResponseEntity<ViewDto> response;
         try {
             response = restTemplate.exchange("/api/database/" + databaseId + "/view/" + id, HttpMethod.GET, HttpEntity.EMPTY, ViewDto.class);
@@ -183,15 +183,15 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find view with id {}: service responded unsuccessful: {}", id, response.getStatusCode());
-            throw new ServiceException("Failed to find view: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find view: service responded unsuccessful: " + response.getStatusCode());
         }
         if (!response.getHeaders().keySet().containsAll(List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database"))) {
             log.error("Failed to find all privileged view headers");
-            throw new ServiceException("Failed to find all privileged view headers");
+            throw new MetadataServiceException("Failed to find all privileged view headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find view with id {}: body is empty", id);
-            throw new ServiceException("Failed to find view with id " + id + ": body is empty");
+            throw new MetadataServiceException("Failed to find view with id " + id + ": body is empty");
         }
         final PrivilegedViewDto table = metadataMapper.viewDtoToPrivilegedViewDto(response.getBody());
         table.getDatabase().getContainer().getImage().setJdbcMethod(response.getHeaders().get("X-Type").get(0));
@@ -205,7 +205,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
-            ServiceException {
+            MetadataServiceException {
         final ResponseEntity<UserDto> response;
         try {
             response = restTemplate.exchange("/api/user/" + userId, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class);
@@ -218,18 +218,18 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode());
-            throw new ServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to find user with id {}: body is empty", userId);
-            throw new ServiceException("Failed to find user with id " + userId + ": body is empty");
+            throw new MetadataServiceException("Failed to find user with id " + userId + ": body is empty");
         }
         return response.getBody();
     }
 
     @Override
     public PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
-            ServiceException {
+            MetadataServiceException {
         final ResponseEntity<UserDto> response;
         try {
             response = restTemplate.exchange("/api/user/" + userId, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class);
@@ -242,15 +242,15 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode());
-            throw new ServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode());
         }
         if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) {
             log.error("Failed to find all privileged user headers");
-            throw new ServiceException("Failed to find all privileged user headers");
+            throw new MetadataServiceException("Failed to find all privileged user headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find user with id {}: body is empty", userId);
-            throw new ServiceException("Failed to find user with id " + userId + ": body is empty");
+            throw new MetadataServiceException("Failed to find user with id " + userId + ": body is empty");
         }
         final PrivilegedUserDto user = metadataMapper.userDtoToPrivilegedUserDto(response.getBody());
         user.setUsername(response.getHeaders().get("X-Username").get(0));
@@ -260,7 +260,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     @Override
     public DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException,
-            NotAllowedException, ServiceException {
+            NotAllowedException, MetadataServiceException {
         final ResponseEntity<DatabaseAccessDto> response;
         try {
             response = restTemplate.exchange("/api/database/" + databaseId + "/access/" + userId, HttpMethod.GET, HttpEntity.EMPTY, DatabaseAccessDto.class);
@@ -273,17 +273,17 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find database access for user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode());
-            throw new ServiceException("Failed to find database access: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find database access: service responded unsuccessful: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to find database access: body is empty");
-            throw new ServiceException("Failed to find database access: body is empty");
+            throw new MetadataServiceException("Failed to find database access: body is empty");
         }
         return response.getBody();
     }
 
     @Override
-    public List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws ServiceException,
+    public List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws MetadataServiceException,
             RemoteUnavailableException, DatabaseNotFoundException {
         final ResponseEntity<IdentifierDto[]> response;
         final String url = "/api/identifier?dbid=" + databaseId + (subsetId != null ? ("&qid=" + subsetId) : "");
@@ -299,17 +299,17 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find identifiers for database with id {} and subset with id {}: service responded unsuccessful: {}", databaseId, subsetId, response.getStatusCode());
-            throw new ServiceException("Failed to find identifiers for database: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to find identifiers for database: service responded unsuccessful: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to find identifiers: body is null");
-            throw new ServiceException("Failed to find identifiers: body is null");
+            throw new MetadataServiceException("Failed to find identifiers: body is null");
         }
         return List.of(response.getBody());
     }
 
     @Override
-    public void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, ServiceException,
+    public void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, MetadataServiceException,
             RemoteUnavailableException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/table/" + tableId;
@@ -324,7 +324,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to update table statistic for table with id {}: service responded unsuccessful: {}", tableId, response.getStatusCode());
-            throw new ServiceException("Failed to update table statistic for database: service responded unsuccessful: " + response.getStatusCode());
+            throw new MetadataServiceException("Failed to update table statistic for database: service responded unsuccessful: " + response.getStatusCode());
         }
     }
 
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
index 192fc30a61bcf68743d0f9eec36a190a3bc4941b..fac47a3d80f6030f5e7d4d561c4262123e9feea7 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
@@ -64,7 +64,7 @@ public class DefaultListener implements MessageListener {
             log.error("Failed to read object: {}", e.getMessage());
         } catch (SQLException | RemoteUnavailableException e) {
             log.error("Failed to insert tuple: {}", e.getMessage());
-        } catch (TableNotFoundException | ServiceException e) {
+        } catch (TableNotFoundException | MetadataServiceException e) {
             log.error("Failed to find table: {}", e.getMessage());
         }
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
index 8cadf146b1e6acc6cac355d3890a492993a0fff5..b6b782a04c6c2c9c353f837caee4c8f1f2b213ec 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
@@ -94,6 +94,13 @@ public interface MariaDbMapper {
         return statement;
     }
 
+    @Named("dropView")
+    default String dropViewRawQuery(String viewName) {
+        final String statement = "DROP VIEW IF EXISTS `" + viewName + "`;";
+        log.trace("mapped drop view statement: {}", statement);
+        return statement;
+    }
+
     default String databaseViewSelectRawQuery() {
         final String statement = "SELECT t.`TABLE_NAME`, t.`TABLE_TYPE`, t.`TABLE_ROWS`, t.`AVG_ROW_LENGTH`, t.`DATA_LENGTH`, t.`MAX_DATA_LENGTH`, COALESCE(t.`CREATE_TIME`, NOW()) as `CREATE_TIME`, t.`UPDATE_TIME`, v.`VIEW_DEFINITION` FROM information_schema.TABLES t LEFT JOIN information_schema.VIEWS v ON t.`TABLE_NAME` = v.`TABLE_NAME` WHERE t.`TABLE_SCHEMA` = ? AND t.`TABLE_TYPE` = 'VIEW' AND t.`TABLE_NAME` != 'qs_queries' AND t.`TABLE_NAME` = ?";
         log.trace("mapped select view statement: {}", statement);
@@ -439,9 +446,20 @@ public interface MariaDbMapper {
         return statement.toString();
     }
 
-    default String subsetToRawExportQuery(String query, Instant timestamp, String filePath) {
-        final StringBuilder statement = new StringBuilder(query.replaceAll(";", ""))
-                .append(" FOR SYSTEM_TIME AS OF TIMESTAMP'")
+    default String subsetToRawTemporaryViewQuery(String viewName, String query) {
+        final StringBuilder statement = new StringBuilder("CREATE VIEW `")
+                .append(viewName)
+                .append("` AS (")
+                .append(query)
+                .append(");");
+        log.debug("mapped temporary view query: {}", statement);
+        return statement.toString();
+    }
+
+    default String subsetToRawExportQuery(String viewName, Instant timestamp, String filePath) {
+        final StringBuilder statement = new StringBuilder("SELECT * FROM `")
+                .append(viewName)
+                .append("` FOR SYSTEM_TIME AS OF TIMESTAMP'")
                 .append(mariaDbFormatter.format(timestamp))
                 .append("'")
                 .append(" INTO OUTFILE '")
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java
index 7c2575b9cc348724f801dfd7e67d322b5ddd2070..3c3ff101fead4b51caadc8c207848d2b962f98eb 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java
@@ -28,7 +28,9 @@ public interface SubsetService {
 
     QueryResultDto execute(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId, Long page,
                            Long size, SortTypeDto sortDirection, String sortColumn)
-            throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException, UserNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException;
+            throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException,
+            UserNotFoundException, NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException,
+            MetadataServiceException;
 
     QueryResultDto reExecute(PrivilegedDatabaseDto database, QueryDto query, Long page, Long size,
                              SortTypeDto sortDirection, String sortColumn) throws TableMalformedException,
@@ -45,11 +47,12 @@ public interface SubsetService {
      * @return The list of queries.
      */
     List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException,
-            QueryNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException;
+            QueryNotFoundException, NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException,
+            MetadataServiceException;
 
     ExportResourceDto export(PrivilegedDatabaseDto database, QueryDto query, Instant timestamp, String filename)
             throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException,
-            StorageUnavailableException, ServiceException, RemoteUnavailableException;
+            StorageUnavailableException, MetadataServiceException, RemoteUnavailableException;
 
     Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp)
             throws SQLException, QueryMalformedException, TableMalformedException;
@@ -62,7 +65,9 @@ public interface SubsetService {
      * @return The query.
      * @throws QueryNotFoundException The query store did not return a query
      */
-    QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, NotAllowedException, RemoteUnavailableException, UserNotFoundException, ServiceException, DatabaseNotFoundException;
+    QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException,
+            NotAllowedException, RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException,
+            MetadataServiceException;
 
     /**
      * Inserts a query and metadata to the query store of a given database id.
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java
index 98ed0ec7aea96a0c757d480d2829e2dfb82a2665..50894eb77a46b3b2fc0f77d7ebe0f99b73e895af 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java
@@ -105,7 +105,7 @@ public interface TableService {
             QueryMalformedException;
 
     void importDataset(PrivilegedTableDto table, ImportCsvDto data) throws SidecarImportException,
-            StorageNotFoundException, SQLException, QueryMalformedException, ServiceException, RemoteUnavailableException;
+            StorageNotFoundException, SQLException, QueryMalformedException, RemoteUnavailableException;
 
     void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException,
             TableMalformedException, QueryMalformedException;
@@ -118,5 +118,5 @@ public interface TableService {
 
     ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp)
             throws SQLException, SidecarExportException, StorageNotFoundException, StorageUnavailableException,
-            QueryMalformedException, ServiceException, RemoteUnavailableException;
+            QueryMalformedException, RemoteUnavailableException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java
index 3455c320cd10c2e488220843db8ac3d644ef902d..5acca0018de6bc3e29de49aea9f1da4ae95ff492 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java
@@ -58,5 +58,5 @@ public interface ViewService {
 
     ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp)
             throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException,
-            StorageUnavailableException, ServiceException, RemoteUnavailableException;
+            StorageUnavailableException, RemoteUnavailableException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java
index b2d3f1b5504faec2313b6fc7b6b8b9b522b8fdab..c8b49fd4cb5b91637b14d2325806254bd1bda527 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java
@@ -72,9 +72,10 @@ public class StorageServiceS3Impl implements StorageService {
     @Override
     public ExportResourceDto getResource(String bucket, String key) throws StorageNotFoundException,
             StorageUnavailableException {
-        final InputStream stream = getObject(bucket, key);
+        final InputStreamResource resource = new InputStreamResource(getObject(bucket, key));
+        log.trace("return export resource with filename: {}", key);
         return ExportResourceDto.builder()
-                .resource(new InputStreamResource(stream))
+                .resource(resource)
                 .filename(key)
                 .build();
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java
index 2ab2f7b349fe6cf2ba2129679a22024e9167c0fc..3d19276196895efc00834b60383ddfa226a46bc3 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java
@@ -19,12 +19,16 @@ import at.tuwien.mapper.MariaDbMapper;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.SubsetService;
 import at.tuwien.service.StorageService;
+import com.google.common.hash.Hashing;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
 import net.sf.jsqlparser.JSQLParserException;
+import org.apache.commons.lang3.RandomUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.sql.*;
 import java.time.Instant;
 import java.util.LinkedList;
@@ -58,7 +62,8 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     }
 
     @Override
-    public void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException, QueryStoreCreateException {
+    public void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException,
+            QueryStoreCreateException {
         final ComboPooledDataSource dataSource = getPrivilegedDataSource(container, databaseName);
         final Connection connection = dataSource.getConnection();
         try {
@@ -88,8 +93,8 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     public QueryResultDto execute(PrivilegedDatabaseDto database, String statement, Instant timestamp,
                                   UUID userId, Long page, Long size, SortTypeDto sortDirection, String sortColumn)
             throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException,
-            UserNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException,
-            DatabaseNotFoundException {
+            UserNotFoundException, NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException,
+            MetadataServiceException {
         final Long queryId = storeQuery(database, statement, timestamp, userId);
         final QueryDto query = findById(database, queryId);
         return reExecute(database, query, page, size, sortDirection, sortColumn);
@@ -120,7 +125,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
 
     @Override
     public List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException,
-            QueryNotFoundException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException {
+            QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
         final List<IdentifierDto> identifiers = metadataServiceGateway.getIdentifiers(database.getId(), null);
         final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
         final Connection connection = dataSource.getConnection();
@@ -153,13 +158,21 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     @Override
     public ExportResourceDto export(PrivilegedDatabaseDto database, QueryDto query, Instant timestamp, String filename)
             throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException,
-            StorageUnavailableException, ServiceException, RemoteUnavailableException {
+            StorageUnavailableException, RemoteUnavailableException {
         final String filePath = s3Config.getS3FilePath() + "/" + filename;
+        final String viewName = "ex_" + Hashing.sha512()
+                .hashString(new String(RandomUtils.nextBytes(256), Charset.defaultCharset()), Charset.defaultCharset())
+                .toString()
+                .substring(0, 60);
         final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* export to data database sidecar */
-            connection.prepareStatement(mariaDbMapper.subsetToRawExportQuery(query.getQuery(), timestamp, filePath))
+            connection.prepareStatement(mariaDbMapper.subsetToRawTemporaryViewQuery(viewName, query.getQuery()))
+                    .executeUpdate();
+            connection.prepareStatement(mariaDbMapper.subsetToRawExportQuery(viewName, timestamp, filePath))
+                    .executeUpdate();
+            connection.prepareStatement(mariaDbMapper.dropViewRawQuery(viewName))
                     .executeUpdate();
             connection.commit();
         } catch (SQLException e) {
@@ -208,7 +221,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
 
     @Override
     public QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException,
-            RemoteUnavailableException, UserNotFoundException, ServiceException, DatabaseNotFoundException {
+            RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException, MetadataServiceException {
         final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
index be15d46895d37f665120f58b047ae52fb7d7742f..e913c0cb82f22cd12654c7cd23d160bf68b5ef87 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
@@ -245,8 +245,8 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
     }
 
     @Override
-    public void importDataset(PrivilegedTableDto table, ImportCsvDto data)
-            throws StorageNotFoundException, SQLException, QueryMalformedException, ServiceException, RemoteUnavailableException {
+    public void importDataset(PrivilegedTableDto table, ImportCsvDto data) throws StorageNotFoundException,
+            SQLException, QueryMalformedException, RemoteUnavailableException, SidecarImportException {
         /* import .csv from blob storage to sidecar */
         dataDatabaseSidecarGateway.importFile(table.getDatabase().getContainer().getSidecarHost(), table.getDatabase().getContainer().getSidecarPort(), data.getLocation());
         /* import .csv from sidecar to database */
@@ -297,8 +297,8 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
     }
 
     @Override
-    public void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException,
-            QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException {
+    public void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, QueryMalformedException,
+            TableMalformedException, StorageUnavailableException, StorageNotFoundException {
         log.trace("create tuple: {}", data);
         /* for each LOB-like data-column, retrieve the bytes and replace the value */
         for (String key : data.getData().keySet()) {
@@ -385,8 +385,8 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
 
     @Override
     public ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp) throws SQLException,
-            StorageNotFoundException, StorageUnavailableException, QueryMalformedException, ServiceException,
-            RemoteUnavailableException {
+            StorageNotFoundException, StorageUnavailableException, QueryMalformedException, RemoteUnavailableException,
+            SidecarExportException {
         final String fileName = RandomStringUtils.randomAlphabetic(40) + ".csv";
         final String filePath = s3Config.getS3FilePath() + "/" + fileName;
         final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java
index 6f88c409737605671eb31e8b151e9a35ae23afa5..3cdba35f085491334300cc3fb5a3ab3ee30801fd 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java
@@ -174,7 +174,7 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe
         final Connection connection = dataSource.getConnection();
         try {
             /* drop view if exists */
-            connection.prepareStatement("DROP VIEW IF EXISTS `" + view.getInternalName() + "`;")
+            connection.prepareStatement(mariaDbMapper.dropViewRawQuery(view.getInternalName()))
                     .execute();
             connection.commit();
         } catch (SQLException e) {
@@ -214,8 +214,8 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe
 
     @Override
     public ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp)
-            throws SQLException, QueryMalformedException, StorageNotFoundException,
-            StorageUnavailableException, ServiceException, RemoteUnavailableException {
+            throws SQLException, QueryMalformedException, StorageNotFoundException, StorageUnavailableException,
+            RemoteUnavailableException, SidecarExportException {
         final String fileName = RandomStringUtils.randomAlphabetic(40) + ".csv";
         final String filePath = s3Config.getS3FilePath() + "/" + fileName;
         final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile
index 75fe485c16073094c202a476cd55ddf5c6fb84e7..1a37bf7e7e0a87c9c4e9caac814f005b3847badf 100644
--- a/dbrepo-metadata-service/Dockerfile
+++ b/dbrepo-metadata-service/Dockerfile
@@ -34,9 +34,9 @@ RUN apk add --no-cache curl bash jq
 
 WORKDIR /app
 
-USER 65534
+USER 1001
 
-COPY --from=build --chown=65534 ./rest-service/target/dbrepo-metadata-service-rest-service-*.jar ./metadata-service.jar
+COPY --from=build --chown=1001 ./rest-service/target/dbrepo-metadata-service-rest-service-*.jar ./metadata-service.jar
 
 # non-root port
 EXPOSE 8080
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/KeycloakErrorDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/KeycloakErrorDto.java
index 4b9eefa16d30fcc264a4673aaf6ddde8f1d4aeb0..9b8ad90ea55d8d4aba75e637e4f9906fcc7e86d9 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/KeycloakErrorDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/KeycloakErrorDto.java
@@ -6,6 +6,8 @@ import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
+import java.io.Serializable;
+
 @Getter
 @Setter
 @Builder
@@ -13,7 +15,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class KeycloakErrorDto {
+public class KeycloakErrorDto implements Serializable {
 
     @NotNull
     @Schema(example = "invalid_grant")
@@ -23,4 +25,6 @@ public class KeycloakErrorDto {
     @JsonProperty("error_description")
     private String errorDescription;
 
+    private String errorMessage;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/RoleRepresentationDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/RoleRepresentationDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f7d795fdbb0a529fa4492c18f9028016e306d9e
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/RoleRepresentationDto.java
@@ -0,0 +1,34 @@
+package at.tuwien.api.keycloak;
+
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.util.UUID;
+
+/**
+ * https://www.keycloak.org/docs-api/22.0.1/rest-api/index.html#RoleRepresentation
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class RoleRepresentationDto {
+
+    private UUID id;
+
+    private String name;
+
+    private String description;
+
+    private Boolean scopeParamRequired;
+
+    private Boolean composite;
+
+    private Boolean clientRole;
+
+    private UUID containerId;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java
index 0ebaffff10441d984ea13005d8dc1ff3db6954cb..fe4b69550259023b135bf2ae43a70c85c888cce0 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java
@@ -32,4 +32,8 @@ public class UserCreateDto {
     @NotNull
     private List<CredentialDto> credentials;
 
+    private List<String> realmRoles;
+
+    private List<String> groups;
+
 }
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
index 9a50f5c0545c8351b5fae16157b171d2f52dd870..c869e41637659675e317281fd55092e3b331fc6b 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
@@ -86,13 +86,13 @@ public class TableColumn implements Comparable<TableColumn> {
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
     private Instant created;
 
-    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST})
+    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
     @JoinTable(name = "mdb_columns_concepts",
             joinColumns = @JoinColumn(name = "cid", referencedColumnName = "id", nullable = false),
             inverseJoinColumns = @JoinColumn(name = "id", referencedColumnName = "id"))
     private TableColumnConcept concept;
 
-    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST})
+    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
     @JoinTable(name = "mdb_columns_units",
             joinColumns = @JoinColumn(name = "cid", referencedColumnName = "id", nullable = false),
             inverseJoinColumns = @JoinColumn(name = "id", referencedColumnName = "id"))
diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml
index ef3bee26370857c035b7df3971f6d95e9924854a..0fdc80b428c3120888362bed339edbd9097f0ac4 100644
--- a/dbrepo-metadata-service/pom.xml
+++ b/dbrepo-metadata-service/pom.xml
@@ -58,6 +58,7 @@
         <keycloak-testcontainer.version>3.2.0</keycloak-testcontainer.version>
         <aws-s3.version>2.25.23</aws-s3.version>
         <jackson.version>2.15.2</jackson.version>
+        <minio.version>8.5.7</minio.version>
     </properties>
 
     <dependencies>
@@ -248,6 +249,11 @@
             <version>${testcontainers.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>minio</artifactId>
+            <version>${testcontainers.version}</version>
+        </dependency>
         <dependency>
             <groupId>com.github.dasniko</groupId>
             <artifactId>testcontainers-keycloak</artifactId>
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceConnectionException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceConnectionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..6efa16fa8757fbfcf218f09f0750a500d40161b3
--- /dev/null
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceConnectionException.java
@@ -0,0 +1,21 @@
+package at.tuwien.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.BAD_GATEWAY, reason = "error.broker.connection")
+public class BrokerServiceConnectionException extends Exception {
+
+    public BrokerServiceConnectionException(String msg) {
+        super(msg);
+    }
+
+    public BrokerServiceConnectionException(String msg, Throwable thr) {
+        super(msg + ": " + thr.getLocalizedMessage(), thr);
+    }
+
+    public BrokerServiceConnectionException(Throwable thr) {
+        super(thr);
+    }
+
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/StorageUnavailableException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceException.java
similarity index 52%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/StorageUnavailableException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceException.java
index b25bac260eba40176933114765c0633de3caa21a..86201c5d691bdede33bca6bef2606125b29775de 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/StorageUnavailableException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceException.java
@@ -3,18 +3,18 @@ package at.tuwien.exception;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
-@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.storage.missing")
-public class StorageUnavailableException extends Exception {
+@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.broker.invalid")
+public class BrokerServiceException extends Exception {
 
-    public StorageUnavailableException(String message) {
+    public BrokerServiceException(String message) {
         super(message);
     }
 
-    public StorageUnavailableException(String message, Throwable thr) {
+    public BrokerServiceException(String message, Throwable thr) {
         super(message, thr);
     }
 
-    public StorageUnavailableException(Throwable thr) {
+    public BrokerServiceException(Throwable thr) {
         super(thr);
     }
 
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ServiceConnectionException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceConnectionException.java
similarity index 57%
rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ServiceConnectionException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceConnectionException.java
index 069e1d774a564e7286bd6cbc73d6d501f7e81562..0125a781add4e384e43ec87690b0f8afaeb30c92 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ServiceConnectionException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceConnectionException.java
@@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 @ResponseStatus(code = HttpStatus.BAD_GATEWAY, reason = "error.data.connection")
-public class ServiceConnectionException extends Exception {
+public class DataServiceConnectionException extends Exception {
 
-    public ServiceConnectionException(String msg) {
+    public DataServiceConnectionException(String msg) {
         super(msg);
     }
 
-    public ServiceConnectionException(String msg, Throwable thr) {
+    public DataServiceConnectionException(String msg, Throwable thr) {
         super(msg + ": " + thr.getLocalizedMessage(), thr);
     }
 
-    public ServiceConnectionException(Throwable thr) {
+    public DataServiceConnectionException(Throwable thr) {
         super(thr);
     }
 
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ServiceException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceException.java
similarity index 59%
rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ServiceException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceException.java
index 70bef91528a3731b387b6ab55d95a7a1c99f4572..f76e662a655593ffe5991ec84da207b58df052b2 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ServiceException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceException.java
@@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.data.invalid")
-public class ServiceException extends Exception {
+public class DataServiceException extends Exception {
 
-    public ServiceException(String message) {
+    public DataServiceException(String message) {
         super(message);
     }
 
-    public ServiceException(String message, Throwable thr) {
+    public DataServiceException(String message, Throwable thr) {
         super(message, thr);
     }
 
-    public ServiceException(Throwable thr) {
+    public DataServiceException(Throwable thr) {
         super(thr);
     }
 
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseMalformedException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExternalServiceException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExternalServiceException.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5f399c40205b886607f5fc1c22d17d9b159f6e4
--- /dev/null
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExternalServiceException.java
@@ -0,0 +1,21 @@
+package at.tuwien.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.external.invalid")
+public class ExternalServiceException extends Exception {
+
+    public ExternalServiceException(String message) {
+        super(message);
+    }
+
+    public ExternalServiceException(String message, Throwable thr) {
+        super(message, thr);
+    }
+
+    public ExternalServiceException(Throwable thr) {
+        super(thr);
+    }
+
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ServiceConnectionException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceConnectionException.java
similarity index 56%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/ServiceConnectionException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceConnectionException.java
index 6a91dac23aeaf7ff7efd0b5439e344606ce968a7..329de6ffc4b82b859da0ea41aca7ed99a3b1802c 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ServiceConnectionException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceConnectionException.java
@@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 @ResponseStatus(code = HttpStatus.BAD_GATEWAY, reason = "error.metadata.connection")
-public class ServiceConnectionException extends Exception {
+public class MetadataServiceConnectionException extends Exception {
 
-    public ServiceConnectionException(String msg) {
+    public MetadataServiceConnectionException(String msg) {
         super(msg);
     }
 
-    public ServiceConnectionException(String msg, Throwable thr) {
+    public MetadataServiceConnectionException(String msg, Throwable thr) {
         super(msg + ": " + thr.getLocalizedMessage(), thr);
     }
 
-    public ServiceConnectionException(Throwable thr) {
+    public MetadataServiceConnectionException(Throwable thr) {
         super(thr);
     }
 
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ServiceException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceException.java
similarity index 58%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/ServiceException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceException.java
index a543d02c9a4fe32335332eeef980c6283e4c4450..a6784d6dd01ed0c60379246373b26d3c49a8875d 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ServiceException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceException.java
@@ -4,17 +4,17 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.metadata.invalid")
-public class ServiceException extends Exception {
+public class MetadataServiceException extends Exception {
 
-    public ServiceException(String message) {
+    public MetadataServiceException(String message) {
         super(message);
     }
 
-    public ServiceException(String message, Throwable thr) {
+    public MetadataServiceException(String message, Throwable thr) {
         super(message, thr);
     }
 
-    public ServiceException(Throwable thr) {
+    public MetadataServiceException(Throwable thr) {
         super(thr);
     }
 
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryNotSupportedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotSupportedException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryNotSupportedException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotSupportedException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStoreCreateException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreCreateException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStoreCreateException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreCreateException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStoreGCException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreGCException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStoreGCException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreGCException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStoreInsertException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreInsertException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStoreInsertException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreInsertException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStorePersistException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStorePersistException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/QueryStorePersistException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStorePersistException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/SidecarExportException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SidecarExportException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/SidecarExportException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SidecarExportException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/SidecarImportException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SidecarImportException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/SidecarImportException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SidecarImportException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableMalformedException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableSchemaException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableSchemaException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/TableSchemaException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableSchemaException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewMalformedException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewSchemaException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewSchemaException.java
similarity index 100%
rename from dbrepo-data-service/services/src/main/java/at/tuwien/exception/ViewSchemaException.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewSchemaException.java
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
index fb7c80e0113838077f0a65826f636224440f9b94..557d1e49aba58b799f3dfa65fea8c4d0a8f7cf4c 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
@@ -467,8 +467,8 @@ public interface MetadataMapper {
     TableBriefDto tableToTableBriefDto(Table data);
 
     default UniqueDto uniqueToUniqueDto(Unique data) {
-        data.getTable().setOwner(null); /* loop */
-        data.getTable().setCreator(null); /* loop */
+//        data.getTable().setOwner(null); /* loop */
+//        data.getTable().setCreator(null); /* loop */
         return UniqueDto.builder()
                 .id(data.getId())
                 .name(data.getName())
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/UserUtil.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/UserUtil.java
index 7a99e839edd3b97758e713260f798ae5357c53c6..4e517625ed8bc7d700c1815a8437675d17534d85 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/UserUtil.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/UserUtil.java
@@ -18,6 +18,16 @@ public class UserUtil {
                 .anyMatch(a -> a.getAuthority().equals(role));
     }
 
+    public static boolean isSystem(Principal principal) {
+        if (principal == null) {
+            return false;
+        }
+        final Authentication authentication = (Authentication) principal;
+        return authentication.getAuthorities()
+                .stream()
+                .anyMatch(a -> a.getAuthority().equals("system"));
+    }
+
     public static UUID getId(Principal principal) {
         if (principal == null) {
             return null;
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
index 3c33e2b05781eb8d04362f68eb4c81f54d450312..9cdcfdedf9e88fd0138e236db6f15afb959ff2dc 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
@@ -94,8 +94,8 @@ public class AccessEndpoint {
     public ResponseEntity<DatabaseAccessDto> create(@NotBlank @PathVariable("databaseId") Long databaseId,
                                                     @NotBlank @PathVariable("userId") UUID userId,
                                                     @Valid @RequestBody UpdateDatabaseAccessDto data,
-                                                    @NotNull Principal principal) throws NotAllowedException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException,
+                                                    @NotNull Principal principal) throws NotAllowedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint give access to database, databaseId={}, userId={}, access.type={}", databaseId, userId,
                 data.getType());
@@ -157,7 +157,7 @@ public class AccessEndpoint {
                                        @NotBlank @PathVariable("userId") UUID userId,
                                        @Valid @RequestBody UpdateDatabaseAccessDto data,
                                        @NotNull Principal principal) throws NotAllowedException,
-            ServiceException, ServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
+            DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
             AccessNotFoundException, SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint modify database access, databaseId={}, userId={}, access.type={}", databaseId, userId,
                 data.getType());
@@ -176,9 +176,9 @@ public class AccessEndpoint {
     @RequestMapping(value = "/{userId}", method = {RequestMethod.GET, RequestMethod.HEAD})
     @Transactional(readOnly = true)
     @Observed(name = "dbrepo_access_get")
-    @PreAuthorize("hasAuthority('check-database-access') or hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('check-database-access') or hasAuthority('check-foreign-database-access')")
     @Operation(summary = "Find/Check access",
-            description = "Finds or checks access of a user with given id to a database with given id. Requests with HTTP method **GET** return the access object, requests with HTTP method **HEAD** only the status. When the user has at least *READ* access, the status 200 is returned, 403 otherwise. Requires role `check-database-access` or `admin`.",
+            description = "Finds or checks access of a user with given id to a database with given id. Requests with HTTP method **GET** return the access object, requests with HTTP method **HEAD** only the status. When the user has at least *READ* access, the status 200 is returned, 403 otherwise. Requires role `check-database-access` or `check-foreign-database-access`.",
             security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "200",
@@ -204,7 +204,7 @@ public class AccessEndpoint {
         log.debug("endpoint get database access, databaseId={}, userId={}, principal.name={}", databaseId, userId,
                 principal.getName());
         if (!userId.equals(UserUtil.getId(principal))) {
-            if (!UserUtil.hasRole(principal, "admin")) {
+            if (!UserUtil.hasRole(principal, "check-foreign-database-access")) {
                 log.error("Failed to find access: foreign user");
                 throw new NotAllowedException("Failed to find access: foreign user");
             }
@@ -256,8 +256,8 @@ public class AccessEndpoint {
     })
     public ResponseEntity<Void> revoke(@NotBlank @PathVariable("databaseId") Long databaseId,
                                        @NotBlank @PathVariable("userId") UUID userId,
-                                       @NotNull Principal principal) throws NotAllowedException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException,
+                                       @NotNull Principal principal) throws NotAllowedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint revoke database access, databaseId={}, userId={}", databaseId, userId);
         final Database database = databaseService.findById(databaseId);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index 77d35ec498863cd3db09531938a346e02ebb62c1..294d471e8fefe4ccafcf06f5aac47e23fce6f757 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -10,6 +10,7 @@ import at.tuwien.exception.ContainerNotFoundException;
 import at.tuwien.exception.ImageNotFoundException;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.ContainerService;
+import at.tuwien.utils.UserUtil;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.ArraySchema;
@@ -143,14 +144,11 @@ public class ContainerEndpoint {
         final ContainerDto dto = metadataMapper.containerToContainerDto(container);
         log.trace("find container resulted in container {}", dto);
         final HttpHeaders headers = new HttpHeaders();
-        if (principal != null) {
-            final Authentication authentication = (Authentication) principal;
-            if (authentication.isAuthenticated() && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("admin"))) {
-                log.trace("attach privileged credential information");
-                headers.set("X-Username", container.getPrivilegedUsername());
-                headers.set("X-Password", container.getPrivilegedPassword());
-                headers.set("Access-Control-Expose-Headers", "X-Username X-Password");
-            }
+        if (UserUtil.isSystem(principal)) {
+            log.trace("attach privileged credential information");
+            headers.set("X-Username", container.getPrivilegedUsername());
+            headers.set("X-Password", container.getPrivilegedPassword());
+            headers.set("Access-Control-Expose-Headers", "X-Username X-Password");
         }
         return ResponseEntity.ok()
                 .headers(headers)
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index d974de427667f390d995a7d25fbc9789484b5bb4..8be62ea5c400719b31764b0b931a329481b75018 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -8,6 +8,7 @@ import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.*;
+import at.tuwien.utils.UserUtil;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.headers.Header;
@@ -25,7 +26,6 @@ import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.Authentication;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
@@ -139,8 +139,8 @@ public class DatabaseEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<DatabaseDto> create(@Valid @RequestBody DatabaseCreateDto data,
-                                              @NotNull Principal principal) throws ServiceException,
-            ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException,
+                                              @NotNull Principal principal) throws DataServiceException,
+            DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint create database, data.name={}", data.getName());
         final User user = userService.findByUsername(principal.getName());
@@ -190,9 +190,10 @@ public class DatabaseEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<DatabaseDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                            @NotNull Principal principal) throws ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, MalformedException {
+                                                            @NotNull Principal principal) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
+            SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, MalformedException,
+            TableNotFoundException {
         log.debug("endpoint refresh database metadata, databaseId={}", databaseId);
         Database database = databaseService.findById(databaseId);
         if (!database.getOwner().equals(principal)) {
@@ -238,9 +239,9 @@ public class DatabaseEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<DatabaseDto> refreshViewMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                           @NotNull Principal principal) throws ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, NotAllowedException, QueryNotFoundException {
+                                                           @NotNull Principal principal) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
+            SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, ViewNotFoundException {
         log.debug("endpoint refresh database metadata, databaseId={}", databaseId);
         Database database = databaseService.findById(databaseId);
         if (!database.getOwner().equals(principal)) {
@@ -347,7 +348,7 @@ public class DatabaseEndpoint {
     public ResponseEntity<DatabaseDto> transfer(@NotNull @PathVariable("databaseId") Long databaseId,
                                                 @Valid @RequestBody DatabaseTransferDto data,
                                                 @NotNull Principal principal) throws NotAllowedException,
-            ServiceException, ServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
+            DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint transfer database, databaseId={}, transferDto.id={}", databaseId, data.getId());
         final Database database = databaseService.findById(databaseId);
@@ -452,8 +453,8 @@ public class DatabaseEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<DatabaseDto> findById(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                Principal principal) throws ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException {
+                                                Principal principal) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException {
         log.debug("endpoint find database, databaseId={}", databaseId);
         final Database database = databaseService.findById(databaseId);
         final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database);
@@ -467,13 +468,10 @@ public class DatabaseEndpoint {
             log.debug("found {} database accesses", accesses.size());
         }
         final HttpHeaders headers = new HttpHeaders();
-        if (principal != null) {
-            final Authentication authentication = (Authentication) principal;
-            if (authentication.isAuthenticated() && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("admin"))) {
-                headers.set("X-Username", database.getContainer().getPrivilegedUsername());
-                headers.set("X-Password", database.getContainer().getPrivilegedPassword());
-                headers.set("Access-Control-Expose-Headers", "X-Username X-Password");
-            }
+        if (UserUtil.isSystem(principal)) {
+            headers.set("X-Username", database.getContainer().getPrivilegedUsername());
+            headers.set("X-Password", database.getContainer().getPrivilegedPassword());
+            headers.set("Access-Control-Expose-Headers", "X-Username X-Password");
         }
         return ResponseEntity.status(HttpStatus.OK)
                 .headers(headers)
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
index 781e5c44e89c961a1f33d8797aded12ff08b511f..831e9cd28d7148b0eaec5b44c3cb4f3059726461 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
@@ -205,7 +205,7 @@ public class IdentifierEndpoint {
     })
     public ResponseEntity<?> find(@Valid @PathVariable("identifierId") Long identifierId,
                                   @RequestHeader(HttpHeaders.ACCEPT) String accept) throws IdentifierNotFoundException,
-            ServiceException, ServiceConnectionException, MalformedException, FormatNotAvailableException,
+            DataServiceException, DataServiceConnectionException, MalformedException, FormatNotAvailableException,
             QueryNotFoundException {
         log.debug("endpoint find identifier, identifierId={}, accept={}", identifierId, accept);
         final Identifier identifier = identifierService.find(identifierId);
@@ -300,8 +300,9 @@ public class IdentifierEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<Void> delete(@NotNull @PathVariable("identifierId") Long identifierId)
-            throws IdentifierNotFoundException, NotAllowedException, ServiceException, ServiceConnectionException,
-            DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
+            throws IdentifierNotFoundException, NotAllowedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
+            SearchServiceConnectionException {
         log.debug("endpoint delete identifier, identifierId={}", identifierId);
         final Identifier identifier = identifierService.find(identifierId);
         if (identifier.getStatus().equals(IdentifierStatusType.PUBLISHED)) {
@@ -354,7 +355,7 @@ public class IdentifierEndpoint {
     })
     public ResponseEntity<IdentifierDto> publish(@Valid @PathVariable("identifierId") Long identifierId)
             throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException,
-            MalformedException, ServiceConnectionException, IdentifierNotFoundException {
+            MalformedException, DataServiceConnectionException, IdentifierNotFoundException, ExternalServiceException {
         log.debug("endpoint publish identifier, identifierId={}", identifierId);
         identifierService.find(identifierId);
         return ResponseEntity.status(HttpStatus.CREATED)
@@ -403,9 +404,10 @@ public class IdentifierEndpoint {
     public ResponseEntity<IdentifierDto> save(@NotNull @PathVariable("identifierId") Long identifierId,
                                               @NotNull @Valid @RequestBody IdentifierSaveDto data,
                                               @NotNull Principal principal) throws UserNotFoundException,
-            DatabaseNotFoundException, MalformedException, NotAllowedException, ServiceException,
-            ServiceConnectionException, SearchServiceException, QueryNotFoundException,
-            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException, TableNotFoundException {
+            DatabaseNotFoundException, MalformedException, NotAllowedException, DataServiceException,
+            DataServiceConnectionException, SearchServiceException, QueryNotFoundException,
+            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException,
+            TableNotFoundException, ExternalServiceException {
         log.debug("endpoint save identifier, identifierId={}, data.id={}, principal.name={}", identifierId,
                 data.getId(), principal.getName());
         final Database database = databaseService.findById(data.getDatabaseId());
@@ -524,9 +526,9 @@ public class IdentifierEndpoint {
     })
     public ResponseEntity<IdentifierDto> create(@NotNull @Valid @RequestBody IdentifierCreateDto data,
                                                 @NotNull Principal principal) throws DatabaseNotFoundException,
-            UserNotFoundException, NotAllowedException, MalformedException, ServiceConnectionException,
-            SearchServiceException, ServiceException, QueryNotFoundException, SearchServiceConnectionException,
-            IdentifierNotFoundException, ViewNotFoundException {
+            UserNotFoundException, NotAllowedException, MalformedException, DataServiceConnectionException,
+            SearchServiceException, DataServiceException, QueryNotFoundException, SearchServiceConnectionException,
+            IdentifierNotFoundException, ViewNotFoundException, ExternalServiceException {
         log.debug("endpoint create identifier, data.databaseId={}", data.getDatabaseId());
         final Database database = databaseService.findById(data.getDatabaseId());
         final User user = userService.findByUsername(principal.getName());
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
index c8f01bf26a2e1eaa6f020ed80eefc5673aefc2d2..4fb8240b1d00f00f39a233cd3492e0b06940314a 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
@@ -35,7 +35,6 @@ import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.Authentication;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
@@ -152,7 +151,7 @@ public class TableEndpoint {
 
     @PutMapping("/{tableId}")
     @Transactional
-    @PreAuthorize("hasAuthority('update-table-statistic') or hasAuthority('admin')")
+    @PreAuthorize("hasAuthority('update-table-statistic')")
     @Observed(name = "dbrepo_statistic_table_update")
     @Operation(summary = "Update statistics",
             description = "Updates basic statistical properties (min, max, mean, median, std.dev) for numerical columns in a table with id. Requires role `update-table-statistic`",
@@ -184,7 +183,7 @@ public class TableEndpoint {
     public ResponseEntity<Void> updateStatistic(@NotNull @PathVariable("databaseId") Long databaseId,
                                                 @NotNull @PathVariable("tableId") Long tableId)
             throws TableNotFoundException, DatabaseNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, MalformedException, ServiceException, ServiceConnectionException {
+            SearchServiceConnectionException, MalformedException, DataServiceException, DataServiceConnectionException {
         log.debug("endpoint update table statistics, databaseId={}, tableId={}", databaseId, tableId);
         final Table table = tableService.findById(databaseId, tableId);
         tableService.updateStatistics(table);
@@ -236,7 +235,7 @@ public class TableEndpoint {
                                             @NotNull @PathVariable("columnId") Long columnId,
                                             @NotNull @Valid @RequestBody ColumnSemanticsUpdateDto updateDto,
                                             @NotNull Principal principal) throws NotAllowedException,
-            MalformedException, ServiceException, ServiceConnectionException, UserNotFoundException,
+            MalformedException, DataServiceException, DataServiceConnectionException, UserNotFoundException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         log.debug("endpoint update table, databaseId={}, tableId={}, columnId={}", databaseId, tableId, columnId);
@@ -343,7 +342,7 @@ public class TableEndpoint {
     public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                            @NotNull @Valid @RequestBody TableCreateDto data,
                                            @NotNull Principal principal) throws NotAllowedException, MalformedException,
-            ServiceException, ServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
+            DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
             AccessNotFoundException, TableNotFoundException, TableExistsException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName());
@@ -401,26 +400,22 @@ public class TableEndpoint {
     })
     public ResponseEntity<TableDto> findById(@NotNull @PathVariable("databaseId") Long databaseId,
                                              @NotNull @PathVariable("tableId") Long tableId,
-                                             Principal principal) throws ServiceException,
-            ServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, QueueNotFoundException {
+                                             Principal principal) throws DataServiceException,
+            DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, QueueNotFoundException {
         log.debug("endpoint find table, databaseId={}, tableId={}", databaseId, tableId);
         final Table table = tableService.findById(databaseId, tableId);
         final TableDto dto = metadataMapper.customTableToTableDto(table);
         final HttpHeaders headers = new HttpHeaders();
-        if (principal != null) {
-            /* extra effort only when logged-in */
-            final Authentication authentication = (Authentication) principal;
-            if (authentication.isAuthenticated() && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("admin"))) {
-                headers.set("X-Username", table.getDatabase().getContainer().getPrivilegedUsername());
-                headers.set("X-Password", table.getDatabase().getContainer().getPrivilegedPassword());
-                headers.set("X-Host", table.getDatabase().getContainer().getHost());
-                headers.set("X-Port", "" + table.getDatabase().getContainer().getPort());
-                headers.set("X-Type", table.getDatabase().getContainer().getImage().getJdbcMethod());
-                headers.set("X-Database", table.getDatabase().getInternalName());
-                headers.set("X-Sidecar-Host", table.getDatabase().getContainer().getSidecarHost());
-                headers.set("X-Sidecar-Port", "" + table.getDatabase().getContainer().getSidecarPort());
-                headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Sidecar-Host X-Sidecar-Port");
-            }
+        if (UserUtil.isSystem(principal)) {
+            headers.set("X-Username", table.getDatabase().getContainer().getPrivilegedUsername());
+            headers.set("X-Password", table.getDatabase().getContainer().getPrivilegedPassword());
+            headers.set("X-Host", table.getDatabase().getContainer().getHost());
+            headers.set("X-Port", "" + table.getDatabase().getContainer().getPort());
+            headers.set("X-Type", table.getDatabase().getContainer().getImage().getJdbcMethod());
+            headers.set("X-Database", table.getDatabase().getInternalName());
+            headers.set("X-Sidecar-Host", table.getDatabase().getContainer().getSidecarHost());
+            headers.set("X-Sidecar-Port", "" + table.getDatabase().getContainer().getSidecarPort());
+            headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Sidecar-Host X-Sidecar-Port");
         }
         return ResponseEntity.status(HttpStatus.OK)
                 .headers(headers)
@@ -466,7 +461,7 @@ public class TableEndpoint {
     public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") Long databaseId,
                                        @NotNull @PathVariable("tableId") Long tableId,
                                        @NotNull Principal principal) throws NotAllowedException,
-            ServiceException, ServiceConnectionException, TableNotFoundException, DatabaseNotFoundException,
+            DataServiceException, DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId);
         final Table table = tableService.findById(databaseId, tableId);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
index 1ee680e0169bfa24ca68eece30737de0763792bd..19e3a1df06cc7e67dae6cd6fdcadd3664abb9ee9 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
@@ -6,7 +6,6 @@ import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.user.*;
-import at.tuwien.config.KeycloakConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
@@ -187,14 +186,19 @@ public class UserEndpoint {
             userService.findByUsername(data.getUsername());
         } catch (UserNotFoundException e) {
             /* need to sync */
-            log.debug("User with username {} does not exist in metadata database yet", data.getUsername());
+            log.warn("User with username {} does not exist in metadata database yet", data.getUsername());
             final SignupRequestDto request = SignupRequestDto.builder()
                     .username(data.getUsername())
                     .email("noreply@example.com")
                     .password(data.getPassword())
                     .build();
-            userService.create(request, authenticationService.findByUsername(data.getUsername()).getId());
-            log.info("Fetched user information from auth service and stored it into metadata database");
+            final at.tuwien.api.keycloak.UserDto user = authenticationService.findByUsername(data.getUsername());
+            if (user.getAttributes().getLdapId().length != 1) {
+                log.error("Failed to map ldap id for user with username: {}", data.getUsername());
+                throw new UserNotFoundException("Failed to map ldap id");
+            }
+            userService.create(request, user.getAttributes().getLdapId()[0]);
+            log.info("Patched missing user information for user with username: {}", data.getUsername());
         }
         return ResponseEntity.accepted()
                 .body(token);
@@ -266,7 +270,7 @@ public class UserEndpoint {
         /* check */
         final User user = userService.findById(userId);
         if (!user.equals(principal)) {
-            if (!UserUtil.hasRole(principal, "admin")) {
+            if (!UserUtil.hasRole(principal, "find-foreign-user")) {
                 log.error("Failed to find user: foreign user");
                 throw new NotAllowedException("Failed to find user: foreign user");
             }
@@ -360,8 +364,8 @@ public class UserEndpoint {
     public ResponseEntity<Void> password(@NotNull @PathVariable("userId") UUID userId,
                                          @NotNull @Valid @RequestBody UserPasswordDto data,
                                          @NotNull Principal principal) throws NotAllowedException, AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ServiceException,
-            ServiceConnectionException, CredentialsInvalidException {
+            AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, DataServiceException,
+            DataServiceConnectionException, CredentialsInvalidException {
         log.debug("endpoint modify a user password, userId={}, data.password=(hidden)", userId);
         User user = userService.findById(userId);
         if (!user.equals(principal)) {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
index a22bdff267e906fcd372e32b5ba36c70944d2188..79981ee6d1fdcaaa5344915f7a0f3d3c43514926 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
@@ -4,7 +4,6 @@ import at.tuwien.api.database.ViewBriefDto;
 import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.error.ApiErrorDto;
-import at.tuwien.config.KeycloakConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.View;
 import at.tuwien.entities.user.User;
@@ -13,6 +12,7 @@ import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.DatabaseService;
 import at.tuwien.service.UserService;
 import at.tuwien.service.ViewService;
+import at.tuwien.utils.UserUtil;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.ArraySchema;
@@ -29,7 +29,6 @@ import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.Authentication;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
@@ -136,7 +135,7 @@ public class ViewEndpoint {
     public ResponseEntity<ViewBriefDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                                @NotNull @Valid @RequestBody ViewCreateDto data,
                                                @NotNull Principal principal) throws NotAllowedException,
-            MalformedException, ServiceException, ServiceConnectionException, DatabaseNotFoundException,
+            MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
             UserNotFoundException, SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint create view, databaseId={}, data={}", databaseId, data);
         final Database database = databaseService.findById(databaseId);
@@ -184,17 +183,14 @@ public class ViewEndpoint {
         final Database database = databaseService.findById(databaseId);
         final View view = viewService.findById(database, viewId);
         final HttpHeaders headers = new HttpHeaders();
-        if (principal != null) {
-            final Authentication authentication = (Authentication) principal;
-            if (authentication.isAuthenticated() && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("admin"))) {
-                headers.set("X-Username", view.getDatabase().getContainer().getPrivilegedUsername());
-                headers.set("X-Password", view.getDatabase().getContainer().getPrivilegedPassword());
-                headers.set("X-Host", view.getDatabase().getContainer().getHost());
-                headers.set("X-Port", "" + view.getDatabase().getContainer().getPort());
-                headers.set("X-Type", view.getDatabase().getContainer().getImage().getJdbcMethod());
-                headers.set("X-Database", view.getDatabase().getInternalName());
-                headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database");
-            }
+        if (UserUtil.isSystem(principal)) {
+            headers.set("X-Username", view.getDatabase().getContainer().getPrivilegedUsername());
+            headers.set("X-Password", view.getDatabase().getContainer().getPrivilegedPassword());
+            headers.set("X-Host", view.getDatabase().getContainer().getHost());
+            headers.set("X-Port", "" + view.getDatabase().getContainer().getPort());
+            headers.set("X-Type", view.getDatabase().getContainer().getImage().getJdbcMethod());
+            headers.set("X-Database", view.getDatabase().getInternalName());
+            headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database");
         }
         return ResponseEntity.status(HttpStatus.OK)
                 .headers(headers)
@@ -244,8 +240,8 @@ public class ViewEndpoint {
     })
     public ResponseEntity<View> delete(@NotNull @PathVariable("databaseId") Long databaseId,
                                        @NotNull @PathVariable("viewId") Long viewId,
-                                       @NotNull Principal principal) throws NotAllowedException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException,
+                                       @NotNull Principal principal) throws NotAllowedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId);
         final Database database = databaseService.findById(databaseId);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java
index 6b981eb62f8b395e16cd18aa74dc2a88e4c4c502..f6764895556ac07fe0321ae3e4a580f17e873d54 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java
@@ -44,6 +44,20 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.BAD_GATEWAY)
+    @ExceptionHandler(BrokerServiceConnectionException.class)
+    public ResponseEntity<ApiErrorDto> handle(BrokerServiceConnectionException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(BrokerServiceException.class)
+    public ResponseEntity<ApiErrorDto> handle(BrokerServiceException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
     @ExceptionHandler(ConceptNotFoundException.class)
@@ -72,6 +86,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
+    @ExceptionHandler(DatabaseMalformedException.class)
+    public ResponseEntity<ApiErrorDto> handle(DatabaseMalformedException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
     @ExceptionHandler(DatabaseNotFoundException.class)
@@ -79,6 +100,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(DatabaseUnavailableException.class)
+    public ResponseEntity<ApiErrorDto> handle(DatabaseUnavailableException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
     @ExceptionHandler(DoiNotFoundException.class)
@@ -100,30 +128,37 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(ExternalServiceException.class)
+    public ResponseEntity<ApiErrorDto> handle(ExternalServiceException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler({FilterBadRequestException.class})
+    @ExceptionHandler(FilterBadRequestException.class)
     public ResponseEntity<ApiErrorDto> handle(FilterBadRequestException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_ACCEPTABLE)
-    @ExceptionHandler({FormatNotAvailableException.class})
+    @ExceptionHandler(FormatNotAvailableException.class)
     public ResponseEntity<ApiErrorDto> handle(FormatNotAvailableException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({IdentifierNotFoundException.class})
+    @ExceptionHandler(IdentifierNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(IdentifierNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({IdentifierNotSupportedException.class})
+    @ExceptionHandler(IdentifierNotSupportedException.class)
     public ResponseEntity<ApiErrorDto> handle(IdentifierNotSupportedException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
@@ -158,18 +193,32 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
 
     @Hidden
     @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler({MalformedException.class})
+    @ExceptionHandler(MalformedException.class)
     public ResponseEntity<ApiErrorDto> handle(MalformedException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({MessageNotFoundException.class})
+    @ExceptionHandler(MessageNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(MessageNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.BAD_GATEWAY)
+    @ExceptionHandler(MetadataServiceConnectionException.class)
+    public ResponseEntity<ApiErrorDto> handle(MetadataServiceConnectionException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(MetadataServiceException.class)
+    public ResponseEntity<ApiErrorDto> handle(MetadataServiceException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.FORBIDDEN)
     @ExceptionHandler(NotAllowedException.class)
@@ -193,11 +242,18 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
 
     @Hidden
     @ResponseStatus(code = HttpStatus.BAD_REQUEST)
-    @ExceptionHandler({PaginationException.class})
+    @ExceptionHandler(PaginationException.class)
     public ResponseEntity<ApiErrorDto> handle(PaginationException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(QueryMalformedException.class)
+    public ResponseEntity<ApiErrorDto> handle(QueryMalformedException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
     @ExceptionHandler(QueryNotFoundException.class)
@@ -205,52 +261,108 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.NOT_IMPLEMENTED)
+    @ExceptionHandler(QueryNotSupportedException.class)
+    public ResponseEntity<ApiErrorDto> handle(QueryNotSupportedException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({QueueNotFoundException.class})
+    @ExceptionHandler(QueueNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(QueueNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
+    @ExceptionHandler(QueryStoreCreateException.class)
+    public ResponseEntity<ApiErrorDto> handle(QueryStoreCreateException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(QueryStoreGCException.class)
+    public ResponseEntity<ApiErrorDto> handle(QueryStoreGCException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
+    @ExceptionHandler(QueryStoreInsertException.class)
+    public ResponseEntity<ApiErrorDto> handle(QueryStoreInsertException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
+    @ExceptionHandler(QueryStorePersistException.class)
+    public ResponseEntity<ApiErrorDto> handle(QueryStorePersistException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(RemoteUnavailableException.class)
+    public ResponseEntity<ApiErrorDto> handle(RemoteUnavailableException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({RorNotFoundException.class})
+    @ExceptionHandler(RorNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(RorNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.BAD_GATEWAY)
-    @ExceptionHandler({SearchServiceConnectionException.class})
+    @ExceptionHandler(SearchServiceConnectionException.class)
     public ResponseEntity<ApiErrorDto> handle(SearchServiceConnectionException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler({SearchServiceException.class})
+    @ExceptionHandler(SearchServiceException.class)
     public ResponseEntity<ApiErrorDto> handle(SearchServiceException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({SemanticEntityNotFoundException.class})
+    @ExceptionHandler(SemanticEntityNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(SemanticEntityNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.BAD_GATEWAY)
-    @ExceptionHandler({ServiceConnectionException.class})
-    public ResponseEntity<ApiErrorDto> handle(ServiceConnectionException e) {
+    @ExceptionHandler(DataServiceConnectionException.class)
+    public ResponseEntity<ApiErrorDto> handle(DataServiceConnectionException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
-    @ExceptionHandler({ServiceException.class})
-    public ResponseEntity<ApiErrorDto> handle(ServiceException e) {
+    @ExceptionHandler(DataServiceException.class)
+    public ResponseEntity<ApiErrorDto> handle(DataServiceException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(SidecarExportException.class)
+    public ResponseEntity<ApiErrorDto> handle(SidecarExportException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE)
+    @ExceptionHandler(SidecarImportException.class)
+    public ResponseEntity<ApiErrorDto> handle(SidecarImportException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
@@ -282,23 +394,37 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(TableMalformedException.class)
+    public ResponseEntity<ApiErrorDto> handle(TableMalformedException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
+    @Hidden
+    @ResponseStatus(code = HttpStatus.CONFLICT)
+    @ExceptionHandler(TableSchemaException.class)
+    public ResponseEntity<ApiErrorDto> handle(TableSchemaException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({TableNotFoundException.class})
+    @ExceptionHandler(TableNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(TableNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
-    @ExceptionHandler({UnitNotFoundException.class})
+    @ExceptionHandler(UnitNotFoundException.class)
     public ResponseEntity<ApiErrorDto> handle(UnitNotFoundException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
     @Hidden
     @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED)
-    @ExceptionHandler({UriMalformedException.class})
+    @ExceptionHandler(UriMalformedException.class)
     public ResponseEntity<ApiErrorDto> handle(UriMalformedException e) {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
@@ -317,6 +443,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(ViewMalformedException.class)
+    public ResponseEntity<ApiErrorDto> handle(ViewMalformedException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     @Hidden
     @ResponseStatus(code = HttpStatus.NOT_FOUND)
     @ExceptionHandler(ViewNotFoundException.class)
@@ -324,6 +457,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
+    @Hidden
+    @ResponseStatus(code = HttpStatus.CONFLICT)
+    @ExceptionHandler(ViewSchemaException.class)
+    public ResponseEntity<ApiErrorDto> handle(ViewSchemaException e) {
+        return generic_handle(e.getClass(), e.getLocalizedMessage());
+    }
+
     private ResponseEntity<ApiErrorDto> generic_handle(Class<?> exceptionClass, String message) {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("Content-Type", "application/problem+json");
diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml
index fd44a809ca442d50bfd670703ef0c634ba68d4f5..63675da5656eb62b90b79ad2c9f2c99895e7e7c3 100644
--- a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml
+++ b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml
@@ -1,10 +1,4 @@
 spring:
-  ldap:
-    urls: ldap://localhost:1389
-    userDn: cn=admin,dc=dbrepo,dc=at
-    password: adminpassword
-    base: dc=dbrepo,dc=at
-    adminDn: cn=admins,ou=users,dc=dbrepo,dc=at
   datasource:
     url: jdbc:mariadb://localhost:3306/dbrepo
     driver-class-name: org.mariadb.jdbc.Driver
@@ -66,7 +60,7 @@ dbrepo:
     secretAccessKey: seaweedfsadmin
     importBucket: dbrepo-upload
     exportBucket: dbrepo-download
-  admin:
+  system:
     username: admin
     password: admin
   endpoints:
diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
index 0552cce9cb2b14a4e88714a85339137a6ddb4e0e..9398db2b546026d422f85037c2e2b7eb8d4773b8 100644
--- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
+++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
@@ -2,12 +2,6 @@ application:
   title: DBRepo
   version: '@project.version@'
 spring:
-  ldap:
-    urls: "${IDENTITY_SERVICE_URLS:ldap://identity-service:1389}"
-    userDn: "${IDENTITY_SERVICE_USERNAME:cn=admin,dc=dbrepo,dc=at}"
-    password: "${IDENTITY_SERVICE_PASSWORD:adminpassword}"
-    base: "${IDENTITY_SERVICE_BASE:dc=dbrepo,dc=at}"
-    adminDn: "${IDENTITY_SERVICE_ADMIN_GROUP:cn=admins,ou=users,dc=dbrepo,dc=at}"
   datasource:
     url: "jdbc:mariadb://${METADATA_HOST:metadata-db}:3306/${METADATA_DB:dbrepo}${METADATA_JDBC_EXTRA_ARGS}"
     driver-class-name: org.mariadb.jdbc.Driver
@@ -68,9 +62,9 @@ dbrepo:
     secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}"
     importBucket: "${S3_IMPORT_BUCKET:dbrepo-upload}"
     exportBucket: "${S3_EXPORT_BUCKET:dbrepo-download}"
-  admin:
-    username: "${ADMIN_USERNAME:admin}"
-    password: "${ADMIN_PASSWORD:admin}"
+  system:
+    username: "${SYSTEM_USERNAME:admin}"
+    password: "${SYSTEM_PASSWORD:admin}"
   endpoints:
     searchService: "${SEARCH_SERVICE_ENDPOINT:http://gateway-service}"
     analyseService: "${ANALYSE_SERVICE_ENDPOINT:http://gateway-service}"
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/RabbitConfig.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/RabbitConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8a83baf85c36852073f120f182f1819280dec67
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/RabbitConfig.java
@@ -0,0 +1,41 @@
+package at.tuwien.config;
+
+import at.tuwien.test.BaseTest;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.http.client.support.BasicAuthenticationInterceptor;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+@Getter
+@Log4j2
+@Configuration
+public class RabbitConfig extends BaseTest {
+
+    @Value("${dbrepo.exchangeName}")
+    private String exchangeName;
+
+    @Value("${dbrepo.queueName}")
+    private String queueName;
+
+    @Value("${spring.rabbitmq.virtual-host}")
+    private String virtualHost;
+
+    @Value("${dbrepo.endpoints.brokerService}")
+    private String brokerEndpoint;
+
+    @Bean
+    @Primary
+    public RestTemplate brokerRestTemplate() {
+        final RestTemplate restTemplate = new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(brokerEndpoint));
+        restTemplate.getInterceptors()
+                .add(new BasicAuthenticationInterceptor(USER_1_USERNAME, USER_1_PASSWORD));
+        return restTemplate;
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7215e5db918f226e6a826fce66e4e129ca4f0c5f
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java
@@ -0,0 +1,41 @@
+package at.tuwien.converters;
+
+import at.tuwien.api.identifier.IdentifierTypeDto;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Log4j2
+@SpringBootTest
+public class IdentifierTypeConverterUnitTest extends AbstractUnitTest {
+
+    @Autowired
+    private IdentifierTypeConverter identifierTypeConverter;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+    }
+
+    @Test
+    public void identifierTypeConverter_succeeds() {
+
+        /* test */
+        final IdentifierTypeDto response = identifierTypeConverter.convert(IdentifierTypeDto.DATABASE.getName());
+        assertEquals(IdentifierTypeDto.DATABASE, response);
+    }
+
+    @Test
+    public void identifierTypeConverter_fails() {
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            identifierTypeConverter.convert("i_do_not_exist");
+        });
+    }
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
index 16c212a546700d3b1ecf8dfc887326764e5e9e5f..69d817afb763fa47b878b71fb315bb8dbb02f750 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
@@ -73,7 +73,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-access"})
-    public void create_succeeds() throws ServiceException, ServiceConnectionException, NotAllowedException,
+    public void create_succeeds() throws DataServiceException, DataServiceConnectionException, NotAllowedException,
             DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -115,12 +115,12 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"admin"})
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"check-foreign-database-access"})
     public void find_hasRoleHasAccessForeign_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, AccessNotFoundException {
 
         /* test */
-        generic_find(DATABASE_1_ID, DATABASE_1, DATABASE_1_USER_1_READ_ACCESS, USER_LOCAL_ADMIN_PRINCIPAL, USER_1_ID, USER_1);
+        generic_find(DATABASE_1_ID, DATABASE_1, DATABASE_1_USER_1_READ_ACCESS, USER_1_PRINCIPAL, USER_1_ID, USER_1);
     }
 
     @Test
@@ -155,7 +155,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
-    public void update_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    public void update_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             AccessNotFoundException, DatabaseNotFoundException, UserNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -190,7 +190,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
-    public void revoke_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    public void revoke_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -208,7 +208,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     /* ################################################################################################### */
 
     protected void generic_create(Principal principal, UUID userId, String username, User user)
-            throws NotAllowedException, ServiceException, ServiceConnectionException, UserNotFoundException,
+            throws NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException,
             DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -269,7 +269,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected void generic_update(DatabaseAccess access, String otherUsername, User otherUser, Principal principal,
-                                  User user) throws NotAllowedException, ServiceException, ServiceConnectionException,
+                                  User user) throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             AccessNotFoundException, UserNotFoundException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -307,8 +307,8 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         assertNull(response.getBody());
     }
 
-    protected void generic_revoke(Principal principal, User user) throws ServiceConnectionException,
-            NotAllowedException, ServiceException, UserNotFoundException, DatabaseNotFoundException,
+    protected void generic_revoke(Principal principal, User user) throws DataServiceConnectionException,
+            NotAllowedException, DataServiceException, UserNotFoundException, DatabaseNotFoundException,
             AccessNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
index cb230377f3fb443c864a35fcc0486cb3ee915769..7706e185bd3721fdddec7daed15ce8df628b0bad 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
@@ -42,7 +42,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     public void findById_anonymous_succeeds() throws ContainerNotFoundException {
 
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, null, false);
+        findById_generic(CONTAINER_1_ID, CONTAINER_1, null);
     }
 
     @Test
@@ -50,7 +50,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     public void findById_hasRole_succeeds() throws ContainerNotFoundException {
 
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL, false);
+        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -58,15 +58,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     public void findById_noRole_succeeds() throws ContainerNotFoundException {
 
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_4_PRINCIPAL, false);
-    }
-
-    @Test
-    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"})
-    public void findById_admin_succeeds() throws ContainerNotFoundException {
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_LOCAL_ADMIN_PRINCIPAL, true);
+        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_4_PRINCIPAL);
     }
 
     @Test
@@ -173,7 +165,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
-    public void findById_generic(Long containerId, Container container, Principal principal, Boolean isAdmin)
+    public void findById_generic(Long containerId, Container container, Principal principal)
             throws ContainerNotFoundException {
 
         /* mock */
@@ -184,15 +176,6 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
         final ResponseEntity<ContainerDto> response = containerEndpoint.findById(containerId, principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
-        if (isAdmin) {
-            assertNotNull(response.getHeaders());
-            final List<String> xUsername = response.getHeaders().get("X-Username");
-            assertNotNull(xUsername);
-            assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, xUsername.get(0));
-            final List<String> xPassword = response.getHeaders().get("X-Password");
-            assertNotNull(xPassword);
-            assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, xPassword.get(0));
-        }
     }
 
     public void delete_generic(Long containerId, Container container) throws ContainerNotFoundException {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
index 7e53274f504ea36838ce1deda16f3390d372e98b..02ba52ecaa930f1747ee55f80cff2ea36379ffc1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
@@ -94,10 +94,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database"})
-    public void create_succeeds() throws ServiceException, ServiceConnectionException, UserNotFoundException,
+    public void create_succeeds() throws DataServiceException, DataServiceConnectionException, UserNotFoundException,
             DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException,
             SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
-            CredentialsInvalidException {
+            CredentialsInvalidException, BrokerServiceException, BrokerServiceConnectionException {
         final DatabaseCreateDto request = DatabaseCreateDto.builder()
                 .cid(CONTAINER_1_ID)
                 .name(DATABASE_1_NAME)
@@ -302,7 +302,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-owner"})
-    public void transfer_hasRole_succeeds() throws ServiceConnectionException, ServiceException,
+    public void transfer_hasRole_succeeds() throws DataServiceConnectionException, DataServiceException,
             NotAllowedException, UserNotFoundException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
             CredentialsInvalidException {
@@ -345,7 +345,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_anonymous_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_anonymous_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ExchangeNotFoundException {
 
         /* test */
@@ -364,7 +364,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_hasRole_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_hasRole_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ExchangeNotFoundException {
 
         /* pre-condition */
@@ -376,7 +376,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_hasRoleForeign_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_hasRoleForeign_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ExchangeNotFoundException {
 
         /* pre-condition */
@@ -388,7 +388,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_ownerSeesAccessRights_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_ownerSeesAccessRights_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ExchangeNotFoundException {
 
         /* mock */
@@ -430,9 +430,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         assertEquals(databases.size(), body.size());
     }
 
-    public void create_generic(DatabaseCreateDto data, Principal principal, User user) throws ServiceException,
-            ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException,
-            SearchServiceException, SearchServiceConnectionException {
+    public void create_generic(DatabaseCreateDto data, Principal principal, User user) throws DataServiceException,
+            DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
+            ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException,
+            BrokerServiceException, BrokerServiceConnectionException {
 
         /* mock */
         doNothing()
@@ -468,7 +469,8 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     }
 
     public DatabaseDto findById_generic(Long databaseId, Database database, Principal principal)
-            throws ServiceException, ServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException {
+            throws DataServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException,
+            DataServiceException {
 
         /* mock */
         if (database != null) {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
index 7a83d2558f92c93eee618a05ec427d11bb4d1b3a..af98f87e571bac44fd2e422848cbfc8e37262ffd 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
@@ -78,8 +78,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_json0_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_json0_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "application/json";
         final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata0.json"), StandardCharsets.UTF_8), IdentifierDto.class);
 
@@ -109,8 +110,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_json1_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_json1_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "application/json";
         final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata1.json"), StandardCharsets.UTF_8), IdentifierDto.class);
 
@@ -160,8 +162,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_csv_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_csv_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/csv";
         final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv")));
         final InputStreamResource mock = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv")));
@@ -182,7 +185,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @Disabled("not testable with xml")
-    public void find_xml0_succeeds() throws IOException, MalformedException, ServiceException, ServiceConnectionException, IdentifierNotFoundException, QueryNotFoundException, FormatNotAvailableException {
+    public void find_xml0_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, IdentifierNotFoundException, QueryNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/xml";
         final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/xml/metadata0.xml")));
 
@@ -200,8 +205,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @Disabled("not testable with xml")
-    public void find_xml1_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_xml1_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/xml";
         final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/xml/metadata1.xml")));
 
@@ -220,8 +226,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliography_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliography_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"),
                 StandardCharsets.UTF_8);
@@ -242,8 +249,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyApa0_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyApa0_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"),
                 StandardCharsets.UTF_8);
@@ -264,8 +272,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyApa1_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyApa1_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"),
                 StandardCharsets.UTF_8);
@@ -286,8 +295,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyApa2_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa2.txt"),
                 StandardCharsets.UTF_8);
@@ -308,8 +318,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyApa3_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyApa3_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa3.txt"),
                 StandardCharsets.UTF_8);
@@ -330,8 +341,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyApa4_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyApa4_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa4.txt"),
                 StandardCharsets.UTF_8);
@@ -352,8 +364,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyIeee0_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyIeee0_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee0.txt"),
                 StandardCharsets.UTF_8);
@@ -374,8 +387,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyIeee1_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyIeee1_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee1.txt"),
                 StandardCharsets.UTF_8);
@@ -396,8 +410,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyIeee2_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyIeee2_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee2.txt"),
                 StandardCharsets.UTF_8);
@@ -418,8 +433,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyIeee3_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyIeee3_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee3.txt"),
                 StandardCharsets.UTF_8);
@@ -440,8 +456,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyBibtex0_succeeds() throws IOException, MalformedException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyBibtex0_succeeds() throws IOException, MalformedException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex0.txt"),
                 StandardCharsets.UTF_8);
@@ -462,8 +479,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyBibtex1_succeeds() throws MalformedException, IOException, ServiceException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyBibtex1_succeeds() throws MalformedException, IOException, DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex1.txt"),
                 StandardCharsets.UTF_8);
@@ -484,8 +502,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyBibtex2_succeeds() throws MalformedException, ServiceException, IOException,
-            ServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+    public void find_bibliographyBibtex2_succeeds() throws MalformedException, DataServiceException, IOException,
+            DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
+            FormatNotAvailableException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex2.txt"),
                 StandardCharsets.UTF_8);
@@ -506,8 +525,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_bibliographyBibtex3_succeeds() throws MalformedException, ServiceException,
-            ServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException,
+    public void find_bibliographyBibtex3_succeeds() throws MalformedException, DataServiceException,
+            DataServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException,
             FormatNotAvailableException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex3.txt"),
@@ -545,9 +564,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-identifier"})
-    public void delete_hasRole_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
-            DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException,
-            SearchServiceConnectionException {
+    public void delete_hasRole_succeeds() throws NotAllowedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, IdentifierNotFoundException,
+            SearchServiceException, SearchServiceConnectionException {
 
         /* test */
         this.generic_delete();
@@ -555,7 +574,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_json_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
+    public void find_json_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException {
         final String accept = "application/json";
 
@@ -582,7 +601,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_xml_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
+    public void find_xml_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
         final InputStreamResource resource = new InputStreamResource(FileUtils.openInputStream(
                 new File("src/test/resources/xml/datacite-example-dataset-v4.xml")));
@@ -598,8 +617,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void find_httpRedirect_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
-            FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException {
+    public void find_httpRedirect_succeeds() throws MalformedException, DataServiceException,
+            DataServiceConnectionException, FormatNotAvailableException, QueryNotFoundException,
+            IdentifierNotFoundException {
 
         /* test */
         final ResponseEntity<?> response = generic_find(null, null);
@@ -611,10 +631,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-identifier"})
-    public void save_hasRoleDatabase_succeeds() throws MalformedException, NotAllowedException, ServiceException,
-            ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
+    public void save_hasRoleDatabase_succeeds() throws MalformedException, NotAllowedException, DataServiceException,
+            DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
             QueryNotFoundException, IdentifierNotFoundException, ViewNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, TableNotFoundException {
+            SearchServiceConnectionException, TableNotFoundException, ExternalServiceException {
 
         /* test */
         generic_save(DATABASE_1_ID, DATABASE_1, DATABASE_1_USER_1_READ_ACCESS, IDENTIFIER_1, IDENTIFIER_1_SAVE_DTO, USER_1_PRINCIPAL, USER_1);
@@ -633,9 +653,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_2_USERNAME, authorities = {"create-identifier"})
     public void save_hasRoleReadAccessQuery_succeeds() throws MalformedException, NotAllowedException,
-            ServiceException, ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
+            DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
             AccessNotFoundException, QueryNotFoundException, IdentifierNotFoundException, ViewNotFoundException,
-            SearchServiceException, SearchServiceConnectionException, TableNotFoundException {
+            SearchServiceException, SearchServiceConnectionException, TableNotFoundException, ExternalServiceException {
 
         /* mock */
         when(dataServiceGateway.findQuery(DATABASE_2_ID, IDENTIFIER_5_QUERY_ID))
@@ -798,10 +818,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     protected void generic_save(Long databaseId, Database database, DatabaseAccess access, Identifier identifier,
                                 IdentifierSaveDto data, Principal principal, User user) throws MalformedException,
-            NotAllowedException, ServiceException, ServiceConnectionException, UserNotFoundException,
+            NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException,
             DatabaseNotFoundException, AccessNotFoundException, QueryNotFoundException,
             IdentifierNotFoundException, ViewNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, TableNotFoundException {
+            SearchServiceConnectionException, TableNotFoundException, ExternalServiceException {
 
         /* mock */
         if (access != null) {
@@ -842,7 +862,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected ResponseEntity<?> generic_find(String accept, InputStreamResource resource)
-            throws MalformedException, ServiceException, ServiceConnectionException, FormatNotAvailableException,
+            throws MalformedException, DataServiceException, DataServiceConnectionException, FormatNotAvailableException,
             QueryNotFoundException, IdentifierNotFoundException {
 
         /* mock */
@@ -863,7 +883,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
     }
 
-    protected void generic_delete() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    protected void generic_delete() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
index b9a67d9911292efaa0234cb9e61d9ea5c778d03f..154ebda86c3a32554c2c83a3330846ebdee8f939 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
@@ -348,7 +348,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_publicAnonymous_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_publicAnonymous_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -367,7 +367,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = "find-table")
-    public void findById_publicHasRoleDatabaseNotFound_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_publicHasRoleDatabaseNotFound_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -376,7 +376,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = "find-table")
-    public void findById_publicHasRole_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_publicHasRole_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -388,7 +388,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_4_USERNAME)
-    public void findById_publicNoRole_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_publicNoRole_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -497,8 +497,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"})
-    public void update_publicHasRoleHasOwnWriteAccess_succeeds() throws MalformedException, ServiceException,
-            NotAllowedException, ServiceConnectionException, UserNotFoundException, TableNotFoundException,
+    public void update_publicHasRoleHasOwnWriteAccess_succeeds() throws MalformedException, DataServiceException,
+            NotAllowedException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException,
             DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
@@ -540,8 +540,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"})
-    public void update_publicHasRoleForeignHasAllWriteAccess_succeeds() throws MalformedException, ServiceException,
-            NotAllowedException, ServiceConnectionException, UserNotFoundException, TableNotFoundException,
+    public void update_publicHasRoleForeignHasAllWriteAccess_succeeds() throws MalformedException, DataServiceException,
+            NotAllowedException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException,
             DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
@@ -601,8 +601,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"})
-    public void update_privateHasRoleHasOwnWriteAccess_succeeds() throws MalformedException, ServiceException,
-            NotAllowedException, ServiceConnectionException, UserNotFoundException, TableNotFoundException,
+    public void update_privateHasRoleHasOwnWriteAccess_succeeds() throws MalformedException, DataServiceException,
+            NotAllowedException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException,
             DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
@@ -644,8 +644,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"})
-    public void update_privateHasRoleForeignHasAllWriteAccess_succeeds() throws MalformedException, ServiceException,
-            NotAllowedException, ServiceConnectionException, UserNotFoundException, TableNotFoundException,
+    public void update_privateHasRoleForeignHasAllWriteAccess_succeeds() throws MalformedException, DataServiceException,
+            NotAllowedException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException,
             DatabaseNotFoundException, AccessNotFoundException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
@@ -731,7 +731,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_privateAnonymous_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_privateAnonymous_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -750,7 +750,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = "find-table")
-    public void findById_privateHasRoleDatabaseNotFound_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_privateHasRoleDatabaseNotFound_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -759,7 +759,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = "find-table")
-    public void findById_privateHasRole_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_privateHasRole_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
         /* test */
         final ResponseEntity<TableDto> response = generic_findById(DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1,
@@ -771,7 +771,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_4_USERNAME)
-    public void findById_privateNoRole_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findById_privateNoRole_succeeds() throws DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, QueueNotFoundException {
 
         /* test */
@@ -790,7 +790,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table"})
-    public void delete_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    public void delete_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -810,9 +810,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-foreign-table"})
-    public void delete_foreign_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    public void delete_foreign_succeeds() throws NotAllowedException, DataServiceConnectionException,
             TableNotFoundException, DatabaseNotFoundException, SearchServiceException,
-            SearchServiceConnectionException {
+            SearchServiceConnectionException, DataServiceException {
 
         /* test */
         generic_delete(USER_2_PRINCIPAL, TABLE_1);
@@ -895,9 +895,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     protected ResponseEntity<TableDto> generic_create(Long databaseId, Database database, TableCreateDto data,
                                                       Principal principal, User user, DatabaseAccess access)
-            throws MalformedException, NotAllowedException, ServiceException, ServiceConnectionException,
+            throws MalformedException, NotAllowedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, TableNotFoundException,
-            TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
+            TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException,
+            SemanticEntityNotFoundException {
 
         /* mock */
         if (principal != null) {
@@ -927,8 +928,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     protected ResponseEntity<TableDto> generic_findById(Long databaseId, Database database, Long tableId,
                                                         Table table, Principal principal, User user,
-                                                        DatabaseAccess access) throws ServiceException,
-            ServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
+                                                        DatabaseAccess access) throws DataServiceException,
+            DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
             QueueNotFoundException {
 
         /* mock */
@@ -964,7 +965,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected ResponseEntity<?> generic_delete(Principal principal, Table table) throws NotAllowedException,
-            ServiceException, ServiceConnectionException, TableNotFoundException, DatabaseNotFoundException,
+            DataServiceException, DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
@@ -978,7 +979,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     protected ResponseEntity<ColumnDto> generic_update(Long databaseId, Database database, Long tableId, Table table,
                                                        Long columnId, TableColumn column, Principal principal,
                                                        User user, ColumnSemanticsUpdateDto data, DatabaseAccess access)
-            throws ServiceException, ServiceConnectionException, MalformedException, NotAllowedException,
+            throws DataServiceException, DataServiceConnectionException, MalformedException, NotAllowedException,
             UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
             SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException,
             SemanticEntityNotFoundException {
@@ -990,7 +991,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
             when(tableService.update(column, data))
                     .thenReturn(column);
         } else {
-            doThrow(ServiceException.class)
+            doThrow(DataServiceException.class)
                     .when(tableService)
                     .update(column, data);
             doThrow(TableNotFoundException.class)
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java
index f21e13711b88b25cdf981f674edaa103c80b7fe6..f5e413e0e9de10192bca89d4fe823db02924712d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java
@@ -216,7 +216,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void password_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    public void password_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, AuthServiceException, AuthServiceConnectionException,
             CredentialsInvalidException {
         final UserPasswordDto request = UserPasswordDto.builder()
@@ -302,7 +302,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected void password_generic(Principal principal, UserPasswordDto data) throws NotAllowedException,
-            ServiceException, ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
+            DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
             AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
index 724d43ca16a94d354c0f5a72a0bbcb3996eb2733..74e418f42b1ca4fc4cbceec451f645ec05c1223d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
@@ -196,8 +196,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-database-view"})
-    public void delete_publicOwner_succeeds() throws NotAllowedException, ServiceException,
-            ServiceConnectionException, ViewNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
+    public void delete_publicOwner_succeeds() throws NotAllowedException, DataServiceException,
+            DataServiceConnectionException, ViewNotFoundException, DatabaseNotFoundException, AccessNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
 
         /* test */
@@ -352,7 +352,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-view"})
-    public void delete_privateOwner_succeeds() throws NotAllowedException, ServiceException, ServiceConnectionException,
+    public void delete_privateOwner_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, AccessNotFoundException, ViewNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -401,8 +401,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected void create_generic(Long databaseId, Database database, Principal principal, UUID userId, User user,
-                                  DatabaseAccess access) throws MalformedException, ServiceException,
-            ServiceConnectionException, NotAllowedException, UserNotFoundException, DatabaseNotFoundException,
+                                  DatabaseAccess access) throws MalformedException, DataServiceException,
+            DataServiceConnectionException, NotAllowedException, UserNotFoundException, DatabaseNotFoundException,
             AccessNotFoundException, SearchServiceException, SearchServiceConnectionException {
         final ViewCreateDto request = ViewCreateDto.builder()
                 .name(VIEW_1_NAME)
@@ -469,7 +469,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
 
     protected void delete_generic(Long databaseId, Database database, Long viewId, View view, Principal principal,
                                   UUID userId, User user, DatabaseAccess access) throws NotAllowedException,
-            ServiceException, ServiceConnectionException, DatabaseNotFoundException, AccessNotFoundException,
+            DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, AccessNotFoundException,
             ViewNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java
index ffa2ff6c1b163d0defbd4d8fa1fe3d608e923309..a812bd5de49af37c5eca041a2fb36653d243dafc 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java
@@ -14,6 +14,7 @@ import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
 
@@ -33,7 +34,8 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
     private BrokerServiceGateway brokerServiceGateway;
 
     @Test
-    public void grantTopicPermission_exchangeNoRightsBefore_succeeds() throws ServiceException, ServiceConnectionException {
+    public void grantTopicPermission_exchangeNoRightsBefore_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.CREATED)
                 .build();
 
@@ -46,7 +48,8 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void grantTopicPermission_exchangeRightsSame_succeeds() throws ServiceException, ServiceConnectionException {
+    public void grantTopicPermission_exchangeRightsSame_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.NO_CONTENT)
                 .build();
 
@@ -68,13 +71,14 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
                 .thenReturn(mock);
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(BrokerServiceException.class, () -> {
             brokerServiceGateway.grantTopicPermission(USER_1_USERNAME, VIRTUAL_HOST_EXCHANGE_UPDATE_DTO);
         });
     }
 
     @Test
-    public void grantVirtualHostPermission_virtualHostNoRightsBefore_succeeds() throws ServiceConnectionException, ServiceException {
+    public void grantVirtualHostPermission_virtualHostNoRightsBefore_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.CREATED)
                 .build();
 
@@ -87,7 +91,8 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void grantVirtualHostPermission_virtualHostRightsSame_succeeds() throws ServiceConnectionException, ServiceException {
+    public void grantVirtualHostPermission_virtualHostRightsSame_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.NO_CONTENT)
                 .build();
 
@@ -109,7 +114,7 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
                 .thenReturn(mock);
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(BrokerServiceException.class, () -> {
             brokerServiceGateway.grantVirtualHostPermission(USER_1_USERNAME, VIRTUAL_HOST_GRANT_DTO);
         });
     }
@@ -123,7 +128,21 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(BrokerServiceException.class, () -> {
+            brokerServiceGateway.grantVirtualHostPermission(USER_1_USERNAME, VIRTUAL_HOST_GRANT_DTO);
+        });
+    }
+
+    @Test
+    public void grantVirtualHostPermission_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(BrokerServiceConnectionException.class, () -> {
             brokerServiceGateway.grantVirtualHostPermission(USER_1_USERNAME, VIRTUAL_HOST_GRANT_DTO);
         });
     }
@@ -137,13 +156,28 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(BrokerServiceException.class, () -> {
             brokerServiceGateway.grantTopicPermission(USER_1_USERNAME, VIRTUAL_HOST_EXCHANGE_UPDATE_DTO);
         });
     }
 
     @Test
-    public void grantExchangePermission_succeeds() throws ServiceConnectionException, ServiceException {
+    public void grantTopicPermission_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(BrokerServiceConnectionException.class, () -> {
+            brokerServiceGateway.grantTopicPermission(USER_1_USERNAME, VIRTUAL_HOST_EXCHANGE_UPDATE_DTO);
+        });
+    }
+
+    @Test
+    public void grantExchangePermission_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.CREATED)
                 .build();
 
@@ -156,7 +190,8 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void grantExchangePermission_exists_succeeds() throws ServiceConnectionException, ServiceException {
+    public void grantExchangePermission_exists_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.NO_CONTENT)
                 .build();
 
@@ -178,7 +213,21 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
                 .thenReturn(mock);
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(BrokerServiceException.class, () -> {
+            brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO);
+        });
+    }
+
+    @Test
+    public void grantExchangePermission_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(BrokerServiceConnectionException.class, () -> {
             brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO);
         });
     }
@@ -192,7 +241,7 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(BrokerServiceException.class, () -> {
             brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO);
         });
     }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java
index 8d056ad48daab05a38308e047bb167df13e94f9c..881f29ed04b9559884fa26ace511a0627984c963 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java
@@ -15,9 +15,11 @@ import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.*;
 
 @Log4j2
@@ -26,7 +28,6 @@ import static org.mockito.Mockito.*;
 public class CrossrefGatewayUnitTest extends AbstractUnitTest {
 
     @MockBean
-    @Qualifier("keycloakRestTemplate")
     private RestTemplate restTemplate;
 
     @Autowired
@@ -45,15 +46,17 @@ public class CrossrefGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findById_fails() throws DoiNotFoundException {
+    public void findById_fails() {
 
         /* mock */
-        doThrow(ResourceAccessException.class)
+        doThrow(HttpServerErrorException.class)
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(CrossrefDto.class));
 
         /* test */
-        crossrefGateway.findById("501100004729");
+        assertThrows(DoiNotFoundException.class, () -> {
+            crossrefGateway.findById("501100004729");
+        });
     }
 
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java
index d8369bb6dabf926d0435320c360872b4724ca53e..8183ea90808ea6c7e48e1530ea2a88a62a34df9b 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java
@@ -1,16 +1,1119 @@
 package at.tuwien.gateway;
 
+import at.tuwien.ExportResourceDto;
+import at.tuwien.api.database.AccessTypeDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.query.QueryDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.database.table.TableStatisticDto;
+import at.tuwien.exception.*;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+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.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestTemplate;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.when;
 
 @Log4j2
 @SpringBootTest
 @ExtendWith(SpringExtension.class)
 public class DataServiceGatewayUnitTest extends AbstractUnitTest {
 
-    // TODO check mapping of databaseService too!!
+    @MockBean
+    @Qualifier("dataServiceRestTemplate")
+    private RestTemplate dataServiceRestTemplate;
+
+    @Autowired
+    private DataServiceGateway dataServiceGateway;
+
+    @Test
+    public void createAccess_succeeds() throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.createAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+    }
+
+    @Test
+    public void createAccess_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.createAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void createAccess_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            dataServiceGateway.createAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void createAccess_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void createAccess_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void updateAccess_succeeds() throws DataServiceException, DataServiceConnectionException, AccessNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.updateAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+    }
+
+    @Test
+    public void updateAccess_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.updateAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void updateAccess_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(AccessNotFoundException.class, () -> {
+            dataServiceGateway.updateAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void updateAccess_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.updateAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void updateAccess_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.updateAccess(DATABASE_1_ID, USER_1_ID, AccessTypeDto.READ);
+        });
+    }
+
+    @Test
+    public void deleteAccess_succeeds() throws DataServiceException, DataServiceConnectionException, AccessNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.deleteAccess(DATABASE_1_ID, USER_1_ID);
+    }
+
+    @Test
+    public void deleteAccess_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.deleteAccess(DATABASE_1_ID, USER_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteAccess_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class));
+
+        /* test */
+        assertThrows(AccessNotFoundException.class, () -> {
+            dataServiceGateway.deleteAccess(DATABASE_1_ID, USER_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteAccess_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.deleteAccess(DATABASE_1_ID, USER_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteAccess_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.deleteAccess(DATABASE_1_ID, USER_1_ID);
+        });
+    }
+
+    @Test
+    public void createDatabase_succeeds() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(DatabaseDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
+                        .body(DATABASE_1_DTO));
+
+        /* test */
+        dataServiceGateway.createDatabase(DATABASE_1_CREATE_INTERNAL);
+    }
+
+    @Test
+    public void createDatabase_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(DatabaseDto.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.createDatabase(DATABASE_1_CREATE_INTERNAL);
+        });
+    }
+
+    @Test
+    public void createDatabase_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(DatabaseDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createDatabase(DATABASE_1_CREATE_INTERNAL);
+        });
+    }
+
+    @Test
+    public void createDatabase_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(DatabaseDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createDatabase(DATABASE_1_CREATE_INTERNAL);
+        });
+    }
+
+    @Test
+    public void createDatabase_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(DatabaseDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createDatabase(DATABASE_1_CREATE_INTERNAL);
+        });
+    }
+
+    @Test
+    public void updateDatabase_succeeds() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.updateDatabase(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+    }
+
+    @Test
+    public void updateDatabase_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.updateDatabase(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+        });
+    }
+
+    @Test
+    public void updateDatabase_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.updateDatabase(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+        });
+    }
+
+    @Test
+    public void updateDatabase_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            dataServiceGateway.updateDatabase(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+        });
+    }
+
+    @Test
+    public void updateDatabase_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.updateDatabase(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+        });
+    }
+
+    @Test
+    public void updateDatabase_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.updateDatabase(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+        });
+    }
+
+    @Test
+    public void createTable_succeeds() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException, TableExistsException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+    }
+
+    @Test
+    public void createTable_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createTable_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createTable_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createTable_exists_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Conflict.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(TableExistsException.class, () -> {
+            dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createTable_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createTable_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createTable(DATABASE_1_ID, TABLE_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void deleteTable_succeeds() throws DataServiceException, DataServiceConnectionException,
+            TableNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.deleteTable(DATABASE_1_ID, TABLE_1_ID);
+    }
+
+    @Test
+    public void deleteTable_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.deleteTable(DATABASE_1_ID, TABLE_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteTable_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.deleteTable(DATABASE_1_ID, TABLE_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteTable_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(TableNotFoundException.class, () -> {
+            dataServiceGateway.deleteTable(DATABASE_1_ID, TABLE_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteTable_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.deleteTable(DATABASE_1_ID, TABLE_1_ID);
+        });
+    }
+
+    @Test
+    public void createView_succeeds() throws DataServiceException, DataServiceConnectionException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(ViewDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
+                        .body(VIEW_1_DTO));
+
+        /* test */
+        dataServiceGateway.createView(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+    }
+
+    @Test
+    public void createView_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(ViewDto.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.createView(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createView_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(ViewDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createView(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createView_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(ViewDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createView(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createView_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(ViewDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createView(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void createView_emptyBody_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(ViewDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.createView(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+        });
+    }
+
+    @Test
+    public void deleteView_succeeds() throws DataServiceException, DataServiceConnectionException,
+            ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED)
+                        .build());
+
+        /* test */
+        dataServiceGateway.deleteView(DATABASE_1_ID, VIEW_1_ID);
+    }
+
+    @Test
+    public void deleteView_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.deleteView(DATABASE_1_ID, VIEW_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteView_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.deleteView(DATABASE_1_ID, VIEW_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteView_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class));
+
+        /* test */
+        assertThrows(ViewNotFoundException.class, () -> {
+            dataServiceGateway.deleteView(DATABASE_1_ID, VIEW_1_ID);
+        });
+    }
+
+    @Test
+    public void deleteView_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), eq(HttpEntity.EMPTY), eq(Void.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.deleteView(DATABASE_1_ID, VIEW_1_ID);
+        });
+    }
+
+    @Test
+    public void findQuery_succeeds() throws DataServiceException, DataServiceConnectionException,
+            QueryNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(QueryDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(QUERY_1_DTO));
+
+        /* test */
+        dataServiceGateway.findQuery(DATABASE_1_ID, QUERY_1_ID);
+    }
+
+    @Test
+    public void findQuery_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(QueryDto.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.findQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void findQuery_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(QueryDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.findQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void findQuery_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(QueryDto.class));
+
+        /* test */
+        assertThrows(QueryNotFoundException.class, () -> {
+            dataServiceGateway.findQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void findQuery_notAcceptable_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotAcceptable.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(QueryDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.findQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void findQuery_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(QueryDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.findQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void exportQuery_succeeds() throws DataServiceException, DataServiceConnectionException,
+            QueryNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .build());
+
+        /* test */
+        dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID);
+    }
+
+    @Test
+    public void exportQuery_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void exportQuery_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void exportQuery_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class));
+
+        /* test */
+        assertThrows(QueryNotFoundException.class, () -> {
+            dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void exportQuery_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID);
+        });
+    }
+
+    @Test
+    public void getTableSchemas_succeeds() throws DataServiceException, DataServiceConnectionException, TableNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto[].class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(new TableDto[]{}));
+
+        /* test */
+        dataServiceGateway.getTableSchemas(DATABASE_1_ID);
+    }
+
+    @Test
+    public void getTableSchemas_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto[].class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.getTableSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getTableSchemas_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto[].class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getTableSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getTableSchemas_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto[].class));
+
+        /* test */
+        assertThrows(TableNotFoundException.class, () -> {
+            dataServiceGateway.getTableSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getTableSchemas_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto[].class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getTableSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getTableSchemas_emptyBody_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto[].class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getTableSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getViewSchemas_succeeds() throws DataServiceException, DataServiceConnectionException,
+            ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto[].class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(new ViewDto[]{}));
+
+        /* test */
+        dataServiceGateway.getViewSchemas(DATABASE_1_ID);
+    }
+
+    @Test
+    public void getViewSchemas_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto[].class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.getViewSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getViewSchemas_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto[].class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getViewSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getViewSchemas_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto[].class));
+
+        /* test */
+        assertThrows(ViewNotFoundException.class, () -> {
+            dataServiceGateway.getViewSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getViewSchemas_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto[].class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getViewSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getViewSchemas_emptyBody_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto[].class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getViewSchemas(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    public void getTableStatistics_succeeds() throws DataServiceException, DataServiceConnectionException,
+            TableNotFoundException {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TABLE_8_STATISTIC_DTO));
+
+        /* test */
+        dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
+    }
+
+    @Test
+    public void getTableStatistics_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class));
+
+        /* test */
+        assertThrows(DataServiceConnectionException.class, () -> {
+            dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
+        });
+    }
+
+    @Test
+    public void getTableStatistics_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class));
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
+        });
+    }
+
+    @Test
+    public void getTableStatistics_notFound_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(dataServiceRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class));
+
+        /* test */
+        assertThrows(TableNotFoundException.class, () -> {
+            dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
+        });
+    }
+
+    @Test
+    public void getTableStatistics_responseCode_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
+        });
+    }
+
+    @Test
+    public void getTableStatistics_emptyBody_fails() {
+
+        /* mock */
+        when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .build());
+
+        /* test */
+        assertThrows(DataServiceException.class, () -> {
+            dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
+        });
+    }
 
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
index 06e75c62fec70377bf0dabb56b11036cedce22a9..f60211d5902972641a8e2473fd5fd76b289ee571 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
@@ -16,12 +16,11 @@ import org.springframework.http.*;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 
 import java.nio.charset.Charset;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 @Log4j2
@@ -31,6 +30,10 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
 
     @MockBean
     @Qualifier("keycloakRestTemplate")
+    private RestTemplate keycloakRestTemplate;
+
+    @MockBean
+    @Qualifier("restTemplate")
     private RestTemplate restTemplate;
 
     @Autowired
@@ -41,7 +44,7 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
             CredentialsInvalidException {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
 
@@ -50,11 +53,11 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void obtainToken_fails() {
+    public void obtainToken_connection_fails() {
 
         /* mock */
-        doThrow(HttpServerErrorException.BadGateway.create(HttpStatus.BAD_GATEWAY, "", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
+        doThrow(HttpServerErrorException.BadGateway.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
 
         /* test */
@@ -63,15 +66,43 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    public void obtainToken_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(CredentialsInvalidException.class, () -> {
+            keycloakGateway.obtainToken();
+        });
+    }
+
+    @Test
+    public void obtainToken_unexpected_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(AuthServiceException.class, () -> {
+            keycloakGateway.obtainToken();
+        });
+    }
+
     @Test
     public void createUser_succeeds() throws UserExistsException, EmailExistsException, AuthServiceException,
             AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
                         .build());
 
@@ -83,10 +114,10 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     public void createUser_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
                         .build());
 
@@ -96,32 +127,15 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
         });
     }
 
-    @Test
-    public void createUser_sameEMail_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.create(HttpStatus.CONFLICT, "same email", new HttpHeaders(), new byte[]{}, null))
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(EmailExistsException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
     @Test
     public void createUser_sameUsername_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.create(HttpStatus.CONFLICT, "same username", new HttpHeaders(), new byte[]{}, null))
-                .when(restTemplate)
+        doThrow(HttpClientErrorException.Conflict.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
 
         /* test */
@@ -131,14 +145,14 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createUser_unexpected_fails() {
+    public void createUser_connection_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.BadGateway.create(HttpStatus.BAD_GATEWAY, "", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
+        doThrow(HttpServerErrorException.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
 
         /* test */
@@ -151,10 +165,10 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     public void deleteUser_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .build());
 
@@ -169,10 +183,10 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
             AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
                         .build());
 
@@ -181,48 +195,48 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void deleteUser_unexpected_fails() {
+    public void deleteUser_notFound_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(ResourceAccessException.class)
-                .when(restTemplate)
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(AuthServiceException.class, () -> {
+        assertThrows(UserNotFoundException.class, () -> {
             keycloakGateway.deleteUser(USER_1_ID);
         });
     }
 
     @Test
-    public void deleteUser_notFound_fails() {
+    public void deleteUser_unexpected_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.NotFound.create(HttpStatus.NOT_FOUND, "", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
+        doThrow(HttpClientErrorException.Conflict.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(UserNotFoundException.class, () -> {
+        assertThrows(AuthServiceException.class, () -> {
             keycloakGateway.deleteUser(USER_1_ID);
         });
     }
 
     @Test
-    public void deleteUser_unexpected2_fails() {
+    public void deleteUser_connection_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.BadGateway.create(HttpStatus.BAD_GATEWAY, "", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
+        doThrow(HttpServerErrorException.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
 
         /* test */
@@ -236,10 +250,10 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
             CredentialsInvalidException {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
                         .build());
 
@@ -251,10 +265,10 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     public void updateUserCredentials_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .build());
 
@@ -265,14 +279,14 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateUserCredentials_unexpected_fails() {
+    public void updateUserCredentials_connection_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.BadGateway.create(HttpStatus.BAD_GATEWAY, "", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
+        doThrow(HttpServerErrorException.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
@@ -281,14 +295,31 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    public void updateUserCredentials_unexpected_fails() {
+
+        /* mock */
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+        doThrow(HttpClientErrorException.Conflict.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(AuthServiceException.class, () -> {
+            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
+        });
+    }
+
     @Test
     public void findByUsername_notFound_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(new UserDto[]{}));
 
@@ -299,18 +330,18 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findByUsername_remote_fails() {
+    public void findByUsername_connection_fails() {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(ResourceAccessException.class)
-                .when(restTemplate)
+        doThrow(HttpServerErrorException.class)
+                .when(keycloakRestTemplate)
                 .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
 
         /* test */
-        assertThrows(AuthServiceException.class, () -> {
+        assertThrows(AuthServiceConnectionException.class, () -> {
             keycloakGateway.findByUsername(USER_1_USERNAME);
         });
     }
@@ -318,17 +349,196 @@ public class KeycloakGatewayUnitTest extends AbstractUnitTest {
     @Test
     public void findByUsername_unexpected_fails() {
 
+        /* mock */
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+        doThrow(HttpClientErrorException.Conflict.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
+
+        /* test */
+        assertThrows(AuthServiceException.class, () -> {
+            keycloakGateway.findByUsername(USER_1_USERNAME);
+        });
+    }
+
+    @Test
+    public void findById_succeeds() throws UserNotFoundException, AuthServiceException, AuthServiceConnectionException,
+            CredentialsInvalidException {
+
+        /* mock */
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(USER_1_KEYCLOAK_DTO));
+
+        /* test */
+        final UserDto response = keycloakGateway.findById(USER_1_ID);
+        assertEquals(USER_1_ID, response.getId());
+    }
+
+    @Test
+    public void findById_notFound_fails() {
+
+        /* mock */
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+        doThrow(HttpClientErrorException.NotFound.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.findById(USER_1_ID);
+        });
+    }
+
+    @Test
+    public void findById_connection_fails() {
+
+        /* mock */
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+        doThrow(HttpServerErrorException.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
+
+        /* test */
+        assertThrows(AuthServiceConnectionException.class, () -> {
+            keycloakGateway.findById(USER_1_ID);
+        });
+    }
+
+    @Test
+    public void findById_unexpected_fails() {
+
+        /* mock */
+        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+        doThrow(HttpClientErrorException.Conflict.class)
+                .when(keycloakRestTemplate)
+                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
+
+        /* test */
+        assertThrows(AuthServiceException.class, () -> {
+            keycloakGateway.findById(USER_1_ID);
+        });
+    }
+
+    @Test
+    public void refreshUserToken_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
+
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.BadGateway.create(HttpStatus.BAD_GATEWAY, "", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
+
+        /* test */
+        final TokenDto response = keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
+        assertNotNull(response.getAccessToken());
+    }
+
+    @Test
+    public void refreshUserToken_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
                 .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
 
         /* test */
         assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
+            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
+        });
+    }
+
+    @Test
+    public void refreshUserToken_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(CredentialsInvalidException.class, () -> {
+            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
+        });
+    }
+
+    @Test
+    public void refreshUserToken_badRequest_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(CredentialsInvalidException.class, () -> {
+            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
+        });
+    }
+
+    @Test
+    public void refreshUserToken_badRequestInactiveSession_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.BadRequest.create(HttpStatus.BAD_REQUEST, "Session not active", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(CredentialsInvalidException.class, () -> {
+            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
+        });
+    }
+
+    @Test
+    public void obtainUserToken_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException,
+            AccountNotSetupException {
+
+        /* mock */
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(TOKEN_DTO));
+
+        /* test */
+        final TokenDto response = keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
+        assertNotNull(response.getAccessToken());
+    }
+
+    @Test
+    public void obtainUserToken_connection_fails() {
+
+        /* mock */
+        doThrow(HttpServerErrorException.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(AuthServiceConnectionException.class, () -> {
+            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
+        });
+    }
+
+    @Test
+    public void obtainUserToken_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
+
+        /* test */
+        assertThrows(CredentialsInvalidException.class, () -> {
+            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
         });
     }
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java
index 4572711ed228bf6007d79ced93100663e05e2b07..bcd27107bc0189614b4086e0b333fa16cf16cb84 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java
@@ -15,9 +15,11 @@ import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.*;
 
 @Log4j2
@@ -26,7 +28,6 @@ import static org.mockito.Mockito.*;
 public class OrcidGatewayUnitTest extends AbstractUnitTest {
 
     @MockBean
-    @Qualifier("keycloakRestTemplate")
     private RestTemplate restTemplate;
 
     @Autowired
@@ -45,15 +46,17 @@ public class OrcidGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findByUrl_fails() throws OrcidNotFoundException {
+    public void findByUrl_fails() {
 
         /* mock */
-        doThrow(ResourceAccessException.class)
+        doThrow(HttpServerErrorException.class)
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(OrcidDto.class));
 
         /* test */
-        orcidGateway.findByUrl(USER_1_ORCID_URL);
+        assertThrows(OrcidNotFoundException.class, () -> {
+            orcidGateway.findByUrl(USER_1_ORCID_URL);
+        });
     }
 
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java
index 384cd290b36e6696bd14c4a6d74cb88838729d5c..ff9d4f741c18b2dfcd94dca91c344912fddd2167 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java
@@ -7,14 +7,14 @@ import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
-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.http.*;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.web.client.ResourceAccessException;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestTemplate;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.*;
 
 @Log4j2
@@ -23,7 +23,6 @@ import static org.mockito.Mockito.*;
 public class RorGatewayUnitTest extends AbstractUnitTest {
 
     @MockBean
-    @Qualifier("keycloakRestTemplate")
     private RestTemplate restTemplate;
 
     @Autowired
@@ -42,15 +41,17 @@ public class RorGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void findById_fails() throws RorNotFoundException {
+    public void findById_fails() {
 
         /* mock */
-        doThrow(ResourceAccessException.class)
+        doThrow(HttpServerErrorException.class)
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(RorDto.class));
 
         /* test */
-        rorGateway.findById("04d836q62");
+        assertThrows(RorNotFoundException.class, () -> {
+            rorGateway.findById("04d836q62");
+        });
     }
 
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java
index b4b205d4f49ceee118774909ea8f568a23deff3b..aa1c9d4f056f61680aeb341f2cebafdbe262a2b5 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java
@@ -135,6 +135,20 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    public void delete_unauthorized_fails() {
+
+        /* mock */
+        doThrow(HttpClientErrorException.Unauthorized.class)
+                .when(restTemplate)
+                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
+
+        /* test */
+        assertThrows(SearchServiceException.class, () -> {
+            searchServiceGateway.delete(DATABASE_1_ID);
+        });
+    }
+
     @Test
     public void delete_unexpectedResponse_fails() {
         final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.OK)
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
index 732c11124f38fc0bbf2338a93f6d33d04b14d38f..8a72f2cabbe0f4eda33ff77ef125eed2c842e12d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
@@ -15,9 +15,7 @@ import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.database.Database;
-import at.tuwien.entities.database.table.Table;
-import at.tuwien.entities.identifier.Identifier;
-import at.tuwien.entities.identifier.IdentifierType;
+import at.tuwien.entities.identifier.*;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -104,12 +102,42 @@ public class MetadataMapperUnitTest extends AbstractUnitTest {
 
         /* test */
         final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_DTO);
-        assertNull(response.getDatabase());
-        assertNull(response.getViewId());
-        assertNull(response.getQueryId());
-        assertNull(response.getTableId());
-        assertNull(response.getDoi());
-        assertEquals(IDENTIFIER_1_TYPE, response.getType());
+        assertNotNull(response.getTitles());
+        final List<IdentifierTitle> titles = response.getTitles();
+        assertEquals(2, titles.size());
+        final IdentifierTitle title0 = titles.get(0);
+        assertEquals(IDENTIFIER_1_TITLE_1_TITLE, title0.getTitle());
+        assertEquals(IDENTIFIER_1_TITLE_1_LANG, title0.getLanguage());
+        assertEquals(IDENTIFIER_1_TITLE_1_TYPE, title0.getTitleType());
+        final IdentifierTitle title1 = titles.get(1);
+        assertEquals(IDENTIFIER_1_TITLE_2_TITLE, title1.getTitle());
+        assertEquals(IDENTIFIER_1_TITLE_2_LANG, title1.getLanguage());
+        assertEquals(IDENTIFIER_1_TITLE_2_TYPE, title1.getTitleType());
+        assertNotNull(response.getDescriptions());
+        assertEquals(1, response.getDescriptions().size());
+        final List<IdentifierDescription> descriptions = response.getDescriptions();
+        final IdentifierDescription description0 = descriptions.get(0);
+        assertNull(description0.getId());
+        assertEquals(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION, description0.getDescription());
+        assertEquals(IDENTIFIER_1_DESCRIPTION_1_LANG, description0.getLanguage());
+        assertEquals(IDENTIFIER_1_DESCRIPTION_1_TYPE, description0.getDescriptionType());
+        assertNotNull(response.getCreators());
+        assertEquals(1, response.getCreators().size());
+        final Creator creator0 = response.getCreators().get(0);
+        assertNotNull(creator0);
+        assertNull(creator0.getId());
+        assertEquals(IDENTIFIER_1_CREATOR_1_FIRSTNAME, creator0.getFirstname());
+        assertEquals(IDENTIFIER_1_CREATOR_1_LASTNAME, creator0.getLastname());
+        assertEquals(IDENTIFIER_1_CREATOR_1_NAME, creator0.getCreatorName());
+        assertEquals(IDENTIFIER_1_CREATOR_1_ORCID, creator0.getNameIdentifier());
+        assertEquals(IDENTIFIER_1_CREATOR_1_IDENTIFIER_SCHEME_TYPE, creator0.getNameIdentifierScheme());
+        assertEquals(IDENTIFIER_1_CREATOR_1_AFFILIATION, creator0.getAffiliation());
+        assertEquals(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER, creator0.getAffiliationIdentifier());
+        assertEquals(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME, creator0.getAffiliationIdentifierScheme());
+        assertEquals(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI, creator0.getAffiliationIdentifierSchemeUri());
+        assertNotNull(response.getFunders());
+        assertEquals(1, response.getFunders().size());
+        assertNull(response.getRelatedIdentifiers()); /* mapstruct strategy for empty values is to set null */
     }
 
     @Test
@@ -154,6 +182,8 @@ public class MetadataMapperUnitTest extends AbstractUnitTest {
     @Test
     public void customDatabaseToDatabaseDto_succeeds() {
 
+        final Database debug = DATABASE_1;
+
         /* test */
         final DatabaseDto response = metadataMapper.customDatabaseToDatabaseDto(DATABASE_1);
         assertEquals(DATABASE_1_ID, response.getId());
@@ -193,7 +223,9 @@ public class MetadataMapperUnitTest extends AbstractUnitTest {
         assertEquals(TABLE_1_DESCRIPTION, table0.getDescription());
         assertEquals(DATABASE_1_ID, table0.getTdbid());
         assertEquals(USER_1_ID, table0.getCreatedBy());
+        assertNotNull(table0.getOwner());
         assertEquals(USER_1_ID, table0.getOwner().getId());
+        assertNotNull(table0.getCreator());
         assertEquals(USER_1_ID, table0.getCreator().getId());
         assertEquals(TABLE_1_AVG_ROW_LENGTH, table0.getAvgRowLength());
         assertEquals(TABLE_1_NUM_ROWS, table0.getNumRows());
@@ -244,7 +276,9 @@ public class MetadataMapperUnitTest extends AbstractUnitTest {
         assertEquals(TABLE_2_DESCRIPTION, table1.getDescription());
         assertEquals(DATABASE_1_ID, table1.getTdbid());
         assertEquals(USER_2_ID, table1.getCreatedBy());
+        assertNotNull(table1.getOwner());
         assertEquals(USER_2_ID, table1.getOwner().getId());
+        assertNotNull(table1.getCreator());
         assertEquals(USER_2_ID, table1.getCreator().getId());
         assertEquals(TABLE_2_AVG_ROW_LENGTH, table1.getAvgRowLength());
         assertEquals(TABLE_2_NUM_ROWS, table1.getNumRows());
@@ -316,7 +350,9 @@ public class MetadataMapperUnitTest extends AbstractUnitTest {
         assertEquals(TABLE_3_DESCRIPTION, table2.getDescription());
         assertEquals(DATABASE_1_ID, table2.getTdbid());
         assertEquals(USER_3_ID, table2.getCreatedBy());
+        assertNotNull(table2.getOwner());
         assertEquals(USER_3_ID, table2.getOwner().getId());
+        assertNotNull(table2.getCreator());
         assertEquals(USER_3_ID, table2.getCreator().getId());
         assertEquals(TABLE_3_AVG_ROW_LENGTH, table2.getAvgRowLength());
         assertEquals(TABLE_3_NUM_ROWS, table2.getNumRows());
@@ -359,7 +395,9 @@ public class MetadataMapperUnitTest extends AbstractUnitTest {
         assertEquals(TABLE_4_DESCRIPTION, table3.getDescription());
         assertEquals(DATABASE_1_ID, table3.getTdbid());
         assertEquals(USER_1_ID, table3.getCreatedBy());
+        assertNotNull(table3.getOwner());
         assertEquals(USER_1_ID, table3.getOwner().getId());
+        assertNotNull(table3.getCreator());
         assertEquals(USER_1_ID, table3.getCreator().getId());
         assertEquals(TABLE_4_AVG_ROW_LENGTH, table3.getAvgRowLength());
         assertEquals(TABLE_4_NUM_ROWS, table3.getNumRows());
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1ca4ab2f2bb168a77051a269c6a3ef79fd9d63b
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationIntegrationTest.java
@@ -0,0 +1,293 @@
+package at.tuwien.mvc;
+
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.CredentialsInvalidException;
+import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.repository.ContainerRepository;
+import at.tuwien.repository.DatabaseRepository;
+import at.tuwien.repository.LicenseRepository;
+import at.tuwien.repository.UserRepository;
+import at.tuwien.test.AbstractUnitTest;
+import at.tuwien.utils.KeycloakUtils;
+import dasniko.testcontainers.keycloak.KeycloakContainer;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.testcontainers.images.PullPolicy;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.util.List;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@Testcontainers
+@SpringBootTest
+public class AuthenticationIntegrationTest extends AbstractUnitTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Autowired
+    private KeycloakUtils keycloakUtils;
+
+    @Autowired
+    private KeycloakGateway keycloakGateway;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private LicenseRepository licenseRepository;
+
+    @Autowired
+    private ContainerRepository containerRepository;
+
+    @Autowired
+    private DatabaseRepository databaseRepository;
+
+    @Container
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:21.0")
+            .withImagePullPolicy(PullPolicy.alwaysPull())
+            .withAdminUsername("admin")
+            .withAdminPassword("admin")
+            .withRealmImportFile("./init/dbrepo-realm.json")
+            .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false");
+
+    @DynamicPropertySource
+    static void keycloakProperties(DynamicPropertyRegistry registry) {
+        registry.add("dbrepo.endpoints.authService", () -> "http://localhost:" + keycloakContainer.getMappedPort(8080));
+    }
+
+    @BeforeEach
+    public void beforeEach() throws AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
+        genesis();
+        /* metadata database */
+        licenseRepository.save(LICENSE_1);
+        containerRepository.save(CONTAINER_1);
+        userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4));
+        databaseRepository.save(DATABASE_1);
+        /* keycloak */
+        keycloakUtils.deleteUser(USER_1_USERNAME);
+    }
+
+    @Test
+    public void findById_database_basicUser_fails() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().doesNotExist("X-Username"))
+                .andExpect(header().doesNotExist("X-Password"))
+                .andExpect(header().doesNotExist("Access-Control-Expose-Headers"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_database_basicAdmin_succeeds() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SYSTEM_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    @WithMockUser(username = "admin", authorities = {"system"})
+    public void findById_database_bearerAdmin_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1"))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_table_basicUser_fails() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().doesNotExist("X-Username"))
+                .andExpect(header().doesNotExist("X-Password"))
+                .andExpect(header().doesNotExist("X-Host"))
+                .andExpect(header().doesNotExist("X-Port"))
+                .andExpect(header().doesNotExist("X-Type"))
+                .andExpect(header().doesNotExist("X-Database"))
+                .andExpect(header().doesNotExist("X-Sidecar-Host"))
+                .andExpect(header().doesNotExist("X-Sidecar-Port"))
+                .andExpect(header().doesNotExist("Access-Control-Expose-Headers"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_table_basicAdmin_succeeds() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SYSTEM_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
+                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
+                .andExpect(header().string("X-Type", IMAGE_1_JDBC))
+                .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME))
+                .andExpect(header().string("X-Sidecar-Host", CONTAINER_1_SIDECAR_HOST))
+                .andExpect(header().string("X-Sidecar-Port", "" + CONTAINER_1_SIDECAR_PORT))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Sidecar-Host X-Sidecar-Port"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    @WithMockUser(username = "admin", authorities = {"system"})
+    public void findById_table_bearerAdmin_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1/table/1"))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
+                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
+                .andExpect(header().string("X-Type", IMAGE_1_JDBC))
+                .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME))
+                .andExpect(header().string("X-Sidecar-Host", CONTAINER_1_SIDECAR_HOST))
+                .andExpect(header().string("X-Sidecar-Port", "" + CONTAINER_1_SIDECAR_PORT))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Sidecar-Host X-Sidecar-Port"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_view_basicUser_fails() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1/view/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().doesNotExist("X-Username"))
+                .andExpect(header().doesNotExist("X-Password"))
+                .andExpect(header().doesNotExist("X-Host"))
+                .andExpect(header().doesNotExist("X-Port"))
+                .andExpect(header().doesNotExist("X-Type"))
+                .andExpect(header().doesNotExist("X-Database"))
+                .andExpect(header().doesNotExist("Access-Control-Expose-Headers"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_view_basicAdmin_succeeds() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SYSTEM_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1/view/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
+                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
+                .andExpect(header().string("X-Type", IMAGE_1_JDBC))
+                .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    @WithMockUser(username = "admin", authorities = {"system"})
+    public void findById_view_bearerAdmin_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/api/database/1/view/1"))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
+                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
+                .andExpect(header().string("X-Type", IMAGE_1_JDBC))
+                .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_container_basicUser_fails() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/container/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().doesNotExist("X-Username"))
+                .andExpect(header().doesNotExist("X-Password"))
+                .andExpect(header().doesNotExist("Access-Control-Expose-Headers"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void findById_container_basicAdmin_succeeds() throws Exception {
+
+        /* mock */
+        keycloakGateway.createUser(USER_1_KEYCLOAK_SYSTEM_SIGNUP_REQUEST);
+
+        /* test */
+        this.mockMvc.perform(get("/api/container/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    @WithMockUser(username = "admin", authorities = {"system"})
+    public void findById_container_bearerAdmin_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/api/container/1"))
+                .andDo(print())
+                .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
+                .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
+                .andExpect(status().isOk());
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
index 2b2df73909dfa67fe416d279f864b580f6a776b2..d3f75d70602ffb2dad2a6b2adc8797eb7636135c 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
@@ -500,7 +500,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-table", "delete-table",
-            "modify-table-column-semantics", "modify-foreign-table-column-semantics", "admin",
+            "modify-table-column-semantics", "modify-foreign-table-column-semantics", "update-table-statistic",
             "table-semantic-analyse"})
     public void prometheusTableEndpoint_succeeds() {
         final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
index 75a08540b0cae6f9528a25b3c6c855bff9358991..fa939b0cb1795b08257b743ddb239bd075871cf0 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
@@ -73,7 +73,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws ServiceException, ServiceConnectionException,
+    public void create_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
@@ -99,7 +99,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             accessService.create(DATABASE_1, USER_1, AccessTypeDto.WRITE_ALL);
         });
     }
@@ -113,7 +113,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             accessService.create(DATABASE_1, USER_1, AccessTypeDto.WRITE_ALL);
         });
     }
@@ -141,7 +141,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceConnectionException.class, () -> {
+        assertThrows(DataServiceConnectionException.class, () -> {
             accessService.create(DATABASE_1, USER_1, AccessTypeDto.WRITE_ALL);
         });
     }
@@ -223,7 +223,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void update_succeeds() throws ServiceException, ServiceConnectionException, AccessNotFoundException,
+    public void update_succeeds() throws DataServiceException, DataServiceConnectionException, AccessNotFoundException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
@@ -249,7 +249,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             accessService.update(DATABASE_1, USER_1, AccessTypeDto.WRITE_ALL);
         });
     }
@@ -263,7 +263,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             accessService.update(DATABASE_1, USER_1, AccessTypeDto.WRITE_ALL);
         });
     }
@@ -291,7 +291,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceConnectionException.class, () -> {
+        assertThrows(DataServiceConnectionException.class, () -> {
             accessService.update(DATABASE_1, USER_1, AccessTypeDto.WRITE_ALL);
         });
     }
@@ -373,7 +373,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_succeeds() throws ServiceException, ServiceConnectionException, AccessNotFoundException,
+    public void delete_succeeds() throws DataServiceException, DataServiceConnectionException, AccessNotFoundException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
@@ -401,7 +401,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             accessService.delete(DATABASE_1, USER_1);
         });
     }
@@ -429,7 +429,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                 .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
 
         /* test */
-        assertThrows(ServiceConnectionException.class, () -> {
+        assertThrows(DataServiceConnectionException.class, () -> {
             accessService.delete(DATABASE_1, USER_1);
         });
     }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
index ba560f0e47ff2426f2bb3623048a03f5f6c58d13..8b7be04cb6b4c2b383e54c02c18966855eeeca25 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
@@ -64,8 +64,8 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws EmailExistsException, UserExistsException, ServiceException,
-            ServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
+    public void create_succeeds() throws EmailExistsException, UserExistsException,
+            DataServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
             CredentialsInvalidException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java
index a340e293452b135d8d37b8bd212ea3ee425cbd60..c9a2ad62b61d324934236c885bf6be2aca586e9e 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java
@@ -1,15 +1,13 @@
 package at.tuwien.service;
 
 import at.tuwien.config.RabbitConfig;
+import at.tuwien.exception.*;
 import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.api.amqp.GrantExchangePermissionsDto;
 import at.tuwien.api.amqp.TopicPermissionDto;
 import at.tuwien.api.amqp.VirtualHostPermissionDto;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.ServiceConnectionException;
-import at.tuwien.exception.ServiceException;
-import at.tuwien.repository.*;
 import at.tuwien.utils.AmqpUtils;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -44,9 +42,6 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     @Autowired
     private BrokerService brokerService;
 
-    @Autowired
-    private AmqpUtils amqpUtils;
-
     @Container
     private static final RabbitMQContainer rabbitContainer = new RabbitMQContainer("rabbitmq:3-management")
             .withUser(USER_1_USERNAME, USER_1_PASSWORD, Set.of("administrator"))
@@ -55,10 +50,6 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     @DynamicPropertySource
     static void rabbitProperties(DynamicPropertyRegistry registry) {
         registry.add("dbrepo.endpoints.brokerService", rabbitContainer::getHttpUrl);
-        registry.add("spring.rabbitmq.host", rabbitContainer::getHost);
-        registry.add("spring.rabbitmq.port", rabbitContainer::getAmqpPort);
-        registry.add("spring.rabbitmq.username", rabbitContainer::getAdminUsername);
-        registry.add("spring.rabbitmq.password", rabbitContainer::getAdminPassword);
     }
 
     @BeforeEach
@@ -67,7 +58,7 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePermissions_empty_succeeds() throws ServiceException, ServiceConnectionException {
+    public void updatePermissions_empty_succeeds() throws BrokerServiceException, BrokerServiceConnectionException {
 
         /* test */
         final VirtualHostPermissionDto permissions = setVirtualHostPermissions_generic();
@@ -79,7 +70,7 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePermissions_writeAll_succeeds() throws ServiceException, ServiceConnectionException {
+    public void updatePermissions_writeAll_succeeds() throws BrokerServiceException, BrokerServiceConnectionException {
 
         /* test */
         final VirtualHostPermissionDto permissions = setVirtualHostPermissions_generic();
@@ -91,7 +82,7 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePermissions_writeOwn_succeeds() throws ServiceException, ServiceConnectionException {
+    public void updatePermissions_writeOwn_succeeds() throws BrokerServiceException, BrokerServiceConnectionException {
 
         /* test */
         final VirtualHostPermissionDto permissions = setVirtualHostPermissions_generic();
@@ -103,7 +94,7 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePermissions_read_succeeds() throws ServiceException, ServiceConnectionException {
+    public void updatePermissions_read_succeeds() throws BrokerServiceException, BrokerServiceConnectionException {
 
         /* test */
         final VirtualHostPermissionDto permissions = setVirtualHostPermissions_generic();
@@ -116,7 +107,8 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     @Transactional(readOnly = true)
-    public void setTopicExchangePermissions_empty_succeeds() throws ServiceException, ServiceConnectionException {
+    public void setTopicExchangePermissions_empty_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
 
         /* test */
         final TopicPermissionDto permissions = setTopicExchangePermissions_generic(List.of());
@@ -129,7 +121,8 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     @Transactional(readOnly = true)
-    public void setTopicExchangePermissions_writeAll_succeeds() throws ServiceException, ServiceConnectionException {
+    public void setTopicExchangePermissions_writeAll_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
 
         /* test */
         final TopicPermissionDto permissions = setTopicExchangePermissions_generic(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS));
@@ -142,7 +135,8 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     @Transactional(readOnly = true)
-    public void setTopicExchangePermissions_writeOwn_succeeds() throws ServiceException, ServiceConnectionException {
+    public void setTopicExchangePermissions_writeOwn_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
 
         /* test */
         final TopicPermissionDto permissions = setTopicExchangePermissions_generic(List.of(DATABASE_1_USER_1_WRITE_OWN_ACCESS));
@@ -155,7 +149,8 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
 
     @Test
     @Transactional(readOnly = true)
-    public void setTopicExchangePermissions_read_succeeds() throws ServiceException, ServiceConnectionException {
+    public void setTopicExchangePermissions_read_succeeds() throws BrokerServiceException,
+            BrokerServiceConnectionException {
 
         /* test */
         final TopicPermissionDto permissions = setTopicExchangePermissions_generic(List.of(DATABASE_1_USER_1_READ_ACCESS));
@@ -170,8 +165,9 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
-    protected VirtualHostPermissionDto setVirtualHostPermissions_generic() throws ServiceException,
-            ServiceConnectionException {
+    protected VirtualHostPermissionDto setVirtualHostPermissions_generic() throws BrokerServiceException,
+            BrokerServiceConnectionException {
+        final AmqpUtils amqpUtils = new AmqpUtils(rabbitContainer.getHttpUrl());
 
         /* mock */
         amqpUtils.setVirtualHostPermissions(REALM_DBREPO_NAME, USER_1_USERNAME, USER_1_RABBITMQ_GRANT_DTO);
@@ -183,13 +179,14 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
 
     @Transactional(readOnly = true)
     protected TopicPermissionDto setTopicExchangePermissions_generic(List<DatabaseAccess> accesses)
-            throws ServiceException, ServiceConnectionException {
+            throws BrokerServiceException, BrokerServiceConnectionException {
+        final AmqpUtils amqpUtils = new AmqpUtils(rabbitContainer.getHttpUrl());
         final GrantExchangePermissionsDto request = GrantExchangePermissionsDto.builder()
                 .exchange(rabbitConfig.getExchangeName())
                 .read("")
                 .write("")
                 .build();
-        final User user1 = User.builder()
+        final User user = User.builder()
                 .id(USER_1_ID)
                 .username(USER_1_USERNAME)
                 .accesses(accesses)
@@ -200,7 +197,7 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest {
         amqpUtils.setTopicPermissions(REALM_DBREPO_NAME, USER_1_USERNAME, request);
 
         /* test */
-        brokerService.setTopicExchangePermissions(user1);
+        brokerService.setTopicExchangePermissions(user);
         return amqpUtils.getTopicPermissions(USER_1_USERNAME);
     }
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java
index 164f335eb73f68c986583da9881b743a32c44a06..7cec5e624187fcb5c5285fc4fc0b4787b6a4e9a0 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java
@@ -6,6 +6,7 @@ import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.entities.database.table.columns.TableColumnConcept;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java
index 7443439608dbf6c353a5873c42aafcf9368b3db2..0c0cf075c4d83645a7df6bae035cbae4d458ad1e 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java
@@ -1,6 +1,10 @@
 package at.tuwien.service;
 
+import at.tuwien.api.identifier.BibliographyTypeDto;
+import at.tuwien.entities.identifier.Creator;
 import at.tuwien.entities.identifier.Identifier;
+import at.tuwien.entities.identifier.IdentifierStatusType;
+import at.tuwien.entities.identifier.NameIdentifierSchemeType;
 import at.tuwien.repository.ContainerRepository;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.repository.LicenseRepository;
@@ -19,6 +23,7 @@ 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.core.ParameterizedTypeReference;
+import org.springframework.core.io.InputStreamResource;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
@@ -38,7 +43,7 @@ import static org.mockito.Mockito.when;
 
 @ExtendWith(SpringExtension.class)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
-@SpringBootTest(properties = "spring.profiles.active:local,doi")
+@SpringBootTest(properties = "spring.profiles.active:local,junit,doi")
 public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
 
     @MockBean
@@ -71,15 +76,62 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
         genesis();
         /* metadata database */
         licenseRepository.save(LICENSE_1);
-        containerRepository.save(CONTAINER_1);
-        userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4));
-        databaseRepository.save(DATABASE_1);
+        containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4));
+        userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5));
+        databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3, DATABASE_4));
     }
 
     @Test
-    public void save_database_succeeds() throws ServiceException, ServiceConnectionException,
+    public void findAll_succeeds() {
+
+        /* test */
+        final List<Identifier> response = dataCiteIdentifierService.findAll(null, null, null, null, null);
+        assertEquals(7, response.size());
+        for (Long id : List.of(IDENTIFIER_1_ID, IDENTIFIER_2_ID, IDENTIFIER_3_ID, IDENTIFIER_4_ID, IDENTIFIER_5_ID, IDENTIFIER_6_ID, IDENTIFIER_7_ID)) {
+            assertTrue(response.stream().map(Identifier::getId).toList().contains(id));
+        }
+    }
+
+    @Test
+    public void findAll_databaseId_succeeds() {
+
+        /* test */
+        final List<Identifier> response = dataCiteIdentifierService.findAll(null, DATABASE_1_ID, null, null, null);
+        assertEquals(4, response.size());
+        assertTrue(response.stream().map(Identifier::getId).toList().contains(IDENTIFIER_1_ID));
+        assertTrue(response.stream().map(Identifier::getId).toList().contains(IDENTIFIER_2_ID));
+        assertTrue(response.stream().map(Identifier::getId).toList().contains(IDENTIFIER_3_ID));
+        assertTrue(response.stream().map(Identifier::getId).toList().contains(IDENTIFIER_4_ID));
+    }
+
+    @Test
+    public void findAll_queryId_succeeds() {
+
+        /* test */
+        final List<Identifier> response = dataCiteIdentifierService.findAll(null, null, QUERY_1_ID, null, null);
+        assertEquals(1, response.size());
+    }
+
+    @Test
+    public void findAll_empty_succeeds() {
+
+        /* test */
+        final List<Identifier> response = dataCiteIdentifierService.findAll(null, DATABASE_2_ID, QUERY_1_ID, null, null);
+        assertEquals(0, response.size());
+    }
+
+    @Test
+    public void find_succeeds() throws IdentifierNotFoundException {
+
+        /* test */
+        final Identifier response = dataCiteIdentifierService.find(IDENTIFIER_1_ID);
+        assertEquals(IDENTIFIER_1, response);
+    }
+
+    @Test
+    public void save_database_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, MalformedException, IdentifierNotFoundException, ViewNotFoundException,
-            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException {
+            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException {
         final ResponseEntity<DataCiteBody<DataCiteDoi>> mock = ResponseEntity.status(HttpStatus.CREATED)
                 .body(IDENTIFIER_1_DATA_CITE);
 
@@ -122,15 +174,16 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_DTO);
 
         /* test */
-        assertThrows(ServiceConnectionException.class, () -> {
+        assertThrows(DataServiceConnectionException.class, () -> {
             dataCiteIdentifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_DTO);
         });
     }
 
     @Test
-    public void create_succeeds() throws SearchServiceException, MalformedException, ServiceException,
-            QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
-            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
+    public void create_succeeds() throws SearchServiceException, MalformedException, DataServiceException,
+            QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
+            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException,
+            ExternalServiceException {
         final ResponseEntity<DataCiteBody<DataCiteDoi>> mock = ResponseEntity.status(HttpStatus.CREATED)
                 .body(IDENTIFIER_1_DATA_CITE);
 
@@ -144,9 +197,10 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_hasDoi_succeeds() throws SearchServiceException, MalformedException, ServiceException,
-            QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
-            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
+    public void create_hasDoi_succeeds() throws SearchServiceException, MalformedException, DataServiceException,
+            QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
+            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException,
+            ExternalServiceException {
         final ResponseEntity<DataCiteBody<DataCiteDoi>> mock = ResponseEntity.status(HttpStatus.CREATED)
                 .body(IDENTIFIER_1_DATA_CITE);
 
@@ -159,4 +213,128 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
         assertEquals(IDENTIFIER_1_DOI_NOT_NULL, response.getDoi());
     }
 
+    @Test
+    public void publish_succeeds() throws MalformedException, DataServiceConnectionException, SearchServiceException,
+            DatabaseNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException,
+            ExternalServiceException {
+        final ResponseEntity<DataCiteBody<DataCiteDoi>> mock = ResponseEntity.status(HttpStatus.CREATED)
+                .body(IDENTIFIER_7_DATA_CITE);
+
+        /* mock */
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)))
+                .thenReturn(mock);
+
+        /* test */
+        final Identifier response = dataCiteIdentifierService.publish(IDENTIFIER_7_ID);
+        assertEquals(IDENTIFIER_7_ID, response.getId());
+        assertEquals(IdentifierStatusType.PUBLISHED, response.getStatus());
+    }
+
+    @Test
+    public void exportMetadata_succeeds() {
+
+        /* test */
+        final InputStreamResource response = dataCiteIdentifierService.exportMetadata(IDENTIFIER_1);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void exportBibliography_apa_succeeds() throws MalformedException {
+
+        /* test */
+        final String response = dataCiteIdentifierService.exportBibliography(IDENTIFIER_1, BibliographyTypeDto.APA);
+        assertTrue(response.contains(IDENTIFIER_1_TITLE_1.getTitle()));
+        assertTrue(response.contains("" + IDENTIFIER_1_PUBLICATION_YEAR));
+        assertTrue(response.contains(IDENTIFIER_1_CREATOR_1.getLastname()));
+    }
+
+    @Test
+    public void exportBibliography_apaMixedPersonAndOrg_succeeds() throws MalformedException {
+        final Creator org = Creator.builder()
+                .id(CREATOR_2_ID)
+                .creatorName("Institute of Science and Technology Austria")
+                .nameIdentifier("https://ror.org/03gnh5541")
+                .nameIdentifierScheme(NameIdentifierSchemeType.ROR)
+                .build();
+        final Identifier identifier = IDENTIFIER_1.toBuilder()
+                .creators(List.of(IDENTIFIER_1_CREATOR_1, org))
+                .build();
+
+        /* test */
+        final String response = dataCiteIdentifierService.exportBibliography(identifier, BibliographyTypeDto.APA);
+        final String title = IDENTIFIER_1_CREATOR_1.getFirstname().charAt(0) + "., " + IDENTIFIER_1_CREATOR_1.getLastname() + " & Institute of Science and Technology Austria";
+        assertTrue(response.contains(title), "expected title not found: " + title);
+        assertTrue(response.contains("" + IDENTIFIER_1_PUBLICATION_YEAR), "expected publication year not found: " + IDENTIFIER_1_PUBLICATION_YEAR);
+    }
+
+    @Test
+    public void exportBibliography_bibtex_succeeds() throws MalformedException {
+
+        /* test */
+        final String response = dataCiteIdentifierService.exportBibliography(IDENTIFIER_1, BibliographyTypeDto.BIBTEX);
+        assertTrue(response.contains(IDENTIFIER_1_TITLE_1.getTitle()));
+        assertTrue(response.contains("" + IDENTIFIER_1_PUBLICATION_YEAR));
+        assertTrue(response.contains(IDENTIFIER_1_CREATOR_1.getLastname()));
+    }
+
+    @Test
+    public void exportBibliography_bibtexMixedPersonAndOrg_succeeds() throws MalformedException {
+        final Creator org = Creator.builder()
+                .id(CREATOR_2_ID)
+                .creatorName("Institute of Science and Technology Austria")
+                .nameIdentifier("https://ror.org/03gnh5541")
+                .nameIdentifierScheme(NameIdentifierSchemeType.ROR)
+                .build();
+        final Identifier identifier = IDENTIFIER_1.toBuilder()
+                .creators(List.of(IDENTIFIER_1_CREATOR_1, org))
+                .build();
+
+        /* test */
+        final String response = dataCiteIdentifierService.exportBibliography(identifier, BibliographyTypeDto.BIBTEX);
+        final String title = IDENTIFIER_5_CREATOR_1.getLastname() + ", " + IDENTIFIER_1_CREATOR_1.getFirstname() + " and Institute of Science and Technology Austria";
+        assertTrue(response.contains(title), "expected title not found: " + title);
+        assertTrue(response.contains("" + IDENTIFIER_1_PUBLICATION_YEAR), "expected publication year not found: " + IDENTIFIER_1_PUBLICATION_YEAR);
+    }
+
+    @Test
+    public void exportBibliography_ieee_succeeds() throws MalformedException {
+
+        /* test */
+        final String response = dataCiteIdentifierService.exportBibliography(IDENTIFIER_1, BibliographyTypeDto.IEEE);
+        assertTrue(response.contains(IDENTIFIER_1_TITLE_1.getTitle()));
+        assertTrue(response.contains("" + IDENTIFIER_1_PUBLICATION_YEAR));
+        assertTrue(response.contains(IDENTIFIER_1_CREATOR_1.getLastname()));
+    }
+
+    @Test
+    public void exportBibliography_ieeeMixedPersonAndOrg_succeeds() throws MalformedException {
+        final Creator org = Creator.builder()
+                .id(CREATOR_2_ID)
+                .creatorName("Institute of Science and Technology Austria")
+                .nameIdentifier("https://ror.org/03gnh5541")
+                .nameIdentifierScheme(NameIdentifierSchemeType.ROR)
+                .build();
+        final Identifier identifier = IDENTIFIER_1.toBuilder()
+                .creators(List.of(IDENTIFIER_1_CREATOR_1, org))
+                .build();
+
+        /* test */
+        final String response = dataCiteIdentifierService.exportBibliography(identifier, BibliographyTypeDto.IEEE);
+        final String title = IDENTIFIER_1_CREATOR_1.getFirstname().charAt(0) + ". " + IDENTIFIER_1_CREATOR_1.getLastname() + ", Institute of Science and Technology Austria";
+        assertTrue(response.contains(title), "expected title not found: " + title);
+        assertTrue(response.contains("" + IDENTIFIER_1_PUBLICATION_YEAR), "expected publication year not found: " + IDENTIFIER_1_PUBLICATION_YEAR);
+    }
+
+    @Test
+    public void delete_succeeds() throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
+            IdentifierNotFoundException, SearchServiceException, SearchServiceConnectionException {
+
+        /* mock */
+        when(searchServiceGateway.update(any(Database.class)))
+                .thenReturn(DATABASE_1_DTO);
+
+        /* test */
+        dataCiteIdentifierService.delete(IDENTIFIER_1);
+    }
+
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java
index 8ccb486638447039360f17b08d4a42712d77bdd0..283450cc256197b1add589295304bd69fbe89dab 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java
@@ -47,9 +47,9 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest {
         genesis();
         /* metadata database */
         licenseRepository.save(LICENSE_1);
-        containerRepository.save(CONTAINER_1);
-        userRepository.saveAll(List.of(USER_1, USER_2, USER_3));
-        databaseRepository.save(DATABASE_1);
+        containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4));
+        userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5));
+        databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3, DATABASE_4));
     }
 
     @Test
@@ -94,4 +94,46 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest {
         assertNotNull(response.getCreator().getAccesses());
     }
 
+    @Test
+    @Transactional
+    public void findByInternalName_succeeds() throws DatabaseNotFoundException {
+
+        /* test */
+        final Database response = databaseService.findByInternalName(DATABASE_1_INTERNALNAME);
+        assertEquals(DATABASE_1_ID, response.getId());
+        assertEquals(CONTAINER_1_ID, response.getCid());
+        /* container */
+        assertNotNull(response.getContainer());
+        assertEquals(CONTAINER_1_ID, response.getContainer().getId());
+        assertEquals(CONTAINER_1_NAME, response.getContainer().getName());
+        assertEquals(CONTAINER_1_INTERNALNAME, response.getContainer().getInternalName());
+        assertEquals(CONTAINER_1_HOST, response.getContainer().getHost());
+        assertEquals(CONTAINER_1_PORT, response.getContainer().getPort());
+        assertEquals(CONTAINER_1_UI_HOST, response.getContainer().getUiHost());
+        assertEquals(CONTAINER_1_UI_PORT, response.getContainer().getUiPort());
+        assertEquals(CONTAINER_1_UI_ADDITIONAL_FLAGS, response.getContainer().getUiAdditionalFlags());
+        assertEquals(CONTAINER_1_SIDECAR_HOST, response.getContainer().getSidecarHost());
+        assertEquals(CONTAINER_1_SIDECAR_PORT, response.getContainer().getSidecarPort());
+        assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getContainer().getPrivilegedUsername());
+        assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getContainer().getPrivilegedPassword());
+        assertNotNull(response.getContainer().getImage());
+        assertEquals(IMAGE_1_NAME, response.getContainer().getImage().getName());
+        assertEquals(IMAGE_1_VERSION, response.getContainer().getImage().getVersion());
+        assertEquals(IMAGE_1_DIALECT, response.getContainer().getImage().getDialect());
+        assertEquals(IMAGE_1_JDBC, response.getContainer().getImage().getJdbcMethod());
+        assertEquals(IMAGE_1_DRIVER, response.getContainer().getImage().getDriverClass());
+        assertEquals(IMAGE_1_REGISTRY, response.getContainer().getImage().getRegistry());
+        assertEquals(IMAGE_1_PORT, response.getContainer().getImage().getDefaultPort());
+        assertNotNull(response.getContainer().getImage().getDateFormats());
+        assertEquals(4, response.getContainer().getImage().getDateFormats().size());
+        /* creator */
+        assertNotNull(response.getCreator());
+        assertEquals(USER_1_ID, response.getCreator().getId());
+        assertEquals(USER_1_USERNAME, response.getCreator().getUsername());
+        assertEquals(USER_1_EMAIL, response.getCreator().getEmail());
+        assertEquals(USER_1_THEME, response.getCreator().getTheme());
+        assertEquals(USER_1_LANGUAGE, response.getCreator().getLanguage());
+        assertNotNull(response.getCreator().getAccesses());
+    }
+
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java
index ede17383813eb46445a33833d680644641b90a20..ea58ae16e4ac35931bb5f713b197bacdc37b6958 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java
@@ -161,33 +161,35 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_dataServiceError_fails() throws ServiceException, ServiceConnectionException {
+    public void create_dataServiceError_fails() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException {
 
         /* mock */
         when(containerRepository.findById(DATABASE_1.getCid()))
                 .thenReturn(Optional.of(CONTAINER_1));
-        doThrow(ServiceException.class)
+        doThrow(DataServiceException.class)
                 .when(dataServiceGateway)
                 .createDatabase(any(CreateDatabaseDto.class));
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             generic_create(DATABASE_1_CREATE, DATABASE_1);
         });
     }
 
     @Test
-    public void create_dataServiceConnection_fails() throws ServiceException, ServiceConnectionException {
+    public void create_dataServiceConnection_fails() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException {
 
         /* mock */
         when(containerRepository.findById(DATABASE_1.getCid()))
                 .thenReturn(Optional.of(CONTAINER_1));
-        doThrow(ServiceConnectionException.class)
+        doThrow(DataServiceConnectionException.class)
                 .when(dataServiceGateway)
                 .createDatabase(any(CreateDatabaseDto.class));
 
         /* test */
-        assertThrows(ServiceConnectionException.class, () -> {
+        assertThrows(DataServiceConnectionException.class, () -> {
             generic_create(DATABASE_1_CREATE, DATABASE_1);
         });
     }
@@ -302,8 +304,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
-    protected Database generic_create(DatabaseCreateDto createDto, Database database) throws ServiceException,
-            ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
+    protected Database generic_create(DatabaseCreateDto createDto, Database database) throws DataServiceException,
+            DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
             ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java
index e664abd5163000e21029836faf0b8db536ddda65..6b3ff624b0e5ebf47757824f645e4a120e43b243 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java
@@ -39,7 +39,6 @@ import static org.mockito.Mockito.when;
 
 @Log4j2
 @SpringBootTest
-@Disabled("keep failing on CI but works locally")
 @ExtendWith(SpringExtension.class)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
 public class IdentifierServicePersistenceTest extends AbstractUnitTest {
@@ -154,9 +153,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_database_succeeds() throws ServiceException, ServiceConnectionException, MalformedException,
-            DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException, QueryNotFoundException,
-            SearchServiceException, SearchServiceConnectionException {
+    public void save_database_succeeds() throws DataServiceException, DataServiceConnectionException,
+            MalformedException, DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException,
+            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException {
 
         /* mock */
         when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), eq(QueryDto.class)))
@@ -168,9 +167,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_existsSubset_succeeds() throws ServiceException, ServiceConnectionException, MalformedException,
-            DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException, QueryNotFoundException,
-            SearchServiceException, SearchServiceConnectionException {
+    public void save_existsSubset_succeeds() throws DataServiceException, DataServiceConnectionException,
+            MalformedException, DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException,
+            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException {
 
         /* mock */
         when(dataServiceGateway.findQuery(IDENTIFIER_5_DATABASE_ID, IDENTIFIER_5_QUERY_ID))
@@ -183,9 +182,10 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_existsDatabase_succeeds() throws MalformedException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException,
-            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public void save_existsDatabase_succeeds() throws MalformedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, IdentifierNotFoundException,
+            ViewNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException,
+            ExternalServiceException {
 
         /* test */
         identifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_DTO);
@@ -279,8 +279,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_succeeds() throws ServiceException, ServiceConnectionException, DatabaseNotFoundException,
-            IdentifierNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public void delete_succeeds() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException,
+            SearchServiceConnectionException {
 
         /* mock */
         when(searchServiceGateway.update(any(Database.class)))
@@ -300,9 +301,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
 
     @Test
     @Transactional
-    public void save_subsetRelatedIdentifiers_succeeds() throws ServiceException, ServiceConnectionException,
+    public void save_subsetRelatedIdentifiers_succeeds() throws DataServiceException, DataServiceConnectionException,
             MalformedException, DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException,
-            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException {
+            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException {
 
         /* mock */
         when(dataServiceGateway.findQuery(IDENTIFIER_5_DATABASE_ID, IDENTIFIER_5_QUERY_ID))
@@ -339,9 +340,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
+    public void save_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException, QueryNotFoundException,
-            SearchServiceException, SearchServiceConnectionException {
+            SearchServiceException, SearchServiceConnectionException, ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_DTO);
@@ -384,9 +385,10 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_repeatedRemoveChildren_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
-            DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException, QueryNotFoundException,
-            SearchServiceException, SearchServiceConnectionException {
+    public void save_repeatedRemoveChildren_succeeds() throws MalformedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, IdentifierNotFoundException,
+            ViewNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException,
+            ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_MODIFY_DTO);
@@ -413,9 +415,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_noRelatedTitleDescription_succeeds() throws ServiceException, ServiceConnectionException,
+    public void save_noRelatedTitleDescription_succeeds() throws DataServiceException, DataServiceConnectionException,
             MalformedException, DatabaseNotFoundException, IdentifierNotFoundException, ViewNotFoundException,
-            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException {
+            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.save(DATABASE_4, USER_4, IDENTIFIER_7_SAVE_DTO);
@@ -430,9 +432,10 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_subsetHasDatabaseIdentifier_succeeds() throws ServiceException, ServiceConnectionException,
+    public void save_subsetHasDatabaseIdentifier_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, ViewNotFoundException,
-            SearchServiceConnectionException, MalformedException, IdentifierNotFoundException {
+            SearchServiceConnectionException, MalformedException, IdentifierNotFoundException,
+            ExternalServiceException {
 
         /* mock */
         when(dataServiceGateway.findQuery(IDENTIFIER_2_DATABASE_ID, IDENTIFIER_2_QUERY_ID))
@@ -449,9 +452,10 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void save_viewIdentifier_succeeds() throws SearchServiceException, MalformedException, ServiceException,
-            QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
-            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
+    public void save_viewIdentifier_succeeds() throws SearchServiceException, MalformedException, DataServiceException,
+            QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
+            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException,
+            ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.save(DATABASE_1, USER_1, IDENTIFIER_3_SAVE_DTO);
@@ -465,9 +469,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws MalformedException, ServiceConnectionException, SearchServiceException,
-            ServiceException, QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException,
-            IdentifierNotFoundException, ViewNotFoundException {
+    public void create_succeeds() throws MalformedException, DataServiceConnectionException, SearchServiceException,
+            DataServiceException, QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException,
+            IdentifierNotFoundException, ViewNotFoundException, ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.create(DATABASE_1, USER_1, IDENTIFIER_1_CREATE_DTO);
@@ -475,9 +479,10 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_hasDoi_succeeds() throws SearchServiceException, MalformedException, ServiceException,
-            QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
-            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
+    public void create_hasDoi_succeeds() throws SearchServiceException, MalformedException, DataServiceException,
+            QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
+            SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException,
+            ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.create(DATABASE_1, USER_1, IDENTIFIER_1_CREATE_WITH_DOI_DTO);
@@ -486,8 +491,9 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void publish_succeeds() throws MalformedException, ServiceConnectionException, SearchServiceException,
-            DatabaseNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException {
+    public void publish_succeeds() throws MalformedException, DataServiceConnectionException, SearchServiceException,
+            DatabaseNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException,
+            ExternalServiceException {
 
         /* test */
         final Identifier response = identifierService.publish(IDENTIFIER_7_ID);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa3a460b999c4e1dbfe78d9e9b50f3d0053e1bf7
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java
@@ -0,0 +1,139 @@
+package at.tuwien.service;
+
+import at.tuwien.config.S3Config;
+import at.tuwien.exception.*;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.containers.MinIOContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
+import software.amazon.awssdk.services.s3.model.PutObjectRequest;
+
+import java.io.File;
+import java.io.InputStream;
+import java.sql.SQLException;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@Testcontainers
+@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+public class StorageServiceIntegrationTest extends AbstractUnitTest {
+
+    @Autowired
+    private StorageService storageService;
+
+    @Autowired
+    private S3Client s3Client;
+
+    @Autowired
+    private S3Config s3Config;
+
+    @Container
+    private static final MinIOContainer minIOContainer = new MinIOContainer("minio/minio:RELEASE.2024-06-06T09-36-42Z");
+
+    @DynamicPropertySource
+    static void dynamicProperties(DynamicPropertyRegistry registry) {
+        registry.add("dbrepo.endpoints.storageService", minIOContainer::getS3URL);
+    }
+
+    @BeforeEach
+    public void beforeEach() throws SQLException {
+        genesis();
+        /* s3 */
+        if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3ImportBucket()))) {
+            s3Client.createBucket(CreateBucketRequest.builder()
+                    .bucket(s3Config.getS3ImportBucket())
+                    .build());
+        }
+        if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3ExportBucket()))) {
+            s3Client.createBucket(CreateBucketRequest.builder()
+                    .bucket(s3Config.getS3ExportBucket())
+                    .build());
+        }
+    }
+
+    @Test
+    public void getObject_succeeds() throws StorageUnavailableException, StorageNotFoundException {
+        final String key = "s3key";
+
+        /* mock */
+        log.trace("mock object with key {} to bucket {}", key, s3Config.getS3ImportBucket());
+        s3Client.putObject(PutObjectRequest.builder()
+                .key(key)
+                .bucket(s3Config.getS3ImportBucket())
+                .build(), RequestBody.fromFile(new File("src/test/resources/csv/keyboard.csv")));
+
+        /* test */
+        final InputStream response = storageService.getObject(s3Config.getS3ImportBucket(), key);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void getObject_notFound_fails() {
+
+        /* test */
+        assertThrows(StorageNotFoundException.class, () -> {
+            storageService.getObject(s3Config.getS3ImportBucket(), "i_do_not_exist");
+        });
+    }
+
+    @Test
+    public void getObject_bucketNotFound_fails() {
+
+        /* test */
+        assertThrows(StorageUnavailableException.class, () -> {
+            storageService.getObject("i_do_not_exist", "i_do_neither");
+        });
+    }
+
+    @Test
+    public void getBytes_succeeds() throws StorageUnavailableException, StorageNotFoundException {
+        final String key = "s3key";
+
+        /* mock */
+        log.trace("mock object with key {} to bucket {}", key, s3Config.getS3ImportBucket());
+        s3Client.putObject(PutObjectRequest.builder()
+                .key(key)
+                .bucket(s3Config.getS3ImportBucket())
+                .build(), RequestBody.fromFile(new File("src/test/resources/csv/keyboard.csv")));
+
+        /* test */
+        final byte[] response = storageService.getBytes(key);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void getBytes_notExists_fails() {
+
+        /* test */
+        assertThrows(StorageNotFoundException.class, () -> {
+            storageService.getBytes("i_do_not_exist");
+        });
+    }
+
+    @Test
+    public void getBytes_bucketNotExists_fails() {
+
+        /* test */
+        assertThrows(StorageUnavailableException.class, () -> {
+            storageService.getBytes("i_do_not_exist", "i_do_neither");
+        });
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java
index f30bf485f3be9a75eaa43f28e0d57fecd7d96b2a..e66d35d8ea0d8b0f9aff850cf4baf880e4240c12 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java
@@ -78,7 +78,7 @@ public class TableServicePersistenceTest extends AbstractUnitTest {
 
     @Test
     @Transactional
-    public void create_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
+    public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
         final TableCreateDto request = TableCreateDto.builder()
                 .name("New Table")
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
index d32189f944767a41aea777728ce7d1c58cf05a10..33b4594424956b584ff2910898f18d336c1aec7b 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
@@ -8,11 +8,9 @@ import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto;
 import at.tuwien.entities.database.table.columns.TableColumnType;
 import at.tuwien.entities.database.table.constraints.Constraints;
 import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
-import at.tuwien.entities.database.table.columns.TableColumnConcept;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
@@ -117,9 +115,9 @@ public class TableServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTable_succeeds() throws ServiceException, ServiceConnectionException, UserNotFoundException,
-            TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException,
-            SearchServiceConnectionException, MalformedException, OntologyNotFoundException,
+    public void createTable_succeeds() throws DataServiceException, DataServiceConnectionException,
+            UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException,
+            SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException,
             SemanticEntityNotFoundException {
 
         /* mock */
@@ -139,10 +137,10 @@ public class TableServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTable_nonStandardColumnNames_succeeds() throws ServiceException, ServiceConnectionException,
-            UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException,
-            SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException,
-            SemanticEntityNotFoundException {
+    public void createTable_nonStandardColumnNames_succeeds() throws DataServiceException,
+            DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException,
+            TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException,
+            OntologyNotFoundException, SemanticEntityNotFoundException {
         final TableCreateDto request = TableCreateDto.builder()
                 .name("New Table")
                 .description("A wonderful table")
@@ -202,7 +200,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTable_dateFormatNotFound_fails() throws ServiceException, ServiceConnectionException,
+    public void createTable_dateFormatNotFound_fails() throws DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException,
             SearchServiceConnectionException {
         final TableCreateDto request = TableCreateDto.builder()
@@ -240,7 +238,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
+    public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException,
             SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException,
             SemanticEntityNotFoundException {
@@ -262,31 +260,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @Transactional
-    public void update_succeeds() throws ServiceException, ServiceConnectionException, DatabaseNotFoundException,
-            SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException,
-            SemanticEntityNotFoundException {
-        final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
-                .conceptUri(CONCEPT_1_URI)
-                .build();
-
-        /* mock */
-        when(ontologyService.find(anyString()))
-                .thenReturn(ONTOLOGY_2);
-        when(ontologyService.findAll())
-                .thenReturn(List.of(ONTOLOGY_1, ONTOLOGY_2, ONTOLOGY_3, ONTOLOGY_4, ONTOLOGY_5));
-        when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
-
-        /* test */
-        final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request);
-        assertNotNull(response.getConcept());
-        final TableColumnConcept concept = response.getConcept();
-        assertEquals(CONCEPT_1_URI, concept.getUri());
-    }
-
-    @Test
-    public void create_dataServiceError_fails() throws ServiceException, ServiceConnectionException,
+    public void create_dataServiceError_fails() throws DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException,
             SearchServiceConnectionException {
 
@@ -295,14 +269,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(USER_1);
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
-        doThrow(ServiceException.class)
+        doThrow(DataServiceException.class)
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, TABLE_5_CREATE_DTO);
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             tableService.createTable(DATABASE_1, TABLE_5_CREATE_DTO, USER_1_PRINCIPAL);
         });
     }
@@ -388,8 +362,9 @@ public class TableServiceUnitTest extends AbstractUnitTest {
 
     @Test
     @Transactional
-    public void delete_succeeds() throws ServiceException, ServiceConnectionException, DatabaseNotFoundException,
-            TableNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public void delete_succeeds() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException, TableNotFoundException, SearchServiceException,
+            SearchServiceConnectionException {
 
         /* mock */
         doNothing()
@@ -404,7 +379,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
 
     @Test
     @Transactional
-    public void delete_hasIdentifier_succeeds() throws ServiceException, ServiceConnectionException,
+    public void delete_hasIdentifier_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, TableNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
index f85d4663700427aaca2f55bae9c88e26e441f45b..5a4690892f890097f636a868ab9d69aadb0c6ef2 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
@@ -72,7 +72,7 @@ public class UserServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void create_succeeds() throws UserNotFoundException, UserExistsException, EmailExistsException,
-            ServiceException, ServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
+            DataServiceException, DataServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
             CredentialsInvalidException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java
index fc83d3a650b5642bbe0e8cdc252e95ef59c9dcf5..e23320017c54592662f42b24c3eb7039a3f1a540 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java
@@ -79,7 +79,7 @@ public class ViewServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_succeeds() throws SearchServiceException, ServiceException, ServiceConnectionException,
+    public void delete_succeeds() throws SearchServiceException, DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, SearchServiceConnectionException, ViewNotFoundException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java
index 517661ce1a03220bb536ef1fbacfe81e3d0f32c9..cd9fe03c655d33b014239af4f05f0f0ae9b6d1e9 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java
@@ -48,7 +48,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws MalformedException, ServiceException, ServiceConnectionException,
+    public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
         final ViewCreateDto request = ViewCreateDto.builder()
                 .name(VIEW_1_NAME)
@@ -107,8 +107,8 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_succeeds() throws ServiceException, ServiceConnectionException, DatabaseNotFoundException,
-            ViewNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public void delete_succeeds() throws DataServiceException, DataServiceConnectionException,
+            DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
         doNothing()
@@ -124,37 +124,37 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_dataServiceException_fails() throws ServiceException, ServiceConnectionException,
+    public void delete_dataServiceException_fails() throws DataServiceException, DataServiceConnectionException,
             ViewNotFoundException {
 
         /* mock */
-        doThrow(ServiceException.class)
+        doThrow(DataServiceException.class)
                 .when(dataServiceGateway)
                 .deleteView(DATABASE_1_ID, VIEW_1_ID);
 
         /* test */
-        assertThrows(ServiceException.class, () -> {
+        assertThrows(DataServiceException.class, () -> {
             viewService.delete(VIEW_1);
         });
     }
 
     @Test
-    public void delete_dataServiceConnection_fails() throws ServiceException, ServiceConnectionException,
+    public void delete_dataServiceConnection_fails() throws DataServiceException, DataServiceConnectionException,
             ViewNotFoundException {
 
         /* mock */
-        doThrow(ServiceConnectionException.class)
+        doThrow(DataServiceConnectionException.class)
                 .when(dataServiceGateway)
                 .deleteView(DATABASE_1_ID, VIEW_1_ID);
 
         /* test */
-        assertThrows(ServiceConnectionException.class, () -> {
+        assertThrows(DataServiceConnectionException.class, () -> {
             viewService.delete(VIEW_1);
         });
     }
 
     @Test
-    public void delete_searchServiceError_fails() throws ServiceException, ServiceConnectionException,
+    public void delete_searchServiceError_fails() throws DataServiceException, DataServiceConnectionException,
             ViewNotFoundException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
@@ -174,7 +174,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_searchServiceConnection_fails() throws ServiceException, ServiceConnectionException,
+    public void delete_searchServiceConnection_fails() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
@@ -194,7 +194,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void delete_searchServiceNotFound_fails() throws ServiceException, ServiceConnectionException,
+    public void delete_searchServiceNotFound_fails() throws DataServiceException, DataServiceConnectionException,
             ViewNotFoundException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
index a0588a6e1b118f206e8fb17c3507dcdb4efacaad..df86598714d65600e0dc79b5f6a3048fb3df16b5 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java
@@ -1,18 +1,22 @@
 package at.tuwien.utils;
 
 import at.tuwien.api.amqp.*;
+import at.tuwien.test.BaseTest;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.codec.binary.Base64;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.support.BasicAuthenticationInterceptor;
 import org.springframework.stereotype.Service;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
 
 import java.nio.charset.Charset;
 import java.util.Arrays;
@@ -20,13 +24,17 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 @Log4j2
-@Service
-public class AmqpUtils {
+public class AmqpUtils extends BaseTest {
+
+    private static final String BASIC_AUTH = new String(Base64.encodeBase64((USER_1_USERNAME + ":" + USER_1_PASSWORD).getBytes(Charset.defaultCharset())));
 
     private final RestTemplate restTemplate;
 
-    @Autowired
-    public AmqpUtils(@Qualifier("brokerRestTemplate") RestTemplate restTemplate) {
+    public AmqpUtils(String endpoint) {
+        final RestTemplate restTemplate = new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(endpoint));
+        restTemplate.getInterceptors()
+                .add(new BasicAuthenticationInterceptor(USER_1_USERNAME, USER_1_PASSWORD));
         this.restTemplate = restTemplate;
     }
 
@@ -97,10 +105,10 @@ public class AmqpUtils {
 
     public void setVirtualHostPermissions(String vhost, String username, GrantVirtualHostPermissionsDto data) {
         final String url = "/api/permissions/" + vhost + "/" + username;
-        log.debug("set virtual host permissions: {}", url);
         log.trace("body: {}", data);
         final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
-        headers.add("Authentication", "Basic " + new String(Base64.encodeBase64("guest:guest".getBytes(Charset.defaultCharset()))));
+        headers.add("Authentication", "Basic " + BASIC_AUTH);
+        log.trace("set virtual host permissions: {}", url);
         final ResponseEntity<Void> response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data, headers), Void.class);
         if (!response.getStatusCode().equals(HttpStatus.CREATED) && !response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
             log.error("Failed to set virtual host permissions: {}", response.getStatusCode());
@@ -113,7 +121,7 @@ public class AmqpUtils {
         log.debug("set topic permissions: {}", url);
         log.trace("body: {}", data);
         final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
-        headers.add("Authentication", "Basic " + new String(Base64.encodeBase64("guest:guest".getBytes(Charset.defaultCharset()))));
+        headers.add("Authentication", "Basic " + BASIC_AUTH);
         final ResponseEntity<Void> response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data, headers), Void.class);
         if (!response.getStatusCode().equals(HttpStatus.CREATED) && !response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
             log.error("Failed to set topic permissions: {}", response.getStatusCode());
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/H2Utils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/H2Utils.java
similarity index 97%
rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/H2Utils.java
rename to dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/H2Utils.java
index 033d1ba280c7224f447ec99ded6850dbd38a38e9..7c80d5274a386031276fdb48eab6eaa3e2989024 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/H2Utils.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/H2Utils.java
@@ -1,4 +1,4 @@
-package at.tuwien.config;
+package at.tuwien.utils;
 
 import jakarta.persistence.EntityManager;
 import lombok.extern.log4j.Log4j2;
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..49694e6fd1dc49eb0f4bc8df35f1b6cd4965bf5e
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
@@ -0,0 +1,40 @@
+package at.tuwien.utils;
+
+import at.tuwien.api.keycloak.RoleRepresentationDto;
+import at.tuwien.exception.*;
+import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.gateway.impl.KeycloakGatewayImpl;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
+import java.util.UUID;
+
+@Log4j2
+@Component
+public class KeycloakUtils {
+
+    final static UUID realmId = UUID.fromString("82c39861-d877-4667-a0f3-4daa2ee230e0");
+
+    private final KeycloakGateway keycloakGateway;
+
+    @Autowired
+    public KeycloakUtils(KeycloakGateway keycloakGateway) {
+        this.keycloakGateway = keycloakGateway;
+    }
+
+    public void deleteUser(String username) throws AuthServiceException, AuthServiceConnectionException,
+            CredentialsInvalidException {
+        try {
+            final UUID userId = keycloakGateway.findByUsername(username).getId();
+            keycloakGateway.deleteUser(userId);
+        } catch (UserNotFoundException e) {
+            /* ignore */
+        }
+    }
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
index 1e5aa8227a077254112f2a9c4ec86d759d269bc7..f6cf4e887d4d25f2dfc201ae6d4d014f3b8c1547 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
@@ -30,8 +30,7 @@ import java.util.List;
 import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.when;
 
@@ -173,7 +172,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
             DatabaseNotFoundException, AccessNotFoundException {
 
         /* mock */
-        when(databaseService.findById(DATABASE_3_ID))
+        when(databaseService.findById(anyLong()))
                 .thenReturn(DATABASE_3);
 
         /* test */
@@ -181,11 +180,11 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @Disabled("keep failing on CI but works locally")
+    @Disabled
     public void validateOnlyAccessOrPublic_privateAnonymous_fails() throws DatabaseNotFoundException {
 
         /* mock */
-        when(databaseService.findById(DATABASE_1_ID))
+        when(databaseService.findById(anyLong()))
                 .thenReturn(DATABASE_1);
 
         /* test */
@@ -195,7 +194,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @Disabled("keep failing on CI but works locally")
+    @Disabled
     public void validateOnlyAccessOrPublic_privateNoAccess_fails() throws DatabaseNotFoundException,
             AccessNotFoundException {
 
@@ -204,7 +203,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1);
         doThrow(AccessNotFoundException.class)
                 .when(accessService)
-                .find(eq(DATABASE_1), any(User.class));
+                .find(any(Database.class), any(User.class));
 
         /* test */
         assertThrows(AccessNotFoundException.class, () -> {
@@ -402,11 +401,11 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @Disabled("keep failing on CI but works locally")
+    @Disabled
     public void validateOnlyPrivateHasRole_privatePrincipalMissing_fails() throws DatabaseNotFoundException {
 
         /* mock */
-        when(databaseService.findById(DATABASE_1_ID))
+        when(databaseService.findById(anyLong()))
                 .thenReturn(DATABASE_1);
 
         /* test */
@@ -416,11 +415,11 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @Disabled("keep failing on CI but works locally")
+    @Disabled
     public void validateOnlyPrivateHasRole_privateRoleMissing_fails() throws DatabaseNotFoundException {
 
         /* mock */
-        when(databaseService.findById(DATABASE_1_ID))
+        when(databaseService.findById(anyLong()))
                 .thenReturn(DATABASE_1);
 
         /* test */
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/application.properties b/dbrepo-metadata-service/rest-service/src/test/resources/application.properties
index 4243bcf79e7133c183f076dd33c07269921b900b..0929175cf79929776a59fd6d27075ae6df998de6 100644
--- a/dbrepo-metadata-service/rest-service/src/test/resources/application.properties
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/application.properties
@@ -14,20 +14,20 @@ spring.sql.init.mode=always
 spring.sql.init.schema-locations=classpath*:init/schema.sql
 spring.jpa.hibernate.ddl-auto=create
 
-# LDAP
-spring.ldap.userDn: cn=admin,dc=dbrepo,dc=at
-spring.ldap.password: adminpassword
-spring.ldap.base: dc=dbrepo,dc=at
-
-# admin
-dbrepo.system.role: admin
-
 # logging
 logging.level.root=error
 logging.level.at.tuwien.=trace
+logging.level.org.testcontainers.=info
+logging.level.tc.=info
+logging.level.com.github.dockerjava.=warn
+logging.level.com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.wire.=off
 
 # datacite
 dbrepo.datacite.url: https://api.test.datacite.org
 dbrepo.datacite.prefix: 10.12345
 dbrepo.datacite.username: test-user
 dbrepo.datacite.password: test-password
+
+# s3
+dbrepo.s3.accessKeyId=minioadmin
+dbrepo.s3.secretAccessKey=minioadmin
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
index 639d73ea15fdba309347312286e71a7f0706268e..588053e15fa6d5872c4cb83da42d71859b5f7a64 100644
--- a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
@@ -1,1525 +1,2822 @@
-{
-  "id": "4ef53018-8322-40ed-a44a-a7c5292a07be",
-  "realm": "dbrepo",
-  "displayName": "",
-  "displayNameHtml": "",
-  "notBefore": 0,
-  "defaultSignatureAlgorithm": "RS256",
-  "revokeRefreshToken": false,
-  "refreshTokenMaxReuse": 0,
-  "accessTokenLifespan": 300,
-  "accessTokenLifespanForImplicitFlow": 900,
-  "ssoSessionIdleTimeout": 1800,
-  "ssoSessionMaxLifespan": 36000,
-  "ssoSessionIdleTimeoutRememberMe": 0,
-  "ssoSessionMaxLifespanRememberMe": 0,
-  "offlineSessionIdleTimeout": 2592000,
-  "offlineSessionMaxLifespanEnabled": false,
-  "offlineSessionMaxLifespan": 5184000,
-  "clientSessionIdleTimeout": 0,
-  "clientSessionMaxLifespan": 0,
-  "clientOfflineSessionIdleTimeout": 0,
-  "clientOfflineSessionMaxLifespan": 0,
-  "accessCodeLifespan": 60,
-  "accessCodeLifespanUserAction": 300,
-  "accessCodeLifespanLogin": 1800,
-  "actionTokenGeneratedByAdminLifespan": 43200,
-  "actionTokenGeneratedByUserLifespan": 300,
-  "oauth2DeviceCodeLifespan": 600,
-  "oauth2DevicePollingInterval": 5,
-  "enabled": true,
-  "sslRequired": "none",
-  "registrationAllowed": false,
-  "registrationEmailAsUsername": false,
-  "rememberMe": false,
-  "verifyEmail": false,
-  "loginWithEmailAllowed": true,
-  "duplicateEmailsAllowed": false,
-  "resetPasswordAllowed": false,
-  "editUsernameAllowed": false,
-  "bruteForceProtected": false,
-  "permanentLockout": false,
-  "maxFailureWaitSeconds": 900,
-  "minimumQuickLoginWaitSeconds": 60,
-  "waitIncrementSeconds": 60,
-  "quickLoginCheckMilliSeconds": 1000,
-  "maxDeltaTimeSeconds": 43200,
-  "failureFactor": 30,
-  "defaultRole": {
-    "id": "7a02acbe-09aa-4af7-8e79-fbb0cf5fd0d6",
-    "name": "default-roles-dbrepo",
-    "description": "${role_default-roles}",
-    "composite": true,
-    "clientRole": false,
-    "containerId": "4ef53018-8322-40ed-a44a-a7c5292a07be"
-  },
-  "requiredCredentials": [
-    "password"
-  ],
-  "otpPolicyType": "totp",
-  "otpPolicyAlgorithm": "HmacSHA1",
-  "otpPolicyInitialCounter": 0,
-  "otpPolicyDigits": 6,
-  "otpPolicyLookAheadWindow": 1,
-  "otpPolicyPeriod": 30,
-  "otpPolicyCodeReusable": false,
-  "otpSupportedApplications": [
-    "totpAppGoogleName",
-    "totpAppMicrosoftAuthenticatorName",
-    "totpAppFreeOTPName"
-  ],
-  "webAuthnPolicyRpEntityName": "keycloak",
-  "webAuthnPolicySignatureAlgorithms": [
-    "ES256"
-  ],
-  "webAuthnPolicyRpId": "",
-  "webAuthnPolicyAttestationConveyancePreference": "not specified",
-  "webAuthnPolicyAuthenticatorAttachment": "not specified",
-  "webAuthnPolicyRequireResidentKey": "not specified",
-  "webAuthnPolicyUserVerificationRequirement": "not specified",
-  "webAuthnPolicyCreateTimeout": 0,
-  "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
-  "webAuthnPolicyAcceptableAaguids": [],
-  "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
-  "webAuthnPolicyPasswordlessSignatureAlgorithms": [
-    "ES256"
-  ],
-  "webAuthnPolicyPasswordlessRpId": "",
-  "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
-  "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
-  "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
-  "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
-  "webAuthnPolicyPasswordlessCreateTimeout": 0,
-  "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
-  "webAuthnPolicyPasswordlessAcceptableAaguids": [],
-  "scopeMappings": [
-    {
-      "clientScope": "offline_access",
-      "roles": [
-        "offline_access"
-      ]
-    }
-  ],
-  "clientScopes": [
-    {
-      "id": "4410371f-2840-458a-a496-375bd500f5fc",
-      "name": "email",
-      "description": "OpenID Connect built-in scope: email",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${emailScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "7001651a-7ded-4a0f-9cb7-816b058af730",
-          "name": "email",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "email",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "email",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "25e4ad82-8b9b-463d-8b35-02fae44ec64c",
-          "name": "email verified",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "emailVerified",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "email_verified",
-            "jsonType.label": "boolean"
-          }
-        }
-      ]
-    },
-    {
-      "id": "ebe0a886-5df1-48f3-9f00-a45d686b0b02",
-      "name": "address",
-      "description": "OpenID Connect built-in scope: address",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${addressScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "866be669-9799-45ad-abdd-23f5d1c82293",
-          "name": "address",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-address-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.attribute.formatted": "formatted",
-            "user.attribute.country": "country",
-            "user.attribute.postal_code": "postal_code",
-            "userinfo.token.claim": "true",
-            "user.attribute.street": "street",
-            "id.token.claim": "true",
-            "user.attribute.region": "region",
-            "access.token.claim": "true",
-            "user.attribute.locality": "locality"
-          }
-        }
-      ]
-    },
-    {
-      "id": "be0f3000-0106-4edd-a8f5-0618e3a3f7fe",
-      "name": "microprofile-jwt",
-      "description": "Microprofile - JWT built-in scope",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "false"
-      },
-      "protocolMappers": [
-        {
-          "id": "093f222d-cee9-495a-81b7-ddae4b730ab2",
-          "name": "groups",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-realm-role-mapper",
-          "consentRequired": false,
-          "config": {
-            "multivalued": "true",
-            "user.attribute": "foo",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "groups",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "2e21b9f5-c428-4a5b-9dd8-8a80bc6d9795",
-          "name": "upn",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "username",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "upn",
-            "jsonType.label": "String"
-          }
-        }
-      ]
-    },
-    {
-      "id": "2a95813e-053d-4c20-9f2b-f7e1ad1798f5",
-      "name": "role_list",
-      "description": "SAML role list",
-      "protocol": "saml",
-      "attributes": {
-        "consent.screen.text": "${samlRoleListScopeConsentText}",
-        "display.on.consent.screen": "true"
-      },
-      "protocolMappers": [
-        {
-          "id": "9c8a5628-af2a-4ba4-9cad-a8ae58c8526a",
-          "name": "role list",
-          "protocol": "saml",
-          "protocolMapper": "saml-role-list-mapper",
-          "consentRequired": false,
-          "config": {
-            "single": "false",
-            "attribute.nameformat": "Basic",
-            "attribute.name": "Role"
-          }
-        }
-      ]
-    },
-    {
-      "id": "c6375bbe-9820-4781-8828-99020210f5bd",
-      "name": "roles",
-      "description": "OpenID Connect scope for add user roles to the access token",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "false",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${rolesScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "a1db2464-4e12-4696-914d-d252263e4470",
-          "name": "audience resolve",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-audience-resolve-mapper",
-          "consentRequired": false,
-          "config": {}
-        },
-        {
-          "id": "c5513105-d577-4ba0-bff8-f96e9272f6fd",
-          "name": "client roles",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-client-role-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.attribute": "foo",
-            "access.token.claim": "true",
-            "claim.name": "resource_access.${client_id}.roles",
-            "jsonType.label": "String",
-            "multivalued": "true"
-          }
-        },
-        {
-          "id": "66901106-8ea3-4712-8bdf-bc67da4a9d2d",
-          "name": "realm roles",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-realm-role-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.attribute": "foo",
-            "access.token.claim": "true",
-            "claim.name": "realm_access.roles",
-            "jsonType.label": "String",
-            "multivalued": "true"
-          }
-        }
-      ]
-    },
-    {
-      "id": "f0ea8ba1-794d-4b89-9ad3-b7f390c5241e",
-      "name": "phone",
-      "description": "OpenID Connect built-in scope: phone",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${phoneScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "b3789148-8427-4af8-bc03-4dd3fae4b312",
-          "name": "phone number",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "phoneNumber",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "phone_number",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "552ac5e8-6e04-47d5-8ddf-89230ca31b43",
-          "name": "phone number verified",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "phoneNumberVerified",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "phone_number_verified",
-            "jsonType.label": "boolean"
-          }
-        }
-      ]
-    },
-    {
-      "id": "8ff9a2f3-582c-4cda-8ea8-d08850f8a394",
-      "name": "web-origins",
-      "description": "OpenID Connect scope for add allowed web origins to the access token",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "false",
-        "display.on.consent.screen": "false",
-        "consent.screen.text": ""
-      },
-      "protocolMappers": [
-        {
-          "id": "52af8bfd-44b1-4b69-bfd5-bc92cf1629aa",
-          "name": "allowed web origins",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-allowed-origins-mapper",
-          "consentRequired": false,
-          "config": {}
-        }
-      ]
-    },
-    {
-      "id": "b3ebaf28-e467-4c70-b993-d7b8459dfb5a",
-      "name": "profile",
-      "description": "OpenID Connect built-in scope: profile",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${profileScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "1025302a-104e-42e8-acf8-83579c21bfbb",
-          "name": "family name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "lastName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "family_name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "70a9942e-85c1-4f15-9605-6408e0087b74",
-          "name": "given name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "firstName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "given_name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "1e36c899-c472-427e-a024-c12a64d6084c",
-          "name": "website",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "website",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "website",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "b5e54114-79cb-488d-9e60-6a804ca3b22a",
-          "name": "profile",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "profile",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "profile",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "3e9406b9-a0ae-48d2-98b9-66ab7360b2a2",
-          "name": "gender",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "gender",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "gender",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "aec55dcc-59e7-4ea7-9eb5-55954d983fd0",
-          "name": "locale",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "locale",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "locale",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "11fd80da-8760-4fa6-9d1b-32da9df170bd",
-          "name": "picture",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "picture",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "picture",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "90f93a66-27d0-4890-846b-79d99e02ad76",
-          "name": "updated at",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "updatedAt",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "updated_at",
-            "jsonType.label": "long"
-          }
-        },
-        {
-          "id": "6c8aa1f6-3aa2-4e48-9f9c-44cffe71e7d2",
-          "name": "username",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "username",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "preferred_username",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "a861da8e-87e7-4b5d-92fa-4ca61671c77f",
-          "name": "birthdate",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "birthdate",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "birthdate",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "ae301563-61a7-413b-87a0-036e1af942bb",
-          "name": "middle name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "middleName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "middle_name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "c39e0763-48a9-4f69-84f4-4e334365f99b",
-          "name": "full name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-full-name-mapper",
-          "consentRequired": false,
-          "config": {
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "userinfo.token.claim": "true"
-          }
-        },
-        {
-          "id": "a54ae213-5854-4f77-8646-5cc7767fb914",
-          "name": "nickname",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "nickname",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "nickname",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "41824638-4a2f-4259-90fe-431a32371256",
-          "name": "zoneinfo",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "zoneinfo",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "zoneinfo",
-            "jsonType.label": "String"
-          }
-        }
-      ]
-    },
-    {
-      "id": "4c7c18fe-2aff-4df3-aeff-4dca9de93a79",
-      "name": "offline_access",
-      "description": "OpenID Connect built-in scope: offline_access",
-      "protocol": "openid-connect",
-      "attributes": {
-        "consent.screen.text": "${offlineAccessScopeConsentText}",
-        "display.on.consent.screen": "true"
-      }
-    },
-    {
-      "id": "30b249b2-c788-47ef-a8c7-daa0e3713b7c",
-      "name": "acr",
-      "description": "OpenID Connect scope for add acr (authentication context class reference) to the token",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "false",
-        "display.on.consent.screen": "false"
-      },
-      "protocolMappers": [
-        {
-          "id": "50cf075c-fdc9-43f4-ab85-1e32cafbbb26",
-          "name": "acr loa level",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-acr-mapper",
-          "consentRequired": false,
-          "config": {
-            "id.token.claim": "true",
-            "access.token.claim": "true"
-          }
-        }
-      ]
-    }
-  ],
-  "defaultDefaultClientScopes": [
-    "role_list",
-    "profile",
-    "email",
-    "roles",
-    "web-origins",
-    "acr"
-  ],
-  "defaultOptionalClientScopes": [
-    "offline_access",
-    "address",
-    "phone",
-    "microprofile-jwt"
-  ],
-  "browserSecurityHeaders": {
-    "contentSecurityPolicyReportOnly": "",
-    "xContentTypeOptions": "nosniff",
-    "xRobotsTag": "none",
-    "xFrameOptions": "SAMEORIGIN",
-    "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
-    "xXSSProtection": "1; mode=block",
-    "strictTransportSecurity": "max-age=31536000; includeSubDomains"
-  },
-  "smtpServer": {},
-  "eventsEnabled": false,
-  "eventsListeners": [
-    "jboss-logging"
-  ],
-  "enabledEventTypes": [],
-  "adminEventsEnabled": false,
-  "adminEventsDetailsEnabled": false,
-  "identityProviders": [],
-  "identityProviderMappers": [],
-  "components": {
-    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
-      {
-        "id": "4489b316-ab01-42cf-a224-f853a310c7c5",
-        "name": "Allowed Protocol Mapper Types",
-        "providerId": "allowed-protocol-mappers",
-        "subType": "authenticated",
-        "subComponents": {},
-        "config": {
-          "allowed-protocol-mapper-types": [
-            "oidc-address-mapper",
-            "saml-user-property-mapper",
-            "oidc-usermodel-property-mapper",
-            "oidc-usermodel-attribute-mapper",
-            "saml-user-attribute-mapper",
-            "oidc-sha256-pairwise-sub-mapper",
-            "oidc-full-name-mapper",
-            "saml-role-list-mapper"
-          ]
-        }
-      },
-      {
-        "id": "d355f2ac-bd0d-4c5c-8e2d-52f14f332354",
-        "name": "Allowed Protocol Mapper Types",
-        "providerId": "allowed-protocol-mappers",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "allowed-protocol-mapper-types": [
-            "oidc-full-name-mapper",
-            "oidc-usermodel-attribute-mapper",
-            "oidc-address-mapper",
-            "oidc-sha256-pairwise-sub-mapper",
-            "saml-role-list-mapper",
-            "saml-user-property-mapper",
-            "saml-user-attribute-mapper",
-            "oidc-usermodel-property-mapper"
-          ]
-        }
-      },
-      {
-        "id": "cefbb851-d3bd-4b6d-b582-7fc4fa51d9b6",
-        "name": "Allowed Client Scopes",
-        "providerId": "allowed-client-templates",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "allow-default-scopes": [
-            "true"
-          ]
-        }
-      },
-      {
-        "id": "b7fe23c6-f82b-4920-8062-3d9fa6fb838f",
-        "name": "Full Scope Disabled",
-        "providerId": "scope",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {}
-      },
-      {
-        "id": "8332b5b7-5643-4c9f-afdb-4bda506bac55",
-        "name": "Allowed Client Scopes",
-        "providerId": "allowed-client-templates",
-        "subType": "authenticated",
-        "subComponents": {},
-        "config": {
-          "allow-default-scopes": [
-            "true"
-          ]
-        }
-      },
-      {
-        "id": "bb595923-ec43-4cbc-be3c-6d65c250956d",
-        "name": "Consent Required",
-        "providerId": "consent-required",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {}
-      },
-      {
-        "id": "4d9901ea-7d1e-484a-a5de-abb36d8a5cc8",
-        "name": "Trusted Hosts",
-        "providerId": "trusted-hosts",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "host-sending-registration-request-must-match": [
-            "true"
-          ],
-          "client-uris-must-match": [
-            "true"
-          ]
-        }
-      },
-      {
-        "id": "44bd2392-250b-4b4a-9772-7478fbd68f67",
-        "name": "Max Clients Limit",
-        "providerId": "max-clients",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "max-clients": [
-            "200"
-          ]
-        }
-      }
-    ],
-    "org.keycloak.userprofile.UserProfileProvider": [
-      {
-        "id": "0ffb33e9-2f5b-4e54-b188-19b3da816f0f",
-        "providerId": "declarative-user-profile",
-        "subComponents": {},
-        "config": {}
-      }
-    ],
-    "org.keycloak.keys.KeyProvider": [
-      {
-        "id": "d80cf13c-e402-49e5-b347-0175bdcac7b6",
-        "name": "rsa-generated",
-        "providerId": "rsa-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ]
-        }
-      },
-      {
-        "id": "03442c52-879c-4b3d-89c4-db02a0ad3c52",
-        "name": "aes-generated",
-        "providerId": "aes-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ]
-        }
-      },
-      {
-        "id": "30ce0596-cbce-4633-a422-15873bc363bf",
-        "name": "hmac-generated",
-        "providerId": "hmac-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ],
-          "algorithm": [
-            "HS256"
-          ]
-        }
-      },
-      {
-        "id": "012d037c-b22a-48f2-a80a-927424d75f00",
-        "name": "rsa-enc-generated",
-        "providerId": "rsa-enc-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ],
-          "algorithm": [
-            "RSA-OAEP"
-          ]
-        }
-      }
-    ]
-  },
-  "internationalizationEnabled": false,
-  "supportedLocales": [],
-  "authenticationFlows": [
-    {
-      "id": "865c209a-a080-4162-9b49-795345294601",
-      "alias": "Account verification options",
-      "description": "Method with which to verity the existing account",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "idp-email-verification",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "ALTERNATIVE",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "Verify Existing Account by Re-authentication",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "85fc1de2-5b82-40ec-bda0-91a4fec38584",
-      "alias": "Authentication Options",
-      "description": "Authentication options.",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "basic-auth",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "basic-auth-otp",
-          "authenticatorFlow": false,
-          "requirement": "DISABLED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "auth-spnego",
-          "authenticatorFlow": false,
-          "requirement": "DISABLED",
-          "priority": 30,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "2476a340-9459-4541-9e61-226f06ec66c4",
-      "alias": "Browser - Conditional OTP",
-      "description": "Flow to determine if the OTP is required for the authentication",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "conditional-user-configured",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "auth-otp-form",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "2e424297-19dd-4c09-a06a-876ef5183ca6",
-      "alias": "Direct Grant - Conditional OTP",
-      "description": "Flow to determine if the OTP is required for the authentication",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "conditional-user-configured",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "direct-grant-validate-otp",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "3966485f-3455-47d2-86a2-d990b41c7953",
-      "alias": "First broker login - Conditional OTP",
-      "description": "Flow to determine if the OTP is required for the authentication",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "conditional-user-configured",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "auth-otp-form",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "29098fa4-d254-44cb-a6c5-63b36b8bfdc1",
-      "alias": "Handle Existing Account",
-      "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "idp-confirm-link",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "Account verification options",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "03569e80-3083-4147-ad49-445466c191d8",
-      "alias": "Reset - Conditional OTP",
-      "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "conditional-user-configured",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "reset-otp",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "7e660682-5eb3-4527-a5fa-53fc14a0f2f5",
-      "alias": "User creation or linking",
-      "description": "Flow for the existing/non-existing user alternatives",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticatorConfig": "create unique user config",
-          "authenticator": "idp-create-user-if-unique",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "ALTERNATIVE",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "Handle Existing Account",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "4deed0f8-02f9-4581-9a91-05bc58fbffba",
-      "alias": "Verify Existing Account by Re-authentication",
-      "description": "Reauthentication of existing account",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "idp-username-password-form",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "CONDITIONAL",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "First broker login - Conditional OTP",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "3c101100-d2dc-4e0d-beea-7bb41ee08849",
-      "alias": "browser",
-      "description": "browser based authentication",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "auth-cookie",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "auth-spnego",
-          "authenticatorFlow": false,
-          "requirement": "DISABLED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "identity-provider-redirector",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 25,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "ALTERNATIVE",
-          "priority": 30,
-          "autheticatorFlow": true,
-          "flowAlias": "forms",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "f38f76db-5399-4231-82e0-bf31cf748d14",
-      "alias": "clients",
-      "description": "Base authentication for clients",
-      "providerId": "client-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "client-secret",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "client-jwt",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "client-secret-jwt",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 30,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "client-x509",
-          "authenticatorFlow": false,
-          "requirement": "ALTERNATIVE",
-          "priority": 40,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "ed29eed7-d490-4985-be20-2444da957182",
-      "alias": "direct grant",
-      "description": "OpenID Connect Resource Owner Grant",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "direct-grant-validate-username",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "direct-grant-validate-password",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "CONDITIONAL",
-          "priority": 30,
-          "autheticatorFlow": true,
-          "flowAlias": "Direct Grant - Conditional OTP",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "e41f4bae-aad9-4821-8597-514e6dc5796c",
-      "alias": "docker auth",
-      "description": "Used by Docker clients to authenticate against the IDP",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "docker-http-basic-authenticator",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "3149ebc7-481d-43bd-9d09-9e66bd9b2b7f",
-      "alias": "first broker login",
-      "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticatorConfig": "review profile config",
-          "authenticator": "idp-review-profile",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "User creation or linking",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "7aaab1d1-5357-4e71-8553-52d5613acf7d",
-      "alias": "forms",
-      "description": "Username, password, otp and other auth forms.",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "auth-username-password-form",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "CONDITIONAL",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "Browser - Conditional OTP",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "c2ffc5bb-568a-4648-bc13-8e7d6a4a53b4",
-      "alias": "http challenge",
-      "description": "An authentication flow based on challenge-response HTTP Authentication Schemes",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "no-cookie-redirect",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": true,
-          "flowAlias": "Authentication Options",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "c6b78806-13ee-4010-b282-a6e527dda66c",
-      "alias": "registration",
-      "description": "registration flow",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "registration-page-form",
-          "authenticatorFlow": true,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": true,
-          "flowAlias": "registration form",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "b5f00ead-4f6f-4454-a925-154c1e9c2cc5",
-      "alias": "registration form",
-      "description": "registration form",
-      "providerId": "form-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "registration-user-creation",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "registration-profile-action",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 40,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "registration-password-action",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 50,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "registration-recaptcha-action",
-          "authenticatorFlow": false,
-          "requirement": "DISABLED",
-          "priority": 60,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "f8370f63-f996-4039-9fbf-86e87da675dd",
-      "alias": "reset credentials",
-      "description": "Reset credentials for a user if they forgot their password or something",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "reset-credentials-choose-user",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "reset-credential-email",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticator": "reset-password",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 30,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        },
-        {
-          "authenticatorFlow": true,
-          "requirement": "CONDITIONAL",
-          "priority": 40,
-          "autheticatorFlow": true,
-          "flowAlias": "Reset - Conditional OTP",
-          "userSetupAllowed": false
-        }
-      ]
-    },
-    {
-      "id": "7f156260-804d-4848-9ea0-347281aea644",
-      "alias": "saml ecp",
-      "description": "SAML ECP Profile Authentication Flow",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "http-basic-authenticator",
-          "authenticatorFlow": false,
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "autheticatorFlow": false,
-          "userSetupAllowed": false
-        }
-      ]
-    }
-  ],
-  "authenticatorConfig": [
-    {
-      "id": "17f2c0cc-8dd8-4774-adcc-cd294cdadac8",
-      "alias": "create unique user config",
-      "config": {
-        "require.password.update.after.registration": "false"
-      }
-    },
-    {
-      "id": "d5be3f6c-d096-4232-88e8-b0f46e608cff",
-      "alias": "review profile config",
-      "config": {
-        "update.profile.on.first.login": "missing"
-      }
-    }
-  ],
-  "requiredActions": [
-    {
-      "alias": "CONFIGURE_TOTP",
-      "name": "Configure OTP",
-      "providerId": "CONFIGURE_TOTP",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 10,
-      "config": {}
-    },
-    {
-      "alias": "TERMS_AND_CONDITIONS",
-      "name": "Terms and Conditions",
-      "providerId": "TERMS_AND_CONDITIONS",
-      "enabled": false,
-      "defaultAction": false,
-      "priority": 20,
-      "config": {}
-    },
-    {
-      "alias": "UPDATE_PASSWORD",
-      "name": "Update Password",
-      "providerId": "UPDATE_PASSWORD",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 30,
-      "config": {}
-    },
-    {
-      "alias": "UPDATE_PROFILE",
-      "name": "Update Profile",
-      "providerId": "UPDATE_PROFILE",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 40,
-      "config": {}
-    },
-    {
-      "alias": "VERIFY_EMAIL",
-      "name": "Verify Email",
-      "providerId": "VERIFY_EMAIL",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 50,
-      "config": {}
-    },
-    {
-      "alias": "delete_account",
-      "name": "Delete Account",
-      "providerId": "delete_account",
-      "enabled": false,
-      "defaultAction": false,
-      "priority": 60,
-      "config": {}
-    },
-    {
-      "alias": "webauthn-register",
-      "name": "Webauthn Register",
-      "providerId": "webauthn-register",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 70,
-      "config": {}
-    },
-    {
-      "alias": "webauthn-register-passwordless",
-      "name": "Webauthn Register Passwordless",
-      "providerId": "webauthn-register-passwordless",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 80,
-      "config": {}
-    },
-    {
-      "alias": "update_user_locale",
-      "name": "Update User Locale",
-      "providerId": "update_user_locale",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 1000,
-      "config": {}
-    }
-  ],
-  "browserFlow": "browser",
-  "registrationFlow": "registration",
-  "directGrantFlow": "direct grant",
-  "resetCredentialsFlow": "reset credentials",
-  "clientAuthenticationFlow": "clients",
-  "dockerAuthenticationFlow": "docker auth",
-  "attributes": {
-    "cibaBackchannelTokenDeliveryMode": "poll",
-    "cibaAuthRequestedUserHint": "login_hint",
-    "oauth2DevicePollingInterval": "5",
-    "clientOfflineSessionMaxLifespan": "0",
-    "clientSessionIdleTimeout": "0",
-    "clientOfflineSessionIdleTimeout": "0",
-    "cibaInterval": "5",
-    "realmReusableOtpCode": "false",
-    "cibaExpiresIn": "120",
-    "oauth2DeviceCodeLifespan": "600",
-    "parRequestUriLifespan": "60",
-    "clientSessionMaxLifespan": "0",
-    "frontendUrl": "",
-    "acr.loa.map": "{}"
-  },
-  "keycloakVersion": "21.0.2",
-  "userManagedAccessAllowed": false,
-  "clientProfiles": {
-    "profiles": []
-  },
-  "clientPolicies": {
-    "policies": []
-  }
+{
+  "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+  "realm" : "dbrepo",
+  "notBefore" : 0,
+  "defaultSignatureAlgorithm" : "RS256",
+  "revokeRefreshToken" : false,
+  "refreshTokenMaxReuse" : 1,
+  "accessTokenLifespan" : 900,
+  "accessTokenLifespanForImplicitFlow" : 900,
+  "ssoSessionIdleTimeout" : 864000,
+  "ssoSessionMaxLifespan" : 2592000,
+  "ssoSessionIdleTimeoutRememberMe" : 0,
+  "ssoSessionMaxLifespanRememberMe" : 0,
+  "offlineSessionIdleTimeout" : 2592000,
+  "offlineSessionMaxLifespanEnabled" : false,
+  "offlineSessionMaxLifespan" : 5184000,
+  "clientSessionIdleTimeout" : 0,
+  "clientSessionMaxLifespan" : 0,
+  "clientOfflineSessionIdleTimeout" : 0,
+  "clientOfflineSessionMaxLifespan" : 0,
+  "accessCodeLifespan" : 60,
+  "accessCodeLifespanUserAction" : 300,
+  "accessCodeLifespanLogin" : 1800,
+  "actionTokenGeneratedByAdminLifespan" : 43200,
+  "actionTokenGeneratedByUserLifespan" : 1800,
+  "oauth2DeviceCodeLifespan" : 600,
+  "oauth2DevicePollingInterval" : 5,
+  "enabled" : true,
+  "sslRequired" : "none",
+  "registrationAllowed" : false,
+  "registrationEmailAsUsername" : false,
+  "rememberMe" : false,
+  "verifyEmail" : true,
+  "loginWithEmailAllowed" : false,
+  "duplicateEmailsAllowed" : false,
+  "resetPasswordAllowed" : false,
+  "editUsernameAllowed" : false,
+  "bruteForceProtected" : false,
+  "permanentLockout" : false,
+  "maxFailureWaitSeconds" : 900,
+  "minimumQuickLoginWaitSeconds" : 60,
+  "waitIncrementSeconds" : 60,
+  "quickLoginCheckMilliSeconds" : 1000,
+  "maxDeltaTimeSeconds" : 43200,
+  "failureFactor" : 30,
+  "roles" : {
+    "realm" : [ {
+      "id" : "48f38342-1e3f-427a-995d-c436eaee65cb",
+      "name" : "default-user-handling",
+      "description" : "${default-user-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-user-theme", "modify-user-information" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "9bb4a8dc-28e0-4645-b62f-cc94425f0cb0",
+      "name" : "default-maintenance-handling",
+      "description" : "${default-maintenance-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-maintenance-message", "find-maintenance-message", "update-maintenance-message", "delete-maintenance-message", "list-maintenance-messages" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7ee1c424-11b0-46a9-b0ed-725e9b7fc40c",
+      "name" : "default-system-roles",
+      "description" : "${default-system-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-database-view-data", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "143ba359-5fa2-451e-8296-43ecf20bb251",
+      "name" : "update-semantic-concept",
+      "description" : "${update-semantic-concept}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "5136d7a3-e3f0-4585-bacd-15cb8a56095c",
+      "name" : "escalated-container-handling",
+      "description" : "${escalated-container-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-container", "delete-container" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b0bc8649-7d84-4dd3-84f0-7f174425babe",
+      "name" : "list-tables",
+      "description" : "${list-tables}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "bfd85d9c-2772-4660-a8f0-cdc0cd8252b3",
+      "name" : "default-database-handling",
+      "description" : "${default-database-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-database-image", "modify-database-owner", "update-database-access", "create-database", "list-databases", "create-database-access", "find-database", "modify-database-visibility", "import-database-data", "delete-database-access", "check-database-access" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "74648f9a-777e-4ef9-b97b-4c5d749d862f",
+      "name" : "update-search-index",
+      "description" : "${update-search-index}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "22492b64-c633-48a0-9678-b28669f2885b",
+      "name" : "execute-semantic-query",
+      "description" : "${execute-semantic-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "4ed919fa-edc5-44e5-9411-607786e4a86d",
+      "name" : "view-table-history",
+      "description" : "${view-table-history}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d89a2881-b642-4abb-b990-196e71372f6b",
+      "name" : "default-table-handling",
+      "description" : "${default-table-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3",
+      "name" : "view-database-view-data",
+      "description" : "${view-database-view-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44",
+      "name" : "create-database-view",
+      "description" : "${create-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a5ffc20e-8b11-498c-9f3b-b5740aec24c7",
+      "name" : "default-semantics-handling",
+      "description" : "${default-semantics-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-semantic-unit", "create-semantic-concept", "execute-semantic-query", "table-semantic-analyse" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe4a01f3-6590-4df6-9ade-5a9c1fae4736",
+      "name" : "create-semantic-unit",
+      "description" : "${create-semantic-unit}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "0e12eedf-545d-4d32-ac4d-2821dcb118b8",
+      "name" : "update-table-statistic",
+      "description" : "${update-table-statistic}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e63e61a2-d852-4ad3-bfb5-92d9ceafef6a",
+      "name" : "escalated-user-handling",
+      "description" : "${escalated-user-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "find-user" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be4e1aba-e276-4241-b6ea-01dce6c52f8b",
+      "name" : "find-container",
+      "description" : "${find-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3a801b48-f3c2-4bc6-aa25-c7a91d5b32a7",
+      "name" : "default-researcher-roles",
+      "description" : "${default-researcher-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3d8104fb-8307-40f0-b4b2-c3e518957110",
+      "name" : "view-table-data",
+      "description" : "${view-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe71b907-7020-44ab-9964-da2b87264582",
+      "name" : "create-database",
+      "description" : "${create-database}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e51b63c2-48dd-4bd6-95fb-d257d21b26ba",
+      "name" : "import-database-data",
+      "description" : "${import-database-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "1f0a9b13-c2b8-474c-bc08-59dbd71835a6",
+      "name" : "modify-database-image",
+      "description" : "${modify-database-image}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a7ad038c-5c06-42fc-951c-15ac09d4df66",
+      "name" : "modify-database-owner",
+      "description" : "${modify-database-owner}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6",
+      "name" : "create-ontology",
+      "description" : "${create-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b60a5694-4099-4f7d-a7e9-4c433e0eb9c9",
+      "name" : "update-semantic-unit",
+      "description" : "${update-semantic-unit}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e9854bbb-4580-4757-b1ae-305934173249",
+      "name" : "create-database-access",
+      "description" : "${create-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "50c604c1-7c6e-43f3-9c43-2398f5eff66e",
+      "name" : "list-databases",
+      "description" : "${list-databases}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b",
+      "name" : "create-container",
+      "description" : "${create-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f4116230-8642-4bb7-bbc8-db9c5c07b558",
+      "name" : "create-maintenance-message",
+      "description" : "${create-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "973f0999-cc70-4b28-9f43-979c470bea8e",
+      "name" : "default-data-steward-roles",
+      "description" : "${default-data-steward-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-identifier-handling", "default-semantics-handling", "escalated-semantics-handling", "default-user-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e1383fb7-d54c-4732-9146-93030eb2ca50",
+      "name" : "escalated-query-handling",
+      "description" : "${escalated-query-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "993b5c69-9eb2-42af-ac28-b4a46c6b61f2",
+      "name" : "find-user",
+      "description" : "${find-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e4cfdc4d-2373-477b-a8df-161db99aba00",
+      "name" : "create-foreign-identifier",
+      "description" : "${create-foreign-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6a5872a5-2b51-415d-ae2d-25a6db4a35df",
+      "name" : "escalated-semantics-handling",
+      "description" : "${escalated-semantics-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "update-semantic-unit", "create-ontology", "update-ontology", "list-ontologies", "delete-ontology", "modify-foreign-table-column-semantics", "update-semantic-concept" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "09147c48-273b-450b-8b11-7ef9b9245244",
+      "name" : "export-table-data",
+      "description" : "${export-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d14af590-60a8-4d75-b864-40ee0165bd7f",
+      "name" : "delete-database-access",
+      "description" : "${delete-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be051d45-cd74-4b13-8a45-f2d3351bd995",
+      "name" : "table-semantic-analyse",
+      "description" : "${table-semantic-analyse}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "272a79a7-e282-4261-8f7d-5d5d1364243a",
+      "name" : "update-maintenance-message",
+      "description" : "${update-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb",
+      "name" : "default-query-handling",
+      "description" : "${default-query-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-database-view-data", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c047d521-cec3-4444-86c4-aef098489b7b",
+      "name" : "delete-maintenance-message",
+      "description" : "${delete-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "88f82262-be80-4d18-9fb4-5529da031f33",
+      "name" : "system",
+      "description" : "${system}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e14ab76b-1c24-484d-ae2d-478b8457edea",
+      "name" : "list-licenses",
+      "description" : "${list-licenses}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d4f29937-3ca0-41e9-9786-2b7b921b6cdd",
+      "name" : "modify-foreign-table-column-semantics",
+      "description" : "${modify-foreign-table-column-semantics}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "8eda9f5c-938c-4915-bed5-6a81a1de15a8",
+      "name" : "list-database-views",
+      "description" : "${list-database-views}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b372f8f7-d203-4293-b991-ad93fb505917",
+      "name" : "escalated-database-handling",
+      "description" : "${escalated-database-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
+      "name" : "default-roles-dbrepo",
+      "description" : "${role_default-roles}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3293799a-82b9-4f47-8f25-1aad2e0222fd",
+      "name" : "find-identifier",
+      "description" : "${find-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "aaa3f804-38a0-4474-b8e9-f1020c4b3f62",
+      "name" : "list-queries",
+      "description" : "${list-queries}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "76e38f7b-99bf-4d12-8d74-1c7d8812f443",
+      "name" : "update-ontology",
+      "description" : "${update-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "11f7973e-d1eb-42cb-a35d-c59dfc122775",
+      "name" : "modify-user-theme",
+      "description" : "${modify-user-theme}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f392bfcb-0be5-4fad-9ce4-8ac6396f176d",
+      "name" : "export-query-data",
+      "description" : "${export-query-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "da493b7e-fb9b-43ca-82a5-e274ad2e6b39",
+      "name" : "find-query",
+      "description" : "${find-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a4d4a788-ebcf-4d32-baed-4a85616ca037",
+      "name" : "escalated-identifier-handling",
+      "description" : "${escalated-identifier-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-foreign-identifier", "modify-identifier-metadata" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "ea38d69d-17b8-4c65-95e8-1c3501b83618",
+      "name" : "default-container-handling",
+      "description" : "${default-container-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "find-container", "list-containers" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "8b8813e0-af07-4d04-a8c1-e3f37192bace",
+      "name" : "publish-identifier",
+      "description" : "${publish-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "47f5eee7-9821-4bf8-b434-0da1f81c3e5a",
+      "name" : "default-broker-handling",
+      "description" : "${default-broker-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "71874bde-64a5-4a69-8685-d8998303a80c",
+      "name" : "delete-table-data",
+      "description" : "${delete-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7c0306fc-3b03-4c64-87d1-9a34f2073977",
+      "name" : "modify-table-column-semantics",
+      "description" : "${modify-table-column-semantics}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "cd0ee04c-4a5e-4035-a11b-f6a1165f7829",
+      "name" : "delete-container",
+      "description" : "${delete-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "67ee39c0-d601-4a67-a0fe-c4f0021d557e",
+      "name" : "list-containers",
+      "description" : "${list-containers}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "795c7bb8-3502-414a-a97b-2ba1cfd6a79c",
+      "name" : "persist-query",
+      "description" : "${persist-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d05e7698-ddf5-4f20-9027-771afb2cc3c7",
+      "name" : "list-identifiers",
+      "description" : "${list-identifiers}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e4bfaf36-9a5d-43e0-9fa3-0f4ea7bad8d0",
+      "name" : "default-developer-roles",
+      "description" : "${default-developer-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-query-handling", "escalated-broker-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-maintenance-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e2cb054e-ea41-4ab0-881b-e6f576f7424e",
+      "name" : "create-semantic-concept",
+      "description" : "${create-semantic-concept}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "feb612cc-96a6-4ed2-aaa5-01f39b25beb5",
+      "name" : "insert-table-data",
+      "description" : "${insert-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a0942e33-441b-4343-9f02-4353d03f7bbb",
+      "name" : "find-database",
+      "description" : "${find-database}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6a0bb740-4448-49be-aee8-6dd183325be5",
+      "name" : "delete-foreign-table",
+      "description" : "${delete-foreign-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7f3652c7-3073-4566-ab63-25385495ebc3",
+      "name" : "modify-database-visibility",
+      "description" : "${modify-database-visibility}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "4a5df51d-f14d-41a2-ad70-6521df5a5b4f",
+      "name" : "offline_access",
+      "description" : "${role_offline-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fd41c4c3-d2f8-4f49-84c7-dba84e9a5575",
+      "name" : "execute-query",
+      "description" : "${execute-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "2963c2bb-b129-4224-b98f-c8eeab8e72d1",
+      "name" : "create-table",
+      "description" : "${create-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "0c487c93-448f-4a82-8b9f-ebd8a0904bf8",
+      "name" : "find-foreign-user",
+      "description" : "${find-foreign-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "cf9735a9-fb70-4cc5-b5f4-75afc4e5654b",
+      "name" : "modify-identifier-metadata",
+      "description" : "${modify-identifier-metadata}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "64c2b8f2-1527-4928-81ea-b2651512d028",
+      "name" : "delete-ontology",
+      "description" : "${delete-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d6e38368-b40f-423b-82e4-e8aa595237c9",
+      "name" : "find-maintenance-message",
+      "description" : "${find-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fd1cc463-3e67-49d9-81b8-2cd90c1daa9c",
+      "name" : "check-database-access",
+      "description" : "${check-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "74013867-e426-46cc-ab98-2f4a9225ad1e",
+      "name" : "find-table",
+      "description" : "${find-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a2cc60df-d280-46c5-a539-92e2aa249b4a",
+      "name" : "modify-user-information",
+      "description" : "${modify-user-information}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c367241f-b5b5-491f-84d5-07fe1bef3877",
+      "name" : "default-identifier-handling",
+      "description" : "${default-identifier-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-identifier", "list-identifiers", "create-identifier", "find-identifier", "publish-identifier" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "ba1ad8f2-39aa-487d-987f-645e8a459559",
+      "name" : "delete-table",
+      "description" : "${delete-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "09f7bdb0-296f-46c8-a3a3-8f9254fb17e4",
+      "name" : "list-maintenance-messages",
+      "description" : "${list-maintenance-messages}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe3bc45c-61c2-4ece-bcaf-d410dc7de501",
+      "name" : "update-database-access",
+      "description" : "${update-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f43e86ed-76de-4ca8-9b5e-c292c9359bfe",
+      "name" : "escalated-broker-handling",
+      "description" : "${escalated-broker-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "916b1e65-f60c-42cd-96e4-5c98ffc1ba3c",
+      "name" : "uma_authorization",
+      "description" : "${role_uma_authorization}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d1afa3ed-bf4f-469a-a061-ad7325fb8d9e",
+      "name" : "delete-database-view",
+      "description" : "${delete-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6f044bad-6651-4408-bffa-20c2d8f92eee",
+      "name" : "create-identifier",
+      "description" : "${create-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be91195a-e30a-4d15-a8da-0aca0a68782f",
+      "name" : "escalated-table-handling",
+      "description" : "${escalated-table-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-foreign-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "98bee7d6-d78c-4e7f-b6a3-3705968b248c",
+      "name" : "list-ontologies",
+      "description" : "${list-ontologies}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "15720c6b-027d-4d53-a0ff-0124bfab7c4c",
+      "name" : "re-execute-query",
+      "description" : "${re-execute-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a9b5181a-8135-41d3-9862-ef80af42211d",
+      "name" : "delete-identifier",
+      "description" : "${delete-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "469c2e63-cda6-48d4-ab8f-eb59a2c69798",
+      "name" : "find-database-view",
+      "description" : "${find-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    } ],
+    "client" : {
+      "realm-management" : [ {
+        "id" : "4628f654-f8f3-483b-8f92-2a7fc5930b14",
+        "name" : "query-realms",
+        "description" : "${role_query-realms}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "95c2cc47-12f5-4d73-8b74-67e270c45ade",
+        "name" : "manage-authorization",
+        "description" : "${role_manage-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "824791f3-c345-42f8-b103-b7e6d7e40114",
+        "name" : "manage-identity-providers",
+        "description" : "${role_manage-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "1f840202-b7e2-4195-bac9-64e64dad2037",
+        "name" : "view-identity-providers",
+        "description" : "${role_view-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "3c32c096-bb13-44c9-a080-d756a48a9ea3",
+        "name" : "query-clients",
+        "description" : "${role_query-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "e4b85a68-7f31-4fcf-89a2-f10d7df358e9",
+        "name" : "view-authorization",
+        "description" : "${role_view-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7d317752-ae56-46f2-a2ce-67c64d1b35f6",
+        "name" : "view-users",
+        "description" : "${role_view-users}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-users", "query-groups" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "28824208-976e-4622-b4d7-3d18efbb46fa",
+        "name" : "realm-admin",
+        "description" : "${role_realm-admin}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "57e846a2-930d-4621-819d-c35086507146",
+        "name" : "manage-users",
+        "description" : "${role_manage-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7fad9cde-bf96-475a-9174-14a87da51f95",
+        "name" : "view-realm",
+        "description" : "${role_view-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "bbcac294-d78a-4ea1-a4bf-0384266d2fe1",
+        "name" : "query-users",
+        "description" : "${role_query-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "480e1437-ab9e-47de-b47a-edc6b6e285de",
+        "name" : "view-clients",
+        "description" : "${role_view-clients}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-clients" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "b9a9a8f5-f91e-4e73-9e88-1cdf42bd49f9",
+        "name" : "create-client",
+        "description" : "${role_create-client}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "4d1397fb-247c-436f-b26f-124cd89afb08",
+        "name" : "query-groups",
+        "description" : "${role_query-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "e31f522b-b283-4ae1-b875-52afcd98b1d2",
+        "name" : "impersonation",
+        "description" : "${role_impersonation}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "51822d02-fa28-4a49-89da-bc534719d8a8",
+        "name" : "manage-clients",
+        "description" : "${role_manage-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "b2743ce5-0ce8-4157-ae00-f693560f0b39",
+        "name" : "manage-events",
+        "description" : "${role_manage-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7ea3d7e0-9bf4-438a-b773-243daf622aaa",
+        "name" : "view-events",
+        "description" : "${role_view-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "fb73f6f5-0ed5-41d0-852c-0eb3b195b15a",
+        "name" : "manage-realm",
+        "description" : "${role_manage-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      } ],
+      "security-admin-console" : [ ],
+      "dbrepo-client" : [ ],
+      "admin-cli" : [ ],
+      "rabbitmq-client" : [ ],
+      "account-console" : [ ],
+      "broker" : [ {
+        "id" : "de0cfd5e-c2fe-4082-ac39-e3b092139a0f",
+        "name" : "read-token",
+        "description" : "${role_read-token}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "88694c91-753d-4c44-9740-ec9ac06bba45",
+        "attributes" : { }
+      } ],
+      "account" : [ {
+        "id" : "acd78c04-eefc-4344-a5b4-3fc83d848936",
+        "name" : "delete-account",
+        "description" : "${role_delete-account}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "939be844-8c49-45b3-9ca1-4b10a454b346",
+        "name" : "view-profile",
+        "description" : "${role_view-profile}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "e52fdf00-3e73-4c17-bc1c-643493710a6b",
+        "name" : "view-applications",
+        "description" : "${role_view-applications}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "b02a822e-a708-420a-bddc-1a315033fd7c",
+        "name" : "view-consent",
+        "description" : "${role_view-consent}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "c590e5f5-2cbf-4151-b1dc-96c454f1f654",
+        "name" : "view-groups",
+        "description" : "${role_view-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "15974151-6c13-426b-8cc3-7683dd1311e1",
+        "name" : "manage-account-links",
+        "description" : "${role_manage-account-links}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "c12d8d94-c2df-498e-bbe4-2f934a83ae92",
+        "name" : "manage-consent",
+        "description" : "${role_manage-consent}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "view-consent" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "55f85811-bded-4d6b-8f7b-45844b963875",
+        "name" : "manage-account",
+        "description" : "${role_manage-account}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "manage-account-links" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      } ]
+    }
+  },
+  "groups" : [ {
+    "id" : "f2ce17fe-7b15-47a4-bbf8-86f415298fa9",
+    "name" : "data-stewards",
+    "path" : "/data-stewards",
+    "attributes" : { },
+    "realmRoles" : [ "default-data-steward-roles" ],
+    "clientRoles" : { },
+    "subGroups" : [ ]
+  }, {
+    "id" : "124d9888-0b6e-46aa-8225-077dcedaf16e",
+    "name" : "developers",
+    "path" : "/developers",
+    "attributes" : { },
+    "realmRoles" : [ "default-developer-roles" ],
+    "clientRoles" : { },
+    "subGroups" : [ ]
+  }, {
+    "id" : "f467c38e-9041-4faa-ae0b-39cec65ff4db",
+    "name" : "researchers",
+    "path" : "/researchers",
+    "attributes" : { },
+    "realmRoles" : [ "default-researcher-roles" ],
+    "clientRoles" : { },
+    "subGroups" : [ ]
+  }, {
+    "id" : "2b9f94b4-d434-4a98-8eab-25678cfee983",
+    "name" : "system",
+    "path" : "/system",
+    "attributes" : { },
+    "realmRoles" : [ "default-system-roles" ],
+    "clientRoles" : { },
+    "subGroups" : [ ]
+  } ],
+  "defaultRole" : {
+    "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
+    "name" : "default-roles-dbrepo",
+    "description" : "${role_default-roles}",
+    "composite" : false,
+    "clientRole" : false,
+    "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0"
+  },
+  "defaultGroups" : [ "/researchers" ],
+  "requiredCredentials" : [ "password" ],
+  "otpPolicyType" : "totp",
+  "otpPolicyAlgorithm" : "HmacSHA1",
+  "otpPolicyInitialCounter" : 0,
+  "otpPolicyDigits" : 6,
+  "otpPolicyLookAheadWindow" : 1,
+  "otpPolicyPeriod" : 30,
+  "otpPolicyCodeReusable" : false,
+  "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName" ],
+  "webAuthnPolicyRpEntityName" : "keycloak",
+  "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyRpId" : "",
+  "webAuthnPolicyAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyRequireResidentKey" : "not specified",
+  "webAuthnPolicyUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyCreateTimeout" : 0,
+  "webAuthnPolicyAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyAcceptableAaguids" : [ ],
+  "webAuthnPolicyPasswordlessRpEntityName" : "keycloak",
+  "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyPasswordlessRpId" : "",
+  "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified",
+  "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyPasswordlessCreateTimeout" : 0,
+  "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ],
+  "scopeMappings" : [ {
+    "clientScope" : "rabbitmq.tag:administrator",
+    "roles" : [ "escalated-broker-handling" ]
+  }, {
+    "clientScope" : "rabbitmq.tag:management",
+    "roles" : [ "default-broker-handling" ]
+  } ],
+  "clientScopeMappings" : {
+    "account" : [ {
+      "client" : "account-console",
+      "roles" : [ "manage-account", "view-groups" ]
+    } ]
+  },
+  "clients" : [ {
+    "id" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+    "clientId" : "account",
+    "name" : "${client_account}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/dbrepo/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/realms/dbrepo/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96",
+    "clientId" : "account-console",
+    "name" : "${client_account-console}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/dbrepo/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/realms/dbrepo/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+",
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "22d90d9c-9881-474c-8dfd-a62c808a9f1c",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6",
+    "clientId" : "admin-cli",
+    "name" : "${client_admin-cli}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : false,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "88694c91-753d-4c44-9740-ec9ac06bba45",
+    "clientId" : "broker",
+    "name" : "${client_broker}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "6b7ef364-4132-4831-b4e2-b6e9e9dc63ee",
+    "clientId" : "dbrepo-client",
+    "name" : "${dbrepo-client}",
+    "description" : "",
+    "rootUrl" : "",
+    "adminUrl" : "",
+    "baseUrl" : "",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : true,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG",
+    "redirectUris" : [ "*" ],
+    "webOrigins" : [ "*" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "oidc.ciba.grant.enabled" : "false",
+      "client.secret.creation.time" : "1680085365",
+      "backchannel.logout.session.required" : "true",
+      "post.logout.redirect.uris" : "*",
+      "oauth2.device.authorization.grant.enabled" : "false",
+      "backchannel.logout.revoke.offline.tokens" : "false"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : true,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
+      "name" : "preferred_username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "claim.value" : "dbrepo",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "access.tokenResponse.claim" : "false"
+      }
+    }, {
+      "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
+      "name" : "uid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "aggregate.attrs" : "false",
+        "multivalued" : "false",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "LDAP_ID",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "uid"
+      }
+    } ],
+    "defaultClientScopes" : [ "roles", "attributes" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+  }, {
+    "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
+    "clientId" : "rabbitmq-client",
+    "name" : "${rabbitmq-client}",
+    "description" : "",
+    "rootUrl" : "",
+    "adminUrl" : "",
+    "baseUrl" : "",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "JEC2FexxrX4N65fLeDGukAl6R3Lc9y0u",
+    "redirectUris" : [ "*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "oidc.ciba.grant.enabled" : "false",
+      "client.secret.creation.time" : "1680000860",
+      "backchannel.logout.session.required" : "true",
+      "post.logout.redirect.uris" : "*",
+      "oauth2.device.authorization.grant.enabled" : "false",
+      "backchannel.logout.revoke.offline.tokens" : "false"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "01a937ed-f0e8-4137-80f3-3be3c447f7fb",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "false",
+        "user.attribute" : "username",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
+      "name" : "Audience",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "access.tokenResponse.claim" : "false"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+  }, {
+    "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+    "clientId" : "realm-management",
+    "name" : "${client_realm-management}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "f205c451-9524-4380-acc3-947f7ecb6b7c",
+    "clientId" : "security-admin-console",
+    "name" : "${client_security-admin-console}",
+    "rootUrl" : "${authAdminUrl}",
+    "baseUrl" : "/admin/dbrepo/console/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/admin/dbrepo/console/*" ],
+    "webOrigins" : [ "+" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+",
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "c4d54410-3f22-4259-9571-94da2c43b752",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  } ],
+  "clientScopes" : [ {
+    "id" : "69f4ecf0-4165-49ab-bf0d-38409b15b706",
+    "name" : "rabbitmq.tag:administrator",
+    "description" : "administrator",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "7f6e9b44-e2eb-417d-b0fe-db820c9a6564",
+    "name" : "email",
+    "description" : "OpenID Connect built-in scope: email",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${emailScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
+      "name" : "email verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "emailVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email_verified",
+        "jsonType.label" : "boolean"
+      }
+    }, {
+      "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
+      "name" : "email",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "email",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "b9da268f-6745-49dc-a764-3c54e385accc",
+    "name" : "profile",
+    "description" : "OpenID Connect built-in scope: profile",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${profileScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
+      "name" : "gender",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "gender",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "gender",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
+      "name" : "birthdate",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "birthdate",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "birthdate",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
+      "name" : "full name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-full-name-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "f757d8ec-e181-429c-9287-9ad0600b061f",
+      "name" : "profile",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "profile",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "profile",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
+      "name" : "updated at",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "updatedAt",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "updated_at",
+        "jsonType.label" : "long"
+      }
+    }, {
+      "id" : "841ea785-26ab-429a-a420-09ce3948924d",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
+      "name" : "website",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "website",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "website",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "475f071d-5149-4379-b928-76482f5f519c",
+      "name" : "zoneinfo",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "zoneinfo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "zoneinfo",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
+      "name" : "middle name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "middleName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "middle_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
+      "name" : "picture",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "picture",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "picture",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
+      "name" : "nickname",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "nickname",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "nickname",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "627fa054-08eb-4206-af71-9e838e984b8b",
+    "name" : "microprofile-jwt",
+    "description" : "Microprofile - JWT built-in scope",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "e6cc53e5-5d7e-468e-88c8-0737dd3dc759",
+      "name" : "groups",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "multivalued" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "groups",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "83b4444c-10fc-44e8-a0c0-0c1da1f9bba3",
+      "name" : "upn",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "upn",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "4122ff9e-ad3c-4142-afc6-9aefdecfc86d",
+    "name" : "role_list",
+    "description" : "SAML role list",
+    "protocol" : "saml",
+    "attributes" : {
+      "consent.screen.text" : "${samlRoleListScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb0747fa-c008-4af3-93be-e7739650ebd5",
+      "name" : "role list",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-role-list-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "single" : "false",
+        "attribute.nameformat" : "Basic",
+        "attribute.name" : "Role"
+      }
+    } ]
+  }, {
+    "id" : "2e76447d-fbe7-4fa7-a16c-54a381b960ae",
+    "name" : "rabbitmq.configure:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "52aad832-c6c4-49df-8a04-6ad4a406fdfa",
+    "name" : "phone",
+    "description" : "OpenID Connect built-in scope: phone",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${phoneScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
+      "name" : "phone number",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumber",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
+      "name" : "phone number verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumberVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number_verified",
+        "jsonType.label" : "boolean"
+      }
+    } ]
+  }, {
+    "id" : "f64d64e8-57ce-4eb2-b99e-9f02fdbd99f9",
+    "name" : "web-origins",
+    "description" : "OpenID Connect scope for add allowed web origins to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
+      "name" : "allowed web origins",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-allowed-origins-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ]
+  }, {
+    "id" : "55341d34-0086-4173-ae61-d9b175b179d8",
+    "name" : "acr",
+    "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "58ea3217-0fff-4207-9d08-919f5493b629",
+      "name" : "acr loa level",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-acr-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    } ]
+  }, {
+    "id" : "a02c2c38-923c-46ec-9899-321412b388e5",
+    "name" : "attributes",
+    "description" : "User Attributes",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "78c461c1-f3f9-4d10-8835-097f13bdcd60",
+      "name" : "Theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "aggregate.attrs" : "false",
+        "multivalued" : "false",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "theme_dark",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "attributes.theme_dark"
+      }
+    } ]
+  }, {
+    "id" : "06062e22-89c0-4e1d-a25b-2483903b02d5",
+    "name" : "rabbitmq.write:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "db63e03b-7918-492f-997b-f2dda98f3b39",
+    "name" : "rabbitmq.tag:management",
+    "description" : "management",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
+    "name" : "offline_access",
+    "description" : "OpenID Connect built-in scope: offline_access",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "consent.screen.text" : "${offlineAccessScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    }
+  }, {
+    "id" : "425abf4a-2ee2-431d-aa92-e373a36fe556",
+    "name" : "address",
+    "description" : "OpenID Connect built-in scope: address",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${addressScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
+      "name" : "address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-address-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute.formatted" : "formatted",
+        "user.attribute.country" : "country",
+        "user.attribute.postal_code" : "postal_code",
+        "userinfo.token.claim" : "true",
+        "user.attribute.street" : "street",
+        "id.token.claim" : "true",
+        "user.attribute.region" : "region",
+        "access.token.claim" : "true",
+        "user.attribute.locality" : "locality"
+      }
+    } ]
+  }, {
+    "id" : "c96f0b73-ea79-4b46-93ef-d1092297f855",
+    "name" : "rabbitmq.read:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc",
+    "name" : "roles",
+    "description" : "OpenID Connect scope for add user roles to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${rolesScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    }, {
+      "id" : "2defedf5-9af3-4531-822c-a879dedcd29d",
+      "name" : "realm roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "realm_access.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    }, {
+      "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
+      "name" : "client roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-client-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "resource_access.${client_id}.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    } ]
+  } ],
+  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ],
+  "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ],
+  "browserSecurityHeaders" : {
+    "contentSecurityPolicyReportOnly" : "",
+    "xContentTypeOptions" : "nosniff",
+    "xRobotsTag" : "none",
+    "xFrameOptions" : "SAMEORIGIN",
+    "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+    "xXSSProtection" : "1; mode=block",
+    "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
+  },
+  "smtpServer" : { },
+  "eventsEnabled" : false,
+  "eventsListeners" : [ "jboss-logging" ],
+  "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
+  "adminEventsEnabled" : false,
+  "adminEventsDetailsEnabled" : false,
+  "identityProviders" : [ ],
+  "identityProviderMappers" : [ ],
+  "components" : {
+    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ {
+      "id" : "4d3f9f14-f5d2-4b0c-8ea7-e6d078aa2191",
+      "name" : "Max Clients Limit",
+      "providerId" : "max-clients",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "max-clients" : [ "200" ]
+      }
+    }, {
+      "id" : "f35bce67-1e75-408b-b065-52183368d4fd",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
+      "name" : "Trusted Hosts",
+      "providerId" : "trusted-hosts",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "host-sending-registration-request-must-match" : [ "true" ],
+        "client-uris-must-match" : [ "true" ]
+      }
+    }, {
+      "id" : "f565cb47-3bcf-4078-8f94-eb4179c375b8",
+      "name" : "Full Scope Disabled",
+      "providerId" : "scope",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "0efa669d-1017-4b4a-82e1-c2eaf72de2c9",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "528fb423-d66e-472e-9120-1f03ba9e0f18",
+      "name" : "Consent Required",
+      "providerId" : "consent-required",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "104ec5a9-025b-4c44-8ac0-82d22887ca3e",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper" ]
+      }
+    }, {
+      "id" : "3ab11d74-5e76-408a-b85a-26bf8950f979",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ]
+      }
+    } ],
+    "org.keycloak.keys.KeyProvider" : [ {
+      "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30",
+      "name" : "aes-generated",
+      "providerId" : "aes-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "6dc4834f-a1de-4cfe-a29d-e84ac8e9b1a8" ],
+        "secret" : [ "HpuzG_jWYKwypLeoPEMC4A" ],
+        "priority" : [ "100" ]
+      }
+    }, {
+      "id" : "bd7945cf-6d35-4e03-9c3a-197f2dc76973",
+      "name" : "hmac-generated",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "c8500166-5cc4-4085-ad0f-853c3b0b0233" ],
+        "secret" : [ "TI3xg__G2Qy8C47DracpYir2X4ItQZSrhgr5KSlwRNISDbBqZ-ky3OcAyokSXMcpweSOaCPvbivpvzJNklUBvw" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS256" ]
+      }
+    }, {
+      "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
+      "name" : "rsa-enc-generated",
+      "providerId" : "rsa-enc-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEowIBAAKCAQEA3b1tNLfcjFLUw9UShVDNf+ZD8sQqb4YBaIXcSJTX/zDQUPiCp176BBGI3s4VplDArnOW+LumozmKogeoHEnGEIDW8ovgK5uMU9tSA2p0qqGBUMOdR8YATTIfCJe7qGiiuGa3WZy3sQLM70SuRzx02YU8gvUcvl2Js4KyqAziOUX/w3Wa59H9jjGNUXYyqaPWJp73eHzbVYWySzyLG22mVlcUtBx5siL5T2/Xu0p9z4l7/bapwwmOVi1ZrcHjbEAwdGEiSMGI/uWqAF+r1BRpmJLR7HNXcL3eK4/56VYLaiwSejfyYeRFMITEn/UxGYhcXZ5xMUUCG0TxjBhLYpTBuwIDAQABAoIBAA4dwebcxkrH99Poa8+WkiE7JgaS9sahx9OBI2xwJANoIU2TpzGuNLQZ76uLgB+rPWZTD9Xm5a1iJjwOyQ9/937TzPCk91D0tpgcusRikb8jx/6TGB9acL4kBjYUVCCHr3BA2G75MKKGtJ2OMvAbCQSosZj+r2VDwYFEPUkV2jheE5JHSBkwyIRrus3JCwu8gu5fyCg9z8ljcxJxI5HIsi4v8Z21aCw/cLj7h5cMt44wCjQz4rOfYNBEFeHDtlfR1QtWKgjm4ZHHJbKrzf9b2kQXclziceEbSM0tYbROEXKi+s0Zc+z3HEG89vv0vfN400clmzzIAijKY6gg3pPRWdECgYEA+lnWYbSlXDMNYx6RBXm1RnlMUYIm4oy4/9ljgnoGJ6WCn3SjFkgaDtiKfGIG1BSB85r04pAPANgcWHf5tWDnq0ARvBVG0BX2bKd++7B3D4d3CRYKCwm88SslJXv9dfHVhq4+zViFPiUWwT20A72jCuUCvL88y5fh/YBecfdh+jECgYEA4r5RD0NB9dMaeg5/jk/GEHIo4Z9KLc6FrSoOFo2xFkPOy1sgDpDOiNtypuWvniO7k7Ose3DS3hlfTMsKzIW/CgQJ20+Y4cvBWDaOsRxfjj7w3d+jH5OSJdKKSzTrgLKc9ZhlRzVXy0J0hipIA6HG5kdVdLXmh85ITmf1CbJhE6sCgYBjPVeBNbXTHZ2x6/z62aslO5IoQVqetb/kE82hfDOSZcao5Ph9Lam+ttH2ynkAevykj4mBgi+gWwqpey2uW7KaLPSaxShj9kDQA3mP1fzsV/u0y1rB02Nlin/YIxVvOqU1FT9p8SwoXVVu1sHUNck62VtDbN9xqUx5S/ikXrclEQKBgQCoTssOwEcK+Vty9KYcdfy4onTUHZBLdjxl8Iyqkxy7QTQUYRznkvesQPDXEDGO+kk3dyx2KKZt9Hl4IFNww2quPZcvcuMx4DQxjbXXpA8OIIxcta95NepLJwA+mRai3nKCH1A2TlNP7pFeMa5o+8IPly3Ix2lKr4Wepa4PN5i1pwKBgCZ1QP6XAOERl9NznNmU0rXVcvYNP4PIIfQWfvGsldZ4QKkmjjAGiS0/oYqdWs+UDRZyCRChaVjDXO9fk0PEG5OGKAj9nyiYCT/M8xtJ3UeP5ffZZvJ/vnye3QdDIo1e38ZzsWwJHmLYw7fRqY9W5Vxo0Vsy22U3CJY70KTxVdTy" ],
+        "keyUse" : [ "ENC" ],
+        "certificate" : [ "MIICmzCCAYMCBgGG3GWycDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdvW00t9yMUtTD1RKFUM1/5kPyxCpvhgFohdxIlNf/MNBQ+IKnXvoEEYjezhWmUMCuc5b4u6ajOYqiB6gcScYQgNbyi+Arm4xT21IDanSqoYFQw51HxgBNMh8Il7uoaKK4ZrdZnLexAszvRK5HPHTZhTyC9Ry+XYmzgrKoDOI5Rf/DdZrn0f2OMY1RdjKpo9Ymnvd4fNtVhbJLPIsbbaZWVxS0HHmyIvlPb9e7Sn3PiXv9tqnDCY5WLVmtweNsQDB0YSJIwYj+5aoAX6vUFGmYktHsc1dwvd4rj/npVgtqLBJ6N/Jh5EUwhMSf9TEZiFxdnnExRQIbRPGMGEtilMG7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAK3kQ1VkQrzvSWvmXmazmNoA1ZiPzRDs1XhGUWxgsxzgPylr3dGBuqQbKvgnLUBQLSqlJHpI4fZflHswu1qrvVZYtekPcGef4WhcKAu2i1RwxrKa6RJQ1tRbrLuVYCzPv5p/DWgltWVn88aoLnqQn0SK/0PB/o4a4Cm7Kq2ZzCr1dACBr06LvOHsc7249OySmbG4HH+pLK6jVURhZ9VaObqAHe2FJBVVoIzURbdiRRURqumrIvbnpeaU1aFyg6ED5wTnXvmMPmVPt9F79mcB33bASO5wyu00X8t1hyN2Show2l2vxLACGUzVkTQt15s7uDLKE7qLmKSR3EuSGXWv3wA=" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "RSA-OAEP" ]
+      }
+    }, {
+      "id" : "2293ff99-3c6d-46d1-8635-5e679d5b134a",
+      "name" : "rsa-generated",
+      "providerId" : "rsa-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEpAIBAAKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQABAoIBADNcMt6hAHub4JTAYS6Mra0EPRBO2XhWmACBrv3+8ETClXd5475KPLDewgRVtlmtbwU8G8awUXESQgPS9lfiqvQhPreA3cHlm6oP2WMKOEtakr2s8I+frsTBLCo0Ini9RaSzjoVVgS0zofyhASKi+T970MafSj5P3XNb8YBFdXgoYDiA7FXLH6a/+m7LScL+wGcFMAAeYESxZbMQLfH3v8L+4EcTraiwjLG17ZdlF3dpybMyUSse6ZQ/PdlyvBuzzLXhN6Ce2gd9ATfS+YWTzo7Yf+GU+ex5bIpVOfHqtuM/hyq7YGKENClsXwNZIAoFnvGCbvECAfgyapVrD30IfykCgYEA0rgsSZ82pxT40NxwgBD1g9lbNVBKXphRB/3S078qusUzJjT7AldEj4imGPhAbI7bI8gAeWJsp1XJWkjM8ktaVrh+NQl7p8e9OPh0pQF/5Bdg8ajbjXESpjnaU66pVYRQy/d+jNli/YRAHX5RUfsBl+6W4+WSVMGmKBiqJsur+ecCgYEAz1YVXClcmUnyZem5B+2E9noIzjF6ROE+jIb6rawM85P3Xd0lXtECQavtxw+Qk7I32qOwrxl1UpK2foVel3pazi+4OpMfmqtYGenRP1Zk1cZwrDo0cIemTDGjj3kJ8tYn12CGolFQpJZgK6OHzvG0tOxI5VZgjIViWNPe1PGWXtUCgYEAxXGNDe8BZs1f11S2lUlOw5yGug3hoYFXbAWJ5p7Ziuf8ZXB/QlJDC7se54a11wKEk6Jzz0lKRgE8CjzszJuOqnN0zn10QGIIC7nCklo1W6QMUmPGVWH994N976tZP6gbjQL6sT+AYcvpx7j0ubxYYeRNvnz+ACzzY964kGGHY0ECgYEAumlwPPNnMN7+VEjGNm2D7UMdJZ3wi3tkjF5ThdA5uMohTsAk+FG80KSu3RmOaGyEsUwY7+VYyYvlDm4E9PZqLBVVczyR3rMNPAcwPd0EPfvzk7WlLkOX7ct3fehaXH3VRlyfz9KCSeh1wOZ/lT1VtpD2nVOC7PSDzs92+kfXZZ0CgYAnrD1y4skgXkdwolZ3unn3EFyGm2d+X5aMTHwQPdWxqoNIAl/9wdghlzihwnPhhsxq1WzlxuC3V2IMrNPtRx70Mi+FbSmR5m4Xx5RptgMtMlwno+L40PzNJgMjHGjt0wcx3Vel8wuohDtnqMyS7P5nG1/TQx0Cyzwn7QOXlNpgbQ==" ],
+        "keyUse" : [ "SIG" ],
+        "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ],
+        "priority" : [ "100" ]
+      }
+    } ]
+  },
+  "internationalizationEnabled" : false,
+  "supportedLocales" : [ ],
+  "authenticationFlows" : [ {
+    "id" : "88e5d526-2298-413c-a904-133ad839d47f",
+    "alias" : "Account verification options",
+    "description" : "Method with which to verity the existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-email-verification",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Verify Existing Account by Re-authentication",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "bc0b483f-4a3f-4c15-bf65-b26f5320e6c9",
+    "alias" : "Authentication Options",
+    "description" : "Authentication options.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "basic-auth",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "basic-auth-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-spnego",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "a690c715-fbae-4c20-b680-bd4010718761",
+    "alias" : "Browser - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad",
+    "alias" : "Direct Grant - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "direct-grant-validate-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515",
+    "alias" : "First broker login - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523",
+    "alias" : "Handle Existing Account",
+    "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-confirm-link",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Account verification options",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "088f4051-36ab-4952-a4f2-4ba53c408083",
+    "alias" : "Reset - Conditional OTP",
+    "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4",
+    "alias" : "User creation or linking",
+    "description" : "Flow for the existing/non-existing user alternatives",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "create unique user config",
+      "authenticator" : "idp-create-user-if-unique",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Handle Existing Account",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4",
+    "alias" : "Verify Existing Account by Re-authentication",
+    "description" : "Reauthentication of existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-username-password-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "First broker login - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c",
+    "alias" : "browser",
+    "description" : "browser based authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "auth-cookie",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-spnego",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "identity-provider-redirector",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 25,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "autheticatorFlow" : true,
+      "flowAlias" : "forms",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d",
+    "alias" : "clients",
+    "description" : "Base authentication for clients",
+    "providerId" : "client-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "client-secret",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-jwt",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-secret-jwt",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-x509",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 40,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63",
+    "alias" : "direct grant",
+    "description" : "OpenID Connect Resource Owner Grant",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "direct-grant-validate-username",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "direct-grant-validate-password",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 30,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Direct Grant - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781",
+    "alias" : "docker auth",
+    "description" : "Used by Docker clients to authenticate against the IDP",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "docker-http-basic-authenticator",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43",
+    "alias" : "first broker login",
+    "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "review profile config",
+      "authenticator" : "idp-review-profile",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "User creation or linking",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8",
+    "alias" : "forms",
+    "description" : "Username, password, otp and other auth forms.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "auth-username-password-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Browser - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "b8f1f963-6813-4875-bae8-ce48a813763b",
+    "alias" : "http challenge",
+    "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "no-cookie-redirect",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Authentication Options",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914",
+    "alias" : "registration",
+    "description" : "registration flow",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "registration-page-form",
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : true,
+      "flowAlias" : "registration form",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "d62c8dd6-633c-408a-aa99-43071510efb4",
+    "alias" : "registration form",
+    "description" : "registration form",
+    "providerId" : "form-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "registration-user-creation",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-profile-action",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 40,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-password-action",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 50,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-recaptcha-action",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 60,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb",
+    "alias" : "reset credentials",
+    "description" : "Reset credentials for a user if they forgot their password or something",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "reset-credentials-choose-user",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-credential-email",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-password",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 40,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Reset - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "389c1c37-e8af-4610-a507-e1257f55b954",
+    "alias" : "saml ecp",
+    "description" : "SAML ECP Profile Authentication Flow",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "http-basic-authenticator",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  } ],
+  "authenticatorConfig" : [ {
+    "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4",
+    "alias" : "create unique user config",
+    "config" : {
+      "require.password.update.after.registration" : "false"
+    }
+  }, {
+    "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d",
+    "alias" : "review profile config",
+    "config" : {
+      "update.profile.on.first.login" : "missing"
+    }
+  } ],
+  "requiredActions" : [ {
+    "alias" : "CONFIGURE_TOTP",
+    "name" : "Configure OTP",
+    "providerId" : "CONFIGURE_TOTP",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 10,
+    "config" : { }
+  }, {
+    "alias" : "TERMS_AND_CONDITIONS",
+    "name" : "Terms and Conditions",
+    "providerId" : "TERMS_AND_CONDITIONS",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 20,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PASSWORD",
+    "name" : "Update Password",
+    "providerId" : "UPDATE_PASSWORD",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 30,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PROFILE",
+    "name" : "Update Profile",
+    "providerId" : "UPDATE_PROFILE",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 40,
+    "config" : { }
+  }, {
+    "alias" : "VERIFY_EMAIL",
+    "name" : "Verify Email",
+    "providerId" : "VERIFY_EMAIL",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 50,
+    "config" : { }
+  }, {
+    "alias" : "delete_account",
+    "name" : "Delete Account",
+    "providerId" : "delete_account",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 60,
+    "config" : { }
+  }, {
+    "alias" : "webauthn-register",
+    "name" : "Webauthn Register",
+    "providerId" : "webauthn-register",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 70,
+    "config" : { }
+  }, {
+    "alias" : "webauthn-register-passwordless",
+    "name" : "Webauthn Register Passwordless",
+    "providerId" : "webauthn-register-passwordless",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 80,
+    "config" : { }
+  }, {
+    "alias" : "update_user_locale",
+    "name" : "Update User Locale",
+    "providerId" : "update_user_locale",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 1000,
+    "config" : { }
+  } ],
+  "browserFlow" : "browser",
+  "registrationFlow" : "registration",
+  "directGrantFlow" : "direct grant",
+  "resetCredentialsFlow" : "reset credentials",
+  "clientAuthenticationFlow" : "clients",
+  "dockerAuthenticationFlow" : "docker auth",
+  "attributes" : {
+    "cibaBackchannelTokenDeliveryMode" : "poll",
+    "cibaAuthRequestedUserHint" : "login_hint",
+    "clientOfflineSessionMaxLifespan" : "0",
+    "oauth2DevicePollingInterval" : "5",
+    "clientSessionIdleTimeout" : "0",
+    "actionTokenGeneratedByUserLifespan-execute-actions" : "",
+    "actionTokenGeneratedByUserLifespan-verify-email" : "",
+    "clientOfflineSessionIdleTimeout" : "0",
+    "actionTokenGeneratedByUserLifespan-reset-credentials" : "",
+    "cibaInterval" : "5",
+    "realmReusableOtpCode" : "false",
+    "cibaExpiresIn" : "120",
+    "oauth2DeviceCodeLifespan" : "600",
+    "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
+    "parRequestUriLifespan" : "60",
+    "clientSessionMaxLifespan" : "0",
+    "shortVerificationUri" : ""
+  },
+  "keycloakVersion" : "21.0.2",
+  "userManagedAccessAllowed" : false,
+  "clientProfiles" : {
+    "profiles" : [ ]
+  },
+  "clientPolicies" : {
+    "policies" : [ ]
+  }
 }
\ No newline at end of file
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
index 1f8f3ced9d21bb27eccb4c9f7475bee2e5a6bc5f..80fdd15f1daff7625508eb8d46d9b54332a5150f 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
@@ -1,8 +1,6 @@
 package at.tuwien.auth;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.user.UserDetailsDto;
-import at.tuwien.config.GatewayConfig;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import jakarta.servlet.ServletException;
@@ -13,40 +11,24 @@ import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.stereotype.Component;
 
-import java.util.List;
-
 @Log4j2
 @Component
 public class BasicAuthenticationProvider implements AuthenticationManager {
 
-    private final GatewayConfig gatewayConfig;
     private final AuthTokenFilter authTokenFilter;
     private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public BasicAuthenticationProvider(GatewayConfig gatewayConfig, AuthTokenFilter authTokenFilter,
-                                       KeycloakGateway keycloakGateway) {
-        this.gatewayConfig = gatewayConfig;
+    public BasicAuthenticationProvider(AuthTokenFilter authTokenFilter, KeycloakGateway keycloakGateway) {
         this.authTokenFilter = authTokenFilter;
         this.keycloakGateway = keycloakGateway;
     }
 
     @Override
     public Authentication authenticate(Authentication auth) throws AuthenticationException {
-        if (auth.getName().equals(gatewayConfig.getAdminUsername())
-                && auth.getCredentials().toString().equals(gatewayConfig.getAdminPassword())) {
-            log.trace("current user is {}: skip authentication", gatewayConfig.getAdminUsername());
-            final UserDetails userDetails = UserDetailsDto.builder()
-                    .username(auth.getName())
-                    .authorities(List.of(new SimpleGrantedAuthority("admin")))
-                    .build();
-            return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
-        }
-        log.trace("current user is {}: begin authentication", auth.getName());
         try {
             final TokenDto tokenDto = keycloakGateway.obtainUserToken(auth.getName(), auth.getCredentials().toString());
             final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..835b7245d1ef2ca017375990dd77c20693f3ef6f
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
@@ -0,0 +1,47 @@
+package at.tuwien.auth;
+
+import at.tuwien.api.keycloak.TokenDto;
+import at.tuwien.config.GatewayConfig;
+import at.tuwien.exception.AccountNotSetupException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.CredentialsInvalidException;
+import at.tuwien.gateway.KeycloakGateway;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+import java.util.List;
+
+@Log4j2
+public class InternalRequestInterceptor implements ClientHttpRequestInterceptor {
+
+    private final GatewayConfig gatewayConfig;
+    private final KeycloakGateway keycloakGateway;
+
+    public InternalRequestInterceptor(GatewayConfig gatewayConfig, KeycloakGateway keycloakGateway) {
+        this.gatewayConfig = gatewayConfig;
+        this.keycloakGateway = keycloakGateway;
+    }
+
+    @Override
+    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
+            throws IOException {
+        final HttpHeaders headers = request.getHeaders();
+        headers.setAccept(List.of(MediaType.APPLICATION_JSON));
+        try {
+            final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(),
+                    gatewayConfig.getSystemPassword());
+            headers.setBearerAuth(token.getAccessToken());
+            log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername());
+            return execution.execute(request, body);
+        } catch (AuthServiceConnectionException | CredentialsInvalidException | AccountNotSetupException e) {
+            log.error("Failed to obtain token for internal user: {}", gatewayConfig.getSystemUsername());
+            throw new IOException("Failed to obtain token for internal user", e);
+        }
+    }
+}
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
index c64fc52282af3dc8fb3f6bc075ad080e5f162f0c..d7fc192bb6c795fb9425ff99c318f2027fe8ff8d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -1,24 +1,15 @@
 package at.tuwien.config;
 
+import at.tuwien.auth.InternalRequestInterceptor;
+import at.tuwien.gateway.KeycloakGateway;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpRequest;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.ClientHttpRequestExecution;
-import org.springframework.http.client.ClientHttpRequestInterceptor;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.http.client.support.BasicAuthenticationInterceptor;
+import org.springframework.context.annotation.*;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.DefaultUriBuilderFactory;
 
-import java.io.IOException;
-import java.util.List;
-
 @Log4j2
 @Getter
 @Configuration
@@ -42,25 +33,26 @@ public class GatewayConfig {
     @Value("${spring.rabbitmq.password}")
     private String brokerPassword;
 
-    @Value("${dbrepo.admin.username}")
-    private String adminUsername;
+    @Value("${dbrepo.system.username}")
+    private String systemUsername;
+
+    @Value("${dbrepo.system.password}")
+    private String systemPassword;
 
-    @Value("${dbrepo.admin.password}")
-    private String adminPassword;
+    private final KeycloakGateway keycloakGateway;
 
-    @Primary
-    public RestTemplate restTemplate() {
-        return new RestTemplate();
+    @Autowired
+    public GatewayConfig(KeycloakGateway keycloakGateway) {
+        this.keycloakGateway = keycloakGateway;
     }
 
+    @Profile("!junit")
     @Bean("brokerRestTemplate")
     public RestTemplate brokerRestTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(brokerEndpoint));
-        log.debug("add basic authentication for broker service: username={}, password=(hidden)", brokerUsername);
         restTemplate.getInterceptors()
-                .addAll(List.of(new BasicAuthenticationInterceptor(brokerUsername, brokerPassword),
-                        clientHttpRequestInterceptor()));
+                .add(new InternalRequestInterceptor(this, keycloakGateway));
         return restTemplate;
     }
 
@@ -68,10 +60,8 @@ public class GatewayConfig {
     public RestTemplate dataServiceRestTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(dataEndpoint));
-        log.debug("add basic authentication for data service: username={}, password=(hidden)", adminUsername);
         restTemplate.getInterceptors()
-                .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword),
-                        clientHttpRequestInterceptor()));
+                .add(new InternalRequestInterceptor(this, keycloakGateway));
         return restTemplate;
     }
 
@@ -79,10 +69,8 @@ public class GatewayConfig {
     public RestTemplate analyseServiceRestTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(analyseEndpoint));
-        log.debug("add basic authentication for analyse service: username={}, password=(hidden)", adminUsername);
         restTemplate.getInterceptors()
-                .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword),
-                        clientHttpRequestInterceptor()));
+                .add(new InternalRequestInterceptor(this, keycloakGateway));
         return restTemplate;
     }
 
@@ -90,20 +78,9 @@ public class GatewayConfig {
     public RestTemplate searchServiceRestTemplate() {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(searchEndpoint));
-        log.debug("add basic authentication for search service: username={}, password=(hidden)", adminUsername);
         restTemplate.getInterceptors()
-                .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword),
-                        clientHttpRequestInterceptor()));
+                .add(new InternalRequestInterceptor(this, keycloakGateway));
         return restTemplate;
     }
 
-    @Bean
-    public ClientHttpRequestInterceptor clientHttpRequestInterceptor() {
-        return (request, body, execution) -> {
-            final HttpHeaders headers = request.getHeaders();
-            headers.setAccept(List.of(MediaType.APPLICATION_JSON));
-            return execution.execute(request, body);
-        };
-    }
-
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
index 4d258d496aa6ebe825ac2d84a1f00a1b4f9c0298..e422223e06489ff144b148b8210913c1bdff3423 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
@@ -2,16 +2,12 @@ package at.tuwien.config;
 
 import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.client.ClientHttpRequestInterceptor;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.DefaultUriBuilderFactory;
 
-import java.util.List;
-
 @Getter
 @Configuration
 public class KeycloakConfig {
@@ -31,11 +27,9 @@ public class KeycloakConfig {
     @Value("${dbrepo.keycloak.clientSecret}")
     private String keycloakClientSecret;
 
-    private final ClientHttpRequestInterceptor clientHttpRequestInterceptor;
-
-    @Autowired
-    public KeycloakConfig(ClientHttpRequestInterceptor clientHttpRequestInterceptor) {
-        this.clientHttpRequestInterceptor = clientHttpRequestInterceptor;
+    @Bean
+    public RestTemplate restTemplate() {
+        return new RestTemplate();
     }
 
     @Bean("keycloakRestTemplate")
@@ -43,8 +37,7 @@ public class KeycloakConfig {
         final RestTemplate restTemplate = new RestTemplate();
         restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
         restTemplate.getInterceptors()
-                .addAll(List.of(new KeycloakInterceptor(keycloakUsername, keycloakPassword, keycloakEndpoint),
-                        clientHttpRequestInterceptor));
+                .add(new KeycloakInterceptor(keycloakUsername, keycloakPassword, keycloakEndpoint));
         return restTemplate;
     }
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java
index bef02350067f207e03aed94dfc0e06939c6b6c83..0ed5001dd434d400a792bd3700b902d43b435de0 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java
@@ -19,4 +19,7 @@ public class RabbitConfig {
     @Value("${spring.rabbitmq.virtual-host}")
     private String virtualHost;
 
+    @Value("${dbrepo.endpoints.brokerService}")
+    private String brokerEndpoint;
+
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
index 769cf00b01292a131609d2241e23685289e6a888..ae15c9df2d3406a09ec6aeafbfebf571a0325a78 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
@@ -43,8 +43,8 @@ public class WebSecurityConfig {
     }
 
     @Bean
-    public SecurityFilterChain filterChain(GatewayConfig gatewayConfig, HttpSecurity http,
-                                           KeycloakGateway keycloakGateway) throws Exception {
+    public SecurityFilterChain filterChain(HttpSecurity http, KeycloakGateway keycloakGateway)
+            throws Exception {
         final OrRequestMatcher internalEndpoints = new OrRequestMatcher(
                 new AntPathRequestMatcher("/actuator/**", "GET"),
                 new AntPathRequestMatcher("/v3/api-docs.yaml"),
@@ -88,8 +88,8 @@ public class WebSecurityConfig {
         http.addFilterBefore(authTokenFilter(),
                 UsernamePasswordAuthenticationFilter.class
         );
-        http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(gatewayConfig,
-                        authTokenFilter(), keycloakGateway)),
+        http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(authTokenFilter(),
+                        keycloakGateway)),
                 UsernamePasswordAuthenticationFilter.class
         );
         return http.build();
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java
index 0ca0f707e45da7bc25138707eedc68ad88ab26e2..42e8912d0c1c716309ead8d8ddfc3829f3206709 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java
@@ -10,31 +10,31 @@ public interface BrokerServiceGateway {
      * Create topic exchange permissions at the broker service.
      *
      * @param data The topic exchange permissions.
-     * @throws ServiceConnectionException
-     * @throws ServiceException
+     * @throws BrokerServiceConnectionException
+     * @throws BrokerServiceException
      */
-    void grantExchangePermission(String username, GrantExchangePermissionsDto data) throws ServiceConnectionException,
-            ServiceException;
+    void grantExchangePermission(String username, GrantExchangePermissionsDto data)
+            throws BrokerServiceConnectionException, BrokerServiceException;
 
     /**
      * Grants a user permission at a virtual host in the queue service.
      *
      * @param username The username of the user.
      * @param data     The grant data.
-     * @throws ServiceConnectionException
-     * @throws ServiceException
+     * @throws BrokerServiceConnectionException
+     * @throws BrokerServiceException
      */
-    void grantTopicPermission(String username, ExchangeUpdatePermissionsDto data) throws ServiceConnectionException,
-            ServiceException;
+    void grantTopicPermission(String username, ExchangeUpdatePermissionsDto data)
+            throws BrokerServiceConnectionException, BrokerServiceException;
 
     /**
      * Grants a user permission at a virtual host in the queue service.
      *
      * @param username The username of the user.
      * @param data     The grant data.
-     * @throws ServiceConnectionException
-     * @throws ServiceException
+     * @throws BrokerServiceConnectionException
+     * @throws BrokerServiceException
      */
     void grantVirtualHostPermission(String username, GrantVirtualHostPermissionsDto data)
-            throws ServiceConnectionException, ServiceException;
+            throws BrokerServiceConnectionException, BrokerServiceException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java
index 9edb9f388da8ef481f2ec1b18522f8bc4695b954..91fb96e5f93ca5f4fd17c120d2f8f00703f3a3e3 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java
@@ -17,31 +17,163 @@ import java.util.List;
 import java.util.UUID;
 
 public interface DataServiceGateway {
-    void createAccess(Long databaseId, UUID userId, AccessTypeDto access) throws ServiceConnectionException, ServiceException, DatabaseNotFoundException;
 
-    void updateAccess(Long databaseId, UUID userId, AccessTypeDto access) throws ServiceConnectionException, ServiceException, AccessNotFoundException;
-
-    void deleteAccess(Long databaseId, UUID userId) throws ServiceConnectionException, ServiceException, AccessNotFoundException;
-
-    DatabaseDto createDatabase(CreateDatabaseDto data) throws ServiceConnectionException, ServiceException;
-
-    void updateDatabase(Long databaseId, UpdateUserPasswordDto data) throws ServiceConnectionException, ServiceException, DatabaseNotFoundException;
-
-    void createTable(Long databaseId, TableCreateDto data) throws ServiceConnectionException, ServiceException, DatabaseNotFoundException, TableExistsException;
-
-    void deleteTable(Long databaseId, Long tableId) throws ServiceConnectionException, ServiceException, TableNotFoundException;
-
-    ViewDto createView(Long databaseId, ViewCreateDto data) throws ServiceConnectionException, ServiceException;
-
-    void deleteView(Long databaseId, Long viewId) throws ServiceConnectionException, ServiceException, ViewNotFoundException;
-
-    QueryDto findQuery(Long databaseId, Long queryId) throws ServiceConnectionException, ServiceException, QueryNotFoundException;
-
-    ExportResourceDto exportQuery(Long databaseId, Long queryId) throws ServiceConnectionException, ServiceException, QueryNotFoundException;
-
-    List<TableDto> getTableSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException;
-
-    List<ViewDto> getViewSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException;
-
-    TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws ServiceConnectionException, ServiceException, TableNotFoundException;
+    /**
+     * Create r/w access for a given user to a given database.
+     * @param databaseId The database id.
+     * @param userId The user id.
+     * @param access The access.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws DatabaseNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service.
+     */
+    void createAccess(Long databaseId, UUID userId, AccessTypeDto access) throws DataServiceConnectionException,
+            DataServiceException, DatabaseNotFoundException;
+
+    /**
+     * Update r/w access for a given user to a given database.
+     * @param databaseId The database id.
+     * @param userId The user id.
+     * @param access The access.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws AccessNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service.
+     */
+    void updateAccess(Long databaseId, UUID userId, AccessTypeDto access) throws DataServiceConnectionException,
+            DataServiceException, AccessNotFoundException;
+
+    /**
+     * Deletes access for a given user to a given database.
+     * @param databaseId The database id.
+     * @param userId The user id.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws AccessNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service.
+     */
+    void deleteAccess(Long databaseId, UUID userId) throws DataServiceConnectionException, DataServiceException,
+            AccessNotFoundException;
+
+    /**
+     * Creates a database in the data service.
+     * @param data The data.
+     * @return The created database, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws DatabaseNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service.
+     */
+    DatabaseDto createDatabase(CreateDatabaseDto data) throws DataServiceConnectionException, DataServiceException,
+            DatabaseNotFoundException;
+
+    /**
+     * Updates the user password in the given database in the data service.
+     * @param databaseId The database id.
+     * @param data The user password.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws DatabaseNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service.
+     */
+    void updateDatabase(Long databaseId, UpdateUserPasswordDto data) throws DataServiceConnectionException,
+            DataServiceException, DatabaseNotFoundException;
+
+    /**
+     * Creates a table in a given database.
+     * @param databaseId The database id.
+     * @param data The table data.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws DatabaseNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service.
+     * @throws TableExistsException  A table with this internal name exists already in the database.
+     */
+    void createTable(Long databaseId, TableCreateDto data) throws DataServiceConnectionException, DataServiceException,
+            DatabaseNotFoundException, TableExistsException;
+
+    /**
+     * Deletes a given table in a given database.
+     * @param databaseId The database id.
+     * @param tableId The table id.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws TableNotFoundException The given table was not found in the database.
+     */
+    void deleteTable(Long databaseId, Long tableId) throws DataServiceConnectionException, DataServiceException,
+            TableNotFoundException;
+
+    /**
+     * Creates a view in the given database.
+     * @param databaseId The database id.
+     * @param data The view data.
+     * @return The created view, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     */
+    ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException;
+
+    /**
+     * Deletes a given view in the given database.
+     * @param databaseId The database id.
+     * @param viewId The view id.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws ViewNotFoundException The given view was not found in the database.
+     */
+    void deleteView(Long databaseId, Long viewId) throws DataServiceConnectionException, DataServiceException,
+            ViewNotFoundException;
+
+    /**
+     * Finds a given query in a given database.
+     * @param databaseId The database id.
+     * @param queryId The query id.
+     * @return The query, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws QueryNotFoundException The given query was not found in the query store.
+     */
+    QueryDto findQuery(Long databaseId, Long queryId) throws DataServiceConnectionException, DataServiceException,
+            QueryNotFoundException;
+
+    /**
+     * Exports a given query.
+     * @param databaseId The database id.
+     * @param queryId The query id.
+     * @return The exported resource, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws QueryNotFoundException The given query was not found in the query store.
+     */
+    ExportResourceDto exportQuery(Long databaseId, Long queryId) throws DataServiceConnectionException,
+            DataServiceException, QueryNotFoundException;
+
+    /**
+     * Obtain table schemas from a given database.
+     * @param databaseId The database id.
+     * @return The list of tables, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws TableNotFoundException The table was not found in the database.
+     */
+    List<TableDto> getTableSchemas(Long databaseId) throws DataServiceConnectionException, DataServiceException,
+            TableNotFoundException;
+
+    /**
+     * Obtain view schemas from a given database.
+     * @param databaseId The database id.
+     * @return The list of tables, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws ViewNotFoundException The table was not found in the database.
+     */
+    List<ViewDto> getViewSchemas(Long databaseId) throws DataServiceConnectionException, DataServiceException,
+            ViewNotFoundException;
+
+    /**
+     * Obtain table statistics for a given table in a given database.
+     * @param databaseId The database id.
+     * @param tableId The table id.
+     * @return The statistic, if successful.
+     * @throws DataServiceConnectionException The connection to the data service could not be established.
+     * @throws DataServiceException The data service responded unexpectedly.
+     * @throws TableNotFoundException The table was not found in the database.
+     */
+    TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws DataServiceConnectionException,
+            DataServiceException, TableNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java
index b949ddbaddb6bb6dfaba0b31f304a89266224cad..2cd5f142e6638f087265d6f605aa271fd518c51b 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java
@@ -7,5 +7,11 @@ import org.springframework.stereotype.Service;
 @Service
 public interface OrcidGateway {
 
+    /**
+     * Finds metadata from given ORCID url.
+     * @param url The ORCID url.
+     * @return The metadata, if successful.
+     * @throws OrcidNotFoundException The metadata does not exist to the given ORCID.
+     */
     OrcidDto findByUrl(String url) throws OrcidNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java
index 9b3bbf4cf2ab931bad65a146a4024eebb94b41da..0313ca26edc598812ffc9f176737de1e05f4c1ec 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java
@@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.*;
 import org.springframework.stereotype.Service;
-import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
@@ -31,59 +30,61 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway {
 
     @Override
     public void grantTopicPermission(String username, ExchangeUpdatePermissionsDto data)
-            throws ServiceConnectionException, ServiceException {
+            throws BrokerServiceConnectionException, BrokerServiceException {
         final String url = "/api/topic-permissions/" + rabbitConfig.getVirtualHost() + "/" + username;
         final ResponseEntity<Void> response;
         try {
             response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to grant topic permissions: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to grant topic permissions: " + e.getMessage());
+            throw new BrokerServiceConnectionException("Failed to grant topic permissions: " + e.getMessage());
         } catch (Exception e) {
             log.error("Failed to grant topic permissions: unexpected response: {}", e.getMessage());
-            throw new ServiceException("Failed to grant topic permissions: unexpected response: " + e.getMessage(), e);
+            throw new BrokerServiceException("Failed to grant topic permissions: unexpected response: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED) && !response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
             log.error("Failed to grant topic permissions: unexpected status: {}", response.getStatusCode().value());
-            throw new ServiceException("Failed to grant topic permissions: unexpected status: " + response.getStatusCode().value());
+            throw new BrokerServiceException("Failed to grant topic permissions: unexpected status: " + response.getStatusCode().value());
         }
     }
 
     @Override
-    public void grantVirtualHostPermission(String username, GrantVirtualHostPermissionsDto data) throws ServiceConnectionException, ServiceException {
+    public void grantVirtualHostPermission(String username, GrantVirtualHostPermissionsDto data)
+            throws BrokerServiceConnectionException, BrokerServiceException {
         final String url = "/api/permissions/" + rabbitConfig.getVirtualHost() + "/" + username;
         final ResponseEntity<Void> response;
         try {
             response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to grant virtual host permissions: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to grant virtual host permissions: " + e.getMessage());
+            throw new BrokerServiceConnectionException("Failed to grant virtual host permissions: " + e.getMessage());
         } catch (Exception e) {
             log.error("Failed to grant virtual host permissions: unexpected response: {}", e.getMessage());
-            throw new ServiceException("Failed to grant virtual host permissions: unexpected response: " + e.getMessage(), e);
+            throw new BrokerServiceException("Failed to grant virtual host permissions: unexpected response: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED) && !response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
             log.error("Failed to grant virtual host permissions: unexpected status: {}", response.getStatusCode().value());
-            throw new ServiceException("Failed to grant virtual host permissions: unexpected status: " + response.getStatusCode().value());
+            throw new BrokerServiceException("Failed to grant virtual host permissions: unexpected status: " + response.getStatusCode().value());
         }
     }
 
     @Override
-    public void grantExchangePermission(String username, GrantExchangePermissionsDto data) throws ServiceConnectionException, ServiceException {
+    public void grantExchangePermission(String username, GrantExchangePermissionsDto data)
+            throws BrokerServiceConnectionException, BrokerServiceException {
         final String url = "/api/topic-permissions/" + rabbitConfig.getVirtualHost() + "/" + username;
         final ResponseEntity<Void> response;
         try {
             response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to grant exchange permissions: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to grant exchange permissions: " + e.getMessage());
+            throw new BrokerServiceConnectionException("Failed to grant exchange permissions: " + e.getMessage());
         } catch (Exception e) {
             log.error("Failed to grant exchange permissions: unexpected response: {}", e.getMessage());
-            throw new ServiceException("Failed to grant exchange permissions: unexpected response: " + e.getMessage(), e);
+            throw new BrokerServiceException("Failed to grant exchange permissions: unexpected response: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED) && !response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
             log.error("Failed to grant exchange permissions: unexpected status: {}", response.getStatusCode().value());
-            throw new ServiceException("Failed to grant exchange permissions: unexpected status: " + response.getStatusCode().value());
+            throw new BrokerServiceException("Failed to grant exchange permissions: unexpected status: " + response.getStatusCode().value());
         }
     }
 
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java
index 7c5d4b19f553c26201a1f6653465fc66454e7e54..9b675cba348f7cc142958f9ee1cd93de198c2055 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java
@@ -4,6 +4,7 @@ import at.tuwien.api.crossref.CrossrefDto;
 import at.tuwien.exception.DoiNotFoundException;
 import at.tuwien.gateway.CrossrefGateway;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
@@ -19,8 +20,9 @@ public class CrossrefGatewayImpl implements CrossrefGateway {
 
     private final RestTemplate restTemplate;
 
-    public CrossrefGatewayImpl() {
-        this.restTemplate = new RestTemplate();
+    @Autowired
+    public CrossrefGatewayImpl(RestTemplate restTemplate) {
+        this.restTemplate = restTemplate;
     }
 
     @Override
@@ -32,7 +34,7 @@ public class CrossrefGatewayImpl implements CrossrefGateway {
         try {
             log.trace("find crossref doi from url {}", url);
             response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), CrossrefDto.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to retrieve CrossRef metadata from URL {}: {}", url, e.getMessage());
             throw new DoiNotFoundException("Failed to retrieve CrossRef metadata from URL " + url + ": " + e.getMessage());
         }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java
index 6c09d6d50067be958efc69cfbc28fa866cfec803..4a3f12f759d603a9c76ea37ae223a43e05cf897f 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java
@@ -34,7 +34,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
 
     @Override
     public void createAccess(Long databaseId, UUID userId, AccessTypeDto access)
-            throws ServiceConnectionException, ServiceException, DatabaseNotFoundException {
+            throws DataServiceConnectionException, DataServiceException, DatabaseNotFoundException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/access/" + userId;
         try {
@@ -42,23 +42,23 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
                     new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to create access: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to create access: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to create access: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to create access: not found: {}", e.getMessage());
             throw new DatabaseNotFoundException("Failed to create access: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) {
             log.error("Failed to create access: {}", e.getMessage());
-            throw new ServiceException("Failed to create access: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to create access: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
             log.error("Failed to create access: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to create access: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to create access: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
     public void updateAccess(Long databaseId, UUID userId, AccessTypeDto access)
-            throws ServiceConnectionException, ServiceException, AccessNotFoundException {
+            throws DataServiceConnectionException, DataServiceException, AccessNotFoundException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/access/" + userId;
         try {
@@ -66,22 +66,22 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
                     new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to update access: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to update access: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to update access: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to update access: not found: {}", e.getMessage());
             throw new AccessNotFoundException("Failed to update access: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) {
             log.error("Failed to update access: {}", e.getMessage());
-            throw new ServiceException("Failed to update access: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to update access: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to update access: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to update access: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to update access: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
-    public void deleteAccess(Long databaseId, UUID userId) throws ServiceConnectionException, ServiceException,
+    public void deleteAccess(Long databaseId, UUID userId) throws DataServiceConnectionException, DataServiceException,
             AccessNotFoundException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/access/" + userId;
@@ -89,65 +89,69 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             response = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to delete access: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to delete access: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to delete access: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to delete access: not found: {}", e.getMessage());
             throw new AccessNotFoundException("Failed to delete access: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to delete access: {}", e.getMessage());
-            throw new ServiceException("Failed to delete access: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to delete access: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to delete access: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to delete access: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to delete access: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
-    public DatabaseDto createDatabase(CreateDatabaseDto data) throws ServiceConnectionException, ServiceException {
+    public DatabaseDto createDatabase(CreateDatabaseDto data) throws DataServiceConnectionException,
+            DataServiceException, DatabaseNotFoundException {
         final ResponseEntity<DatabaseDto> response;
         final String url = "/api/database";
         try {
             response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data), DatabaseDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to create database: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to create database: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to create database: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) {
-            log.error("Failed to create database: {}", e.getMessage());
-            throw new ServiceException("Failed to create database: " + e.getMessage(), e);
+            log.error("Failed to create database: malformed: {}", e.getMessage());
+            throw new DataServiceException("Failed to create database: malformed: " + e.getMessage(), e);
+        } catch (HttpClientErrorException.NotFound e) {
+            log.error("Failed to create database: not found: {}", e.getMessage());
+            throw new DatabaseNotFoundException("Failed to create database: not found: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
             log.error("Failed to create database: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to create database: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to create database: wrong http code: " + response.getStatusCode());
         }
         return response.getBody();
     }
 
     @Override
-    public void updateDatabase(Long databaseId, UpdateUserPasswordDto data) throws ServiceConnectionException,
-            ServiceException, DatabaseNotFoundException {
+    public void updateDatabase(Long databaseId, UpdateUserPasswordDto data) throws DataServiceConnectionException,
+            DataServiceException, DatabaseNotFoundException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId;
         try {
             response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to update user password in database: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to update user password in database: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to update user password in database: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to update user password in database: not found: {}", e.getMessage());
             throw new DatabaseNotFoundException("Failed to update user password in database: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) {
             log.error("Failed to update user password in database: {}", e.getMessage());
-            throw new ServiceException("Failed to update user password in database: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to update user password in database: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to update user password in database: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to update user password in database: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to update user password in database: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
-    public void createTable(Long databaseId, TableCreateDto data) throws ServiceConnectionException, ServiceException,
+    public void createTable(Long databaseId, TableCreateDto data) throws DataServiceConnectionException, DataServiceException,
             DatabaseNotFoundException, TableExistsException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/table";
@@ -155,7 +159,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to create table: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to create table: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to create table: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to create table: not found: {}", e.getMessage());
             throw new DatabaseNotFoundException("Failed to create table: not found: " + e.getMessage(), e);
@@ -164,16 +168,16 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             throw new TableExistsException("Failed to create table: already exists", e);
         } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) {
             log.error("Failed to create table: {}", e.getMessage());
-            throw new ServiceException("Failed to create table: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to create table: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
             log.error("Failed to create table: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to create table: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to create table: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
-    public void deleteTable(Long databaseId, Long tableId) throws ServiceConnectionException, ServiceException,
+    public void deleteTable(Long databaseId, Long tableId) throws DataServiceConnectionException, DataServiceException,
             TableNotFoundException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/table/" + tableId;
@@ -181,46 +185,46 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             response = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to delete table: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to delete table: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to delete table: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to delete table: not found: {}", e.getMessage());
             throw new TableNotFoundException("Failed to delete table: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to delete table: {}", e.getMessage());
-            throw new ServiceException("Failed to delete table: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to delete table: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to delete table: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to delete table: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to delete table: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
-    public ViewDto createView(Long databaseId, ViewCreateDto data) throws ServiceConnectionException, ServiceException {
+    public ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException {
         final ResponseEntity<ViewDto> response;
         final String url = "/api/database/" + databaseId + "/view";
         try {
             response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data), ViewDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to create view: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to create view: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to create view: " + e.getMessage(), e);
         } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) {
             log.error("Failed to create view: {}", e.getMessage());
-            throw new ServiceException("Failed to create view: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to create view: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
             log.error("Failed to create view: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to create view: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to create view: wrong http code: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to create view: empty body: {}", response.getStatusCode());
-            throw new ServiceException("Failed to create view: empty body: " + response.getStatusCode());
+            throw new DataServiceException("Failed to create view: empty body: " + response.getStatusCode());
         }
         return response.getBody();
     }
 
     @Override
-    public void deleteView(Long databaseId, Long viewId) throws ServiceConnectionException, ServiceException,
+    public void deleteView(Long databaseId, Long viewId) throws DataServiceConnectionException, DataServiceException,
             ViewNotFoundException {
         final ResponseEntity<Void> response;
         final String url = "/api/database/" + databaseId + "/view/" + viewId;
@@ -228,22 +232,22 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             response = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to delete view: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to delete view: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to delete view: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to delete view: not found: {}", e.getMessage());
             throw new ViewNotFoundException("Failed to delete view: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to delete view: {}", e.getMessage());
-            throw new ServiceException("Failed to delete view: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to delete view: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) {
             log.error("Failed to delete view: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to delete view: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to delete view: wrong http code: " + response.getStatusCode());
         }
     }
 
     @Override
-    public QueryDto findQuery(Long databaseId, Long queryId) throws ServiceConnectionException, ServiceException,
+    public QueryDto findQuery(Long databaseId, Long queryId) throws DataServiceConnectionException, DataServiceException,
             QueryNotFoundException {
         final ResponseEntity<QueryDto> response;
         final String url = "/api/database/" + databaseId + "/subset/" + queryId;
@@ -251,71 +255,72 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, QueryDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to find query: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to find query", e);
+            throw new DataServiceConnectionException("Failed to find query", e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to find query: not found: {}", e.getMessage());
             throw new QueryNotFoundException("Failed to find query: not found", e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to find query: unauthorized: {}", e.getMessage());
-            throw new ServiceException("Failed to find query: unauthorized", e);
+            throw new DataServiceException("Failed to find query: unauthorized", e);
         } catch (HttpClientErrorException.NotAcceptable e) {
             log.error("Failed to find query: format not acccepted: {}", e.getMessage());
-            throw new ServiceException("Failed to find query: format not accepted", e);
+            throw new DataServiceException("Failed to find query: format not accepted", e);
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to find query: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to find query: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to find query: wrong http code: " + response.getStatusCode());
         }
         return response.getBody();
     }
 
     @Override
-    public ExportResourceDto exportQuery(Long databaseId, Long queryId) throws ServiceConnectionException,
-            ServiceException, QueryNotFoundException {
+    public ExportResourceDto exportQuery(Long databaseId, Long queryId) throws DataServiceConnectionException,
+            DataServiceException, QueryNotFoundException {
         final ResponseEntity<ExportResourceDto> response;
         final String url = "/api/database/" + databaseId + "/subset/" + queryId;
         try {
             response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ExportResourceDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to export query: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to export query: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to export query: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to export query: not found: {}", e.getMessage());
             throw new QueryNotFoundException("Failed to export query: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to export query: {}", e.getMessage());
-            throw new ServiceException("Failed to export query: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to export query: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to export query: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to export query: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to export query: wrong http code: " + response.getStatusCode());
         }
         return response.getBody();
     }
 
     @Override
-    public List<TableDto> getTableSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException {
+    public List<TableDto> getTableSchemas(Long databaseId) throws DataServiceConnectionException, DataServiceException,
+            TableNotFoundException {
         final ResponseEntity<TableDto[]> response;
         final String url = "/api/database/" + databaseId + "/table";
         try {
             response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, TableDto[].class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to get table schemas: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to get table schemas: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to get table schemas: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to get table schemas: not found: {}", e.getMessage());
-            throw new QueryNotFoundException("Failed to get table schemas: not found: " + e.getMessage(), e);
+            throw new TableNotFoundException("Failed to get table schemas: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to get table schemas: {}", e.getMessage());
-            throw new ServiceException("Failed to get table schemas: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to get table schemas: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to get table schemas: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to get table schemas: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to get table schemas: wrong http code: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to get table schemas: empty body: {}", response.getStatusCode());
-            throw new ServiceException("Failed to get table schemas: empty body: " + response.getStatusCode());
+            throw new DataServiceException("Failed to get table schemas: empty body: " + response.getStatusCode());
         }
         final List<TableDto> tables = Arrays.asList(response.getBody());
         log.debug("found {} table(s) in data service", tables.size());
@@ -323,28 +328,29 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
     }
 
     @Override
-    public List<ViewDto> getViewSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException {
+    public List<ViewDto> getViewSchemas(Long databaseId) throws DataServiceConnectionException, DataServiceException,
+            ViewNotFoundException {
         final ResponseEntity<ViewDto[]> response;
         final String url = "/api/database/" + databaseId + "/view";
         try {
             response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ViewDto[].class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to get view schemas: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to get view schemas: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to get view schemas: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to get view schemas: not found: {}", e.getMessage());
-            throw new QueryNotFoundException("Failed to get view schemas: not found: " + e.getMessage(), e);
+            throw new ViewNotFoundException("Failed to get view schemas: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to get view schemas: {}", e.getMessage());
-            throw new ServiceException("Failed to get view schemas: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to get view schemas: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to get view schemas: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to get view schemas: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to get view schemas: wrong http code: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to get view schemas: empty body: {}", response.getStatusCode());
-            throw new ServiceException("Failed to get view schemas: empty body: " + response.getStatusCode());
+            throw new DataServiceException("Failed to get view schemas: empty body: " + response.getStatusCode());
         }
         final List<ViewDto> views = Arrays.asList(response.getBody());
         log.debug("found {} view(s) in data service", views.size());
@@ -352,28 +358,28 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
     }
 
     @Override
-    public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws ServiceConnectionException, ServiceException, TableNotFoundException {
+    public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws DataServiceConnectionException, DataServiceException, TableNotFoundException {
         final ResponseEntity<TableStatisticDto> response;
         final String url = "/api/database/" + databaseId + "/table/" + tableId + "/statistic";
         try {
             response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, TableStatisticDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to analyse table statistic: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to analyse table statistic: " + e.getMessage(), e);
+            throw new DataServiceConnectionException("Failed to analyse table statistic: " + e.getMessage(), e);
         } catch (HttpClientErrorException.NotFound e) {
             log.error("Failed to analyse table statistic: not found: {}", e.getMessage());
             throw new TableNotFoundException("Failed to analyse table statistic: not found: " + e.getMessage(), e);
         } catch (HttpClientErrorException.Unauthorized e) {
             log.error("Failed to analyse table statistic: {}", e.getMessage());
-            throw new ServiceException("Failed to analyse table statistic: " + e.getMessage(), e);
+            throw new DataServiceException("Failed to analyse table statistic: " + e.getMessage(), e);
         }
         if (!response.getStatusCode().equals(HttpStatus.OK)) {
             log.error("Failed to analyse table statistic: wrong http code: {}", response.getStatusCode());
-            throw new ServiceException("Failed to analyse table statistic: wrong http code: " + response.getStatusCode());
+            throw new DataServiceException("Failed to analyse table statistic: wrong http code: " + response.getStatusCode());
         }
         if (response.getBody() == null) {
             log.error("Failed to analyse table statistic: empty body: {}", response.getStatusCode());
-            throw new ServiceException("Failed to analyse table statistic: empty body: " + response.getStatusCode());
+            throw new DataServiceException("Failed to analyse table statistic: empty body: " + response.getStatusCode());
         }
         return response.getBody();
     }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
index 91ec52d8e092101704acea72ba38656e1aec008f..d05243f9a5bf81a752c085184b754acae1405ad3 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
@@ -24,12 +24,15 @@ import java.util.UUID;
 public class KeycloakGatewayImpl implements KeycloakGateway {
 
     private final RestTemplate restTemplate;
+    private final RestTemplate keycloakRestTemplate;
     private final KeycloakConfig keycloakConfig;
     private final MetadataMapper metadataMapper;
 
-    public KeycloakGatewayImpl(@Qualifier("keycloakRestTemplate") RestTemplate restTemplate,
+    public KeycloakGatewayImpl(@Qualifier("restTemplate") RestTemplate restTemplate,
+                               @Qualifier("keycloakRestTemplate") RestTemplate keycloakRestTemplate,
                                KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
         this.restTemplate = restTemplate;
+        this.keycloakRestTemplate = keycloakRestTemplate;
         this.keycloakConfig = keycloakConfig;
         this.metadataMapper = metadataMapper;
     }
@@ -45,13 +48,9 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         payload.add("client_id", "admin-cli");
         final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/master/protocol/openid-connect/token";
         log.trace("request admin token from url: {}", url);
-        log.trace("request username: {}", keycloakConfig.getKeycloakUsername());
-        log.trace("request password: {}", keycloakConfig.getKeycloakPassword() != null ? "(set)" : "(not set)");
-        log.trace("request client_id: admin-cli");
-        log.trace("request client_secret: (not set)");
         final ResponseEntity<TokenDto> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
+            response = keycloakRestTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to obtain admin token: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
@@ -78,15 +77,10 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         payload.add("client_id", keycloakConfig.getKeycloakClient());
         payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
         final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/dbrepo/protocol/openid-connect/token";
-        log.trace("request user token from url: {}", url);
-        log.trace("request username: {}", username);
-        log.trace("request password: {}", password != null ? "(set)" : "(not set)");
-        log.trace("request client_id: {}", keycloakConfig.getKeycloakClient());
-        log.trace("request client_secret: {}", keycloakConfig.getKeycloakClientSecret());
+        log.trace("request admin token from url: {}", url);
         final ResponseEntity<TokenDto> response;
         try {
-            response = new RestTemplate()
-                    .exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
+            response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to obtain user token: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
@@ -119,8 +113,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         log.trace("request user token from url: {}", url);
         final ResponseEntity<TokenDto> response;
         try {
-            response = new RestTemplate()
-                    .exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
+            response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to refresh user token: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
@@ -128,7 +121,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
             log.error("Failed to refresh user token: invalid credentials");
             throw new CredentialsInvalidException("Invalid credentials", e);
         } catch (HttpClientErrorException.BadRequest e) {
-            if (e.getMessage().contains("Session not active")) {
+            if (e.getMessage() != null && e.getMessage().contains("Session not active")) {
                 log.error("Failed to refresh user token: inactive session", e);
                 throw new CredentialsInvalidException("Inactive session", e);
             }
@@ -148,18 +141,20 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         log.debug("create user at url {}", url);
         final ResponseEntity<Void> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data, headers), Void.class);
+            response = keycloakRestTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data, headers), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to create user: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
         } catch (HttpClientErrorException.Conflict e) {
-            if (e.getMessage().contains("same email")) {
-                log.error("Failed to create user: email exists: {}", e.getMessage());
-                throw new EmailExistsException("E-Mail exists", e);
-            } else {
-                log.error("Failed to create user: user exists: {}", e.getMessage());
-                throw new UserExistsException("User exists", e);
+            if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) {
+                final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
+                if (error != null && error.getErrorMessage().contains("same email")) {
+                    log.error("Failed to create user: email exists: {}", e.getMessage());
+                    throw new EmailExistsException("E-Mail exists", e);
+                }
             }
+            log.error("Failed to create user: user exists: {}", e.getMessage());
+            throw new UserExistsException("User exists", e);
         }
         if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
             log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value());
@@ -178,7 +173,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         log.debug("delete user at url {}", url);
         final ResponseEntity<Void> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null, headers), Void.class);
+            response = keycloakRestTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null, headers), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to delete user: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
@@ -207,7 +202,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         log.debug("update user credentials at url {}", url);
         final ResponseEntity<Void> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(payload, headers), Void.class);
+            response = keycloakRestTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(payload, headers), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to update user credentials: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
@@ -232,7 +227,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         log.debug("find user from url {}", url);
         final ResponseEntity<UserDto[]> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), UserDto[].class);
+            response = keycloakRestTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), UserDto[].class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to find user: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
@@ -258,7 +253,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         log.debug("find user from url {}", url);
         final ResponseEntity<UserDto> response;
         try {
-            response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), UserDto.class);
+            response = keycloakRestTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), UserDto.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to find user: {}", e.getMessage());
             throw new AuthServiceConnectionException("Service unavailable", e);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java
index debbe4d66c288fe5546364b1b3067718217ce894..15b73eb1931a2397d4dba3550479a839b23ec834 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java
@@ -4,6 +4,7 @@ import at.tuwien.api.orcid.OrcidDto;
 import at.tuwien.exception.OrcidNotFoundException;
 import at.tuwien.gateway.OrcidGateway;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
@@ -19,8 +20,9 @@ public class OrcidGatewayImpl implements OrcidGateway {
 
     private final RestTemplate restTemplate;
 
-    public OrcidGatewayImpl() {
-        this.restTemplate = new RestTemplate();
+    @Autowired
+    public OrcidGatewayImpl(RestTemplate restTemplate) {
+        this.restTemplate = restTemplate;
     }
 
     @Override
@@ -31,7 +33,7 @@ public class OrcidGatewayImpl implements OrcidGateway {
         try {
             log.debug("find orcid from url {}", url);
             response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), OrcidDto.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to retrieve ORCID metadata from URL {}: {}", url, e.getMessage());
             throw new OrcidNotFoundException("Failed to retrieve ORCID metadata from URL " + url + ": " + e.getMessage());
         }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java
index 6eeb74c3c072f684834f90228dd755bfcb959c09..7a5a64e8e24faa22f0051cdef8b94ded85ab5da3 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java
@@ -4,6 +4,7 @@ import at.tuwien.api.ror.RorDto;
 import at.tuwien.exception.RorNotFoundException;
 import at.tuwien.gateway.RorGateway;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
@@ -19,8 +20,9 @@ public class RorGatewayImpl implements RorGateway {
 
     private final RestTemplate restTemplate;
 
-    public RorGatewayImpl() {
-        this.restTemplate = new RestTemplate();
+    @Autowired
+    public RorGatewayImpl(RestTemplate restTemplate) {
+        this.restTemplate = restTemplate;
     }
 
     @Override
@@ -32,7 +34,7 @@ public class RorGatewayImpl implements RorGateway {
         try {
             log.trace("find ror from url {}", url);
             response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), RorDto.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+        } catch (HttpServerErrorException e) {
             log.error("Failed to retrieve ROR metadata from URL {}: {}", url, e.getMessage());
             throw new RorNotFoundException("Failed to retrieve ROR metadata from URL " + url + ": " + e.getMessage(), e);
         }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java
index d5a4d03092dfaa7ee7623dc9e3a13f946ae62a02..c47bb8daa36519ff251202d14a02f38c9212aafe 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java
@@ -5,10 +5,8 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
-import java.util.UUID;
 
 public interface AccessService {
 
@@ -37,11 +35,11 @@ public interface AccessService {
      * @param access   The access.
      * @param user     The user.
      * @return The database access, if successful.
-     * @throws ServiceException           The data service responded with unexpected behavior.
-     * @throws ServiceConnectionException The connection with the data service could not be established.
+     * @throws DataServiceException           The data service responded with unexpected behavior.
+     * @throws DataServiceConnectionException The connection with the data service could not be established.
      * @throws DatabaseNotFoundException  The database was not found in the metadata/search database.
      */
-    DatabaseAccess create(Database database, User user, AccessTypeDto access) throws ServiceException, ServiceConnectionException,
+    DatabaseAccess create(Database database, User user, AccessTypeDto access) throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
     /**
@@ -50,11 +48,11 @@ public interface AccessService {
      * @param database The database.
      * @param user     The user.
      * @param access   The updated access.
-     * @throws ServiceException           The data service responded with unexpected behavior.
-     * @throws ServiceConnectionException The connection with the data service could not be established.
+     * @throws DataServiceException           The data service responded with unexpected behavior.
+     * @throws DataServiceConnectionException The connection with the data service could not be established.
      * @throws DatabaseNotFoundException  The database was not found in the metadata/search database.
      */
-    void update(Database database, User user, AccessTypeDto access) throws ServiceException, ServiceConnectionException,
+    void update(Database database, User user, AccessTypeDto access) throws at.tuwien.exception.DataServiceException, DataServiceConnectionException,
             AccessNotFoundException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
     /**
@@ -62,10 +60,10 @@ public interface AccessService {
      *
      * @param database The database.
      * @param user     The user.
-     * @throws ServiceException           The data service responded with unexpected behavior.
-     * @throws ServiceConnectionException The connection with the data service could not be established.
+     * @throws DataServiceException           The data service responded with unexpected behavior.
+     * @throws DataServiceConnectionException The connection with the data service could not be established.
      * @throws DatabaseNotFoundException  The database was not found in the search database.
      */
-    void delete(Database database, User user) throws AccessNotFoundException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
+    void delete(Database database, User user) throws AccessNotFoundException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java
index 6c0021b4507a339dbc34415d668389ae16c380e8..f249f7a2cf128ffd09f4fcbeee4add401609436b 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java
@@ -10,12 +10,12 @@ public interface BrokerService {
      *
      * @param user The user.
      */
-    void setVirtualHostPermissions(User user) throws ServiceException, ServiceConnectionException;
+    void setVirtualHostPermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException;
 
     /**
      * Sets topic exchange permissions for a user.
      *
      * @param user The user.
      */
-    void setTopicExchangePermissions(User user) throws ServiceException, ServiceConnectionException;
+    void setTopicExchangePermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java
index 32291c8755e56c2a59409f8e4da79c292e85d8c5..aa25ee1362f825ddf060ce9c90dde9e4c965b6bf 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java
@@ -2,15 +2,11 @@ package at.tuwien.service;
 
 import at.tuwien.api.database.DatabaseCreateDto;
 import at.tuwien.api.database.DatabaseModifyVisibilityDto;
-import at.tuwien.api.database.DatabaseTransferDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Propagation;
-import org.springframework.transaction.annotation.Transactional;
 
-import java.security.Principal;
 import java.util.List;
 import java.util.UUID;
 
@@ -55,21 +51,21 @@ public interface DatabaseService {
      * @param user      The user.
      * @return The database, if successful.
      * @throws UserNotFoundException      If the container/user was not found in the metadata database.
-     * @throws ServiceException           If the data service returned non-successfully.
-     * @throws ServiceConnectionException If failing to connect to the data service/search service.
+     * @throws DataServiceException           If the data service returned non-successfully.
+     * @throws DataServiceConnectionException If failing to connect to the data service/search service.
      */
     Database create(DatabaseCreateDto createDto, User user) throws UserNotFoundException, ContainerNotFoundException,
-            ServiceException, ServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
+            DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
     /**
      * Updates the user's password.
      *
      * @param database The database.
      * @param user     The user.
-     * @throws ServiceException           If the data service returned non-successfully.
-     * @throws ServiceConnectionException If failing to connect to the data service.
+     * @throws DataServiceException           If the data service returned non-successfully.
+     * @throws DataServiceConnectionException If failing to connect to the data service.
      */
-    void updatePassword(Database database, User user) throws ServiceException, ServiceConnectionException, DatabaseNotFoundException;
+    void updatePassword(Database database, User user) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException;
 
     /**
      * Updates the visibility of the database.
@@ -78,7 +74,7 @@ public interface DatabaseService {
      * @param data     The visibility
      * @return The database, if successful.
      * @throws NotFoundException          The database was not found in the metadata database.
-     * @throws ServiceConnectionException If failing to connect to the search service.
+     * @throws DataServiceConnectionException If failing to connect to the search service.
      */
     Database modifyVisibility(Database database, DatabaseModifyVisibilityDto data) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
@@ -101,11 +97,11 @@ public interface DatabaseService {
      */
     Database modifyImage(Database database, byte[] image) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
-    Database updateTableMetadata(Database database) throws DatabaseNotFoundException, ServiceException,
+    Database updateTableMetadata(Database database) throws DatabaseNotFoundException, DataServiceException,
             SearchServiceException, SearchServiceConnectionException, QueryNotFoundException,
-            ServiceConnectionException, MalformedException;
+            DataServiceConnectionException, MalformedException, TableNotFoundException;
 
-    Database updateViewMetadata(Database database) throws DatabaseNotFoundException, ServiceException,
+    Database updateViewMetadata(Database database) throws DatabaseNotFoundException, DataServiceException,
             SearchServiceException, SearchServiceConnectionException, QueryNotFoundException,
-            ServiceConnectionException;
+            DataServiceConnectionException, ViewNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java
index e88f75b52eae40f3280384cbd8a52dbde9331609..4d0228f4108164eb463ccecd926d6a0ea52214c8 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java
@@ -85,8 +85,20 @@ public interface IdentifierService {
      */
     List<Identifier> findAll(IdentifierTypeDto type, Long databaseId, Long queryId, Long viewId, Long tableId);
 
+    /**
+     * Publishes a draft identifier with DataCite.
+     * @param identifierId The identifier id.
+     * @return The resulting identifier.
+     * @throws SearchServiceException
+     * @throws DatabaseNotFoundException
+     * @throws SearchServiceConnectionException
+     * @throws MalformedException
+     * @throws DataServiceConnectionException
+     * @throws IdentifierNotFoundException
+     */
     Identifier publish(Long identifierId) throws SearchServiceException, DatabaseNotFoundException,
-            SearchServiceConnectionException, MalformedException, ServiceConnectionException, IdentifierNotFoundException;
+            SearchServiceConnectionException, MalformedException, DataServiceConnectionException,
+            IdentifierNotFoundException, ExternalServiceException;
 
     /**
      * Creates a new identifier in the metadata database for a query or database.
@@ -95,10 +107,19 @@ public interface IdentifierService {
      * @param user     The user.
      * @param data     The data.
      * @return The created identifier from the metadata database if successful.
+     * @throws DataServiceException
+     * @throws DataServiceConnectionException
+     * @throws IdentifierNotFoundException
+     * @throws MalformedException
+     * @throws ViewNotFoundException
+     * @throws DatabaseNotFoundException
+     * @throws QueryNotFoundException
+     * @throws SearchServiceException
+     * @throws SearchServiceConnectionException
      */
-    Identifier save(Database database, User user, IdentifierSaveDto data) throws ServiceException,
-            ServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
-            DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException;
+    Identifier save(Database database, User user, IdentifierSaveDto data) throws DataServiceException,
+            DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
+            DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException;
 
     /**
      * Creates a new identifier in the metadata database for a query or database.
@@ -107,10 +128,19 @@ public interface IdentifierService {
      * @param user     The user.
      * @param data     The data.
      * @return The created identifier from the metadata database if successful.
+     * @throws DataServiceException
+     * @throws DataServiceConnectionException
+     * @throws IdentifierNotFoundException
+     * @throws MalformedException
+     * @throws ViewNotFoundException
+     * @throws DatabaseNotFoundException
+     * @throws QueryNotFoundException
+     * @throws SearchServiceException
+     * @throws SearchServiceConnectionException
      */
-    Identifier create(Database database, User user, IdentifierCreateDto data) throws ServiceException,
-            ServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
-            DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException;
+    Identifier create(Database database, User user, IdentifierCreateDto data) throws DataServiceException,
+            DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
+            DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException;
 
     /**
      * Export metadata for a identifier
@@ -135,8 +165,12 @@ public interface IdentifierService {
      *
      * @param identifier The identifier.
      * @return The XML resource, if successful.
+     * @throws DataServiceException
+     * @throws DataServiceConnectionException
+     * @throws IdentifierNotFoundException
+     * @throws QueryNotFoundException
      */
-    InputStreamResource exportResource(Identifier identifier) throws ServiceException, ServiceConnectionException,
+    InputStreamResource exportResource(Identifier identifier) throws DataServiceException, DataServiceConnectionException,
             IdentifierNotFoundException, QueryNotFoundException;
 
     /**
@@ -144,7 +178,13 @@ public interface IdentifierService {
      * database, but sets it as deleted.
      *
      * @param identifier The identifier.
+     * @throws DataServiceException
+     * @throws DataServiceConnectionException
+     * @throws IdentifierNotFoundException
+     * @throws DatabaseNotFoundException
+     * @throws SearchServiceException
+     * @throws SearchServiceConnectionException
      */
-    void delete(Identifier identifier) throws ServiceException, ServiceConnectionException, IdentifierNotFoundException,
+    void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException, IdentifierNotFoundException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java
index 0bed64884e98872842531fed2b46352615288de1..7cb195ce4ee59c919ff0377ece7636be2d091827 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java
@@ -14,6 +14,7 @@ public interface StorageService {
      * @param key    The object key.
      * @return The input stream, if successful.
      * @throws StorageUnavailableException The object failed to be loaded from the Storage Service.
+     * @throws StorageNotFoundException The object could not be found in the Storage Service.
      */
     InputStream getObject(String bucket, String key) throws StorageNotFoundException,
             StorageUnavailableException;
@@ -24,6 +25,7 @@ public interface StorageService {
      * @param key The object key.
      * @return The byte array.
      * @throws StorageUnavailableException The object failed to be loaded from the Storage Service.
+     * @throws StorageNotFoundException The object could not be found in the Storage Service.
      */
     byte[] getBytes(String key) throws StorageUnavailableException, StorageNotFoundException;
 
@@ -34,6 +36,7 @@ public interface StorageService {
      * @param key    The object key.
      * @return The byte array.
      * @throws StorageUnavailableException The object failed to be loaded from the Storage Service.
+     * @throws StorageNotFoundException The object could not be found in the Storage Service.
      */
     byte[] getBytes(String bucket, String key) throws StorageNotFoundException, StorageUnavailableException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java
index 0eb228ccd5d0a284b3c94e5735cff525ff86dfe1..e4767219063b8e9ee504a404be0bbfcf806270d9 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java
@@ -1,17 +1,13 @@
 package at.tuwien.service;
 
 import at.tuwien.api.database.table.TableCreateDto;
-import at.tuwien.api.database.table.TableHistoryDto;
-import at.tuwien.api.database.table.TableStatisticDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.exception.*;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.security.Principal;
-import java.util.List;
 
 public interface TableService {
 
@@ -43,7 +39,7 @@ public interface TableService {
      * @return The created table.
      */
     Table createTable(Database database, TableCreateDto createDto, Principal principal)
-            throws TableNotFoundException, ServiceException, ServiceConnectionException, UserNotFoundException,
+            throws TableNotFoundException, DataServiceException, DataServiceConnectionException, UserNotFoundException,
             DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException;
 
     /**
@@ -51,12 +47,12 @@ public interface TableService {
      *
      * @param table The table.
      */
-    void deleteTable(Table table) throws ServiceException, ServiceConnectionException, DatabaseNotFoundException, TableNotFoundException, SearchServiceException, SearchServiceConnectionException;
+    void deleteTable(Table table) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, TableNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
-    TableColumn update(TableColumn column, ColumnSemanticsUpdateDto updateDto) throws ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException;
+    TableColumn update(TableColumn column, ColumnSemanticsUpdateDto updateDto) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException;
 
     TableColumn findColumnById(Table table, Long columnId) throws MalformedException;
 
-    void updateStatistics(Table table) throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, ServiceException, ServiceConnectionException;
+    void updateStatistics(Table table) throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, DataServiceException, DataServiceConnectionException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java
index d19a3be73beab67d160e09dc892f2a0c46faaee1..a090ece3cb1182f23e37fcf3ba6821ab6254bd02 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java
@@ -33,7 +33,7 @@ public interface ViewService {
      *
      * @param view The view.
      */
-    void delete(View view) throws ServiceException, ServiceConnectionException, DatabaseNotFoundException,
+    void delete(View view) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
             ViewNotFoundException, SearchServiceException, SearchServiceConnectionException;
 
     /**
@@ -44,6 +44,6 @@ public interface ViewService {
      * @param data     The given query.
      * @return The view that was created.
      */
-    View create(Database database, User user, ViewCreateDto data) throws MalformedException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
+    View create(Database database, User user, ViewCreateDto data) throws MalformedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
index e1e6924e76a0f5f32e0fae9e91544ed0a2223c7c..aaa50251c3dc0dd79e51af1c983bfda07affffaa 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
@@ -62,8 +62,8 @@ public class AccessServiceImpl implements AccessService {
 
     @Override
     @Transactional
-    public DatabaseAccess create(Database database, User user, AccessTypeDto type) throws ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
+    public DatabaseAccess create(Database database, User user, AccessTypeDto type) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         /* create in data database */
         dataServiceGateway.createAccess(database.getId(), user.getId(), type);
@@ -85,8 +85,8 @@ public class AccessServiceImpl implements AccessService {
 
     @Override
     @Transactional
-    public void update(Database database, User user, AccessTypeDto access) throws ServiceException,
-            ServiceConnectionException, AccessNotFoundException, DatabaseNotFoundException, SearchServiceException,
+    public void update(Database database, User user, AccessTypeDto access) throws DataServiceException,
+            DataServiceConnectionException, AccessNotFoundException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         /* update in data database */
         dataServiceGateway.updateAccess(database.getId(), user.getId(), access);
@@ -112,8 +112,8 @@ public class AccessServiceImpl implements AccessService {
 
     @Override
     @Transactional
-    public void delete(Database database, User user) throws AccessNotFoundException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
+    public void delete(Database database, User user) throws AccessNotFoundException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         /* delete in data database */
         dataServiceGateway.deleteAccess(database.getId(), user.getId());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java
index c0ce71c996dbff1ca4cd943261b9954f035f6e3e..2800c96bc9d376e14cb990edb4d8fe5f9cc5d3a3 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java
@@ -27,7 +27,7 @@ public class BrokerServiceRabbitMqImpl implements BrokerService {
     }
 
     @Override
-    public void setVirtualHostPermissions(User user) throws ServiceException, ServiceConnectionException {
+    public void setVirtualHostPermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException {
         final GrantVirtualHostPermissionsDto permissions = GrantVirtualHostPermissionsDto.builder()
                 .configure("")
                 .write(".*")
@@ -39,7 +39,7 @@ public class BrokerServiceRabbitMqImpl implements BrokerService {
 
     @Override
     @Transactional(readOnly = true)
-    public void setTopicExchangePermissions(User user) throws ServiceException, ServiceConnectionException {
+    public void setTopicExchangePermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException {
         final GrantExchangePermissionsDto permissions = GrantExchangePermissionsDto.builder()
                 .exchange(rabbitConfig.getExchangeName())
                 .write(userToExchangeWritePermissionString(user))
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
index 87f178b1c0d7e0d0bdf4c2be9e883a1a56b26861..ed58148707440f4dc20728fafbbc19ad3fd06594 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
@@ -13,6 +13,7 @@ import at.tuwien.config.DataCiteConfig;
 import at.tuwien.config.EndpointConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.identifier.Identifier;
+import at.tuwien.entities.identifier.IdentifierStatusType;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.MetadataMapper;
@@ -69,9 +70,10 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
 
     @Override
     @Transactional
-    public Identifier publish(Long identifierId) throws MalformedException, ServiceConnectionException,
-            IdentifierNotFoundException {
+    public Identifier publish(Long identifierId) throws MalformedException, DataServiceConnectionException,
+            IdentifierNotFoundException, ExternalServiceException {
         final Identifier identifier = find(identifierId);
+        identifier.setStatus(IdentifierStatusType.PUBLISHED);
         identifier.setDoi(remoteSave(identifier, DataCiteDoiEvent.PUBLISH));
         return identifierRepository.save(identifier);
     }
@@ -94,19 +96,20 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
 
     @Override
     @Transactional(rollbackFor = {Exception.class})
-    public Identifier save(Database database, User user, IdentifierSaveDto data) throws ServiceException,
-            ServiceConnectionException, MalformedException, DatabaseNotFoundException, IdentifierNotFoundException,
-            ViewNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public Identifier save(Database database, User user, IdentifierSaveDto data) throws DataServiceException,
+            DataServiceConnectionException, MalformedException, DatabaseNotFoundException, IdentifierNotFoundException,
+            ViewNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException,
+            ExternalServiceException {
         data.setDoi(remoteSave(identifierService.save(database, user, data), DataCiteDoiEvent.REGISTER));
         return identifierService.save(database, user, data);
     }
 
     @Override
     @Transactional(rollbackFor = {Exception.class})
-    public Identifier create(Database database, User user, IdentifierCreateDto data) throws ServiceException,
-            ServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
+    public Identifier create(Database database, User user, IdentifierCreateDto data) throws DataServiceException,
+            DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
             DatabaseNotFoundException, QueryNotFoundException, SearchServiceException,
-            SearchServiceConnectionException {
+            SearchServiceConnectionException, ExternalServiceException {
         data.setDoi(remoteSave(identifierService.create(database, user, data), DataCiteDoiEvent.REGISTER));
         return identifierService.create(database, user, data);
     }
@@ -118,14 +121,15 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
      * @param event      The PID status event, e.g. publish
      * @return The DOI for this PID.
      * @throws MalformedException
-     * @throws ServiceConnectionException
+     * @throws DataServiceConnectionException
+     * @throws ExternalServiceException
      */
     public String remoteSave(Identifier identifier, DataCiteDoiEvent event) throws MalformedException,
-            ServiceConnectionException {
+            DataServiceConnectionException, ExternalServiceException {
         final HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
         headers.setBasicAuth(dataCiteConfig.getUsername(), dataCiteConfig.getPassword());
-        HttpEntity<DataCiteBody<DataCiteCreateDoi>> request = new HttpEntity<>(
+        final HttpEntity<DataCiteBody<DataCiteCreateDoi>> request = new HttpEntity<>(
                 DataCiteBody.<DataCiteCreateDoi>builder()
                         .data(DataCiteData.<DataCiteCreateDoi>builder()
                                 .type("dois")
@@ -139,11 +143,11 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
         final String url = dataCiteConfig.getUrl() + "/dois";
         log.trace("request doi from url {}", url);
         try {
-            ResponseEntity<DataCiteBody<DataCiteDoi>> response = restTemplate.exchange(url, HttpMethod.POST,
+            final ResponseEntity<DataCiteBody<DataCiteDoi>> response = restTemplate.exchange(url, HttpMethod.POST,
                     request, dataCiteBodyParameterizedTypeReference);
             if (response.getStatusCode() != HttpStatus.CREATED || response.getBody() == null) {
                 log.error("Failed to mint doi: {}", response);
-                throw new ServiceException("Failed to mint doi: " + response.getBody());
+                throw new ExternalServiceException("Failed to mint doi: " + response.getBody());
             }
             return response.getBody()
                     .getData()
@@ -154,9 +158,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
             throw new MalformedException("Failed to mint doi: malformed metadata: " + e.getMessage(), e);
         } catch (RestClientException e) {
             log.error("Failed to mint doi: {}", e.getMessage());
-            throw new ServiceConnectionException("Failed to mint doi: " + e.getMessage(), e);
-        } catch (ServiceException e) {
-            throw new RuntimeException(e);
+            throw new DataServiceConnectionException("Failed to mint doi: " + e.getMessage(), e);
         }
     }
 
@@ -196,14 +198,14 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
 
     @Override
     @Transactional(readOnly = true)
-    public InputStreamResource exportResource(Identifier identifier) throws ServiceException,
-            ServiceConnectionException, IdentifierNotFoundException, QueryNotFoundException {
+    public InputStreamResource exportResource(Identifier identifier) throws DataServiceException,
+            DataServiceConnectionException, IdentifierNotFoundException, QueryNotFoundException {
         return identifierService.exportResource(identifier);
     }
 
     @Override
     @Transactional
-    public void delete(Identifier identifier) throws ServiceException, ServiceConnectionException,
+    public void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         identifierService.delete(identifier);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
index f42992781c36e438233dd1d376c17d631ac7f584..8c835864db5ed4bf69bd2bd6b29adfe4d409899d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
@@ -62,6 +62,7 @@ public class DatabaseServiceImpl implements DatabaseService {
 
     @Override
     public Database findByInternalName(String internalName) throws DatabaseNotFoundException {
+        log.trace("find database by internal name: {}", internalName);
         final Optional<Database> database = databaseRepository.findByInternalName(internalName);
         if (database.isEmpty()) {
             log.error("Failed to find database with internal name {} in metadata database", internalName);
@@ -84,7 +85,7 @@ public class DatabaseServiceImpl implements DatabaseService {
     @Override
     @Transactional
     public Database create(DatabaseCreateDto data, User user) throws UserNotFoundException,
-            ContainerNotFoundException, ServiceException, ServiceConnectionException, DatabaseNotFoundException,
+            ContainerNotFoundException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         final Container container = containerService.find(data.getCid());
         Database database = Database.builder()
@@ -135,7 +136,7 @@ public class DatabaseServiceImpl implements DatabaseService {
 
     @Override
     @Transactional(readOnly = true)
-    public void updatePassword(Database database, User user) throws ServiceException, ServiceConnectionException,
+    public void updatePassword(Database database, User user) throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException {
         final List<Database> databases = databaseRepository.findReadAccess(user.getId())
                 .stream()
@@ -190,10 +191,10 @@ public class DatabaseServiceImpl implements DatabaseService {
     }
 
     @Override
-    @Transactional(rollbackFor = {SearchServiceException.class, SearchServiceConnectionException.class, DatabaseNotFoundException.class})
-    public Database updateTableMetadata(Database database) throws DatabaseNotFoundException, ServiceException,
-            SearchServiceException, SearchServiceConnectionException, QueryNotFoundException,
-            ServiceConnectionException, MalformedException {
+    @Transactional(rollbackFor = {Exception.class})
+    public Database updateTableMetadata(Database database) throws DatabaseNotFoundException, DataServiceException,
+            SearchServiceException, SearchServiceConnectionException, DataServiceConnectionException,
+            MalformedException, TableNotFoundException {
         for (TableDto table : dataServiceGateway.getTableSchemas(database.getId())) {
             if (database.getTables().stream().anyMatch(t -> t.getInternalName().equals(table.getInternalName()))) {
                 log.debug("fetched known table from data service: {}.{}", database.getInternalName(), table.getInternalName());
@@ -296,10 +297,10 @@ public class DatabaseServiceImpl implements DatabaseService {
     }
 
     @Override
-    @Transactional(rollbackFor = {SearchServiceException.class, SearchServiceConnectionException.class, DatabaseNotFoundException.class})
-    public Database updateViewMetadata(Database database) throws DatabaseNotFoundException, ServiceException,
-            SearchServiceException, SearchServiceConnectionException, QueryNotFoundException,
-            ServiceConnectionException {
+    @Transactional(rollbackFor = {Exception.class})
+    public Database updateViewMetadata(Database database) throws DatabaseNotFoundException, DataServiceException,
+            SearchServiceException, SearchServiceConnectionException, DataServiceConnectionException,
+            ViewNotFoundException {
         for (ViewDto view : dataServiceGateway.getViewSchemas(database.getId())) {
             if (database.getViews().stream().anyMatch(v -> v.getInternalName().equals(view.getInternalName()))) {
                 log.debug("fetched known view from data service: {}.{}", database.getInternalName(), view.getInternalName());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
index 37215d0787d6532eb03d8bf3ebdd8557f28d83e0..df0f895f5d2d3512444b2d3e10e28e14a70e2c45 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
@@ -155,7 +155,7 @@ public class IdentifierServiceImpl implements IdentifierService {
     @Override
     @Transactional
     public Identifier save(Database database, User user, IdentifierSaveDto data) throws SearchServiceException,
-            ServiceException, QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
+            DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
             SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
         final Identifier identifier = find(data.getId());
         identifier.setDatabase(database);
@@ -223,7 +223,7 @@ public class IdentifierServiceImpl implements IdentifierService {
     @Override
     @Transactional
     public Identifier create(Database database, User user, IdentifierCreateDto data) throws SearchServiceException,
-            ServiceException, QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
+            DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
             SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
         final Identifier identifier = metadataMapper.identifierCreateDtoToIdentifier(data);
         identifier.setDatabase(database);
@@ -276,9 +276,9 @@ public class IdentifierServiceImpl implements IdentifierService {
     }
 
     @Transactional
-    public Identifier save(Identifier identifier) throws ServiceException,
-            ServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException, DatabaseNotFoundException,
-            QueryNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public Identifier save(Identifier identifier) throws DataServiceException, DataServiceConnectionException,
+            IdentifierNotFoundException, ViewNotFoundException, DatabaseNotFoundException, QueryNotFoundException,
+            SearchServiceException, SearchServiceConnectionException {
         /* save identifier */
         switch (identifier.getType()) {
             case SUBSET -> {
@@ -356,15 +356,15 @@ public class IdentifierServiceImpl implements IdentifierService {
 
     @Override
     @Transactional(readOnly = true)
-    public InputStreamResource exportResource(Identifier identifier) throws ServiceException,
-            ServiceConnectionException, QueryNotFoundException {
+    public InputStreamResource exportResource(Identifier identifier) throws DataServiceException,
+            DataServiceConnectionException, QueryNotFoundException {
         final ExportResourceDto exportResource = dataServiceGateway.exportQuery(identifier.getDatabase().getId(), identifier.getQueryId());
         return exportResource.getResource();
     }
 
     @Override
     @Transactional
-    public void delete(Identifier identifier) throws ServiceException, ServiceConnectionException,
+    public void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException,
             IdentifierNotFoundException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         /* delete in metadata database */
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java
index 40eab251c9712c30ba960f9d1fbe3b8ca1f72c79..9ad86b7f905c75a174d5cf031c2f666f460e16d8 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java
@@ -29,6 +29,7 @@ public class StorageServiceS3Impl implements StorageService {
     @Override
     public InputStream getObject(String bucket, String key) throws StorageNotFoundException,
             StorageUnavailableException {
+        log.trace("get object with key {} from bucket {}", key, bucket);
         try {
             return s3Client.getObject(GetObjectRequest.builder()
                     .bucket(bucket)
@@ -45,11 +46,13 @@ public class StorageServiceS3Impl implements StorageService {
 
     @Override
     public byte[] getBytes(String key) throws StorageNotFoundException, StorageUnavailableException {
+        log.trace("get bytes with key {} from bucket {}", key, s3Config.getS3ImportBucket());
         return getBytes(s3Config.getS3ImportBucket(), key);
     }
 
     @Override
     public byte[] getBytes(String bucket, String key) throws StorageNotFoundException, StorageUnavailableException {
+        log.trace("get bytes with key {} from bucket {}", key, bucket);
         try {
             return getObject(bucket, key)
                     .readAllBytes();
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
index 593b612a9c36162abc5d97f1fb95ea11cbce7078..46a0602c74dd4c93cf5ef05c4ad0c51116be0cf6 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
@@ -95,9 +95,10 @@ public class TableServiceImpl implements TableService {
 
     @Override
     @Transactional
-    public Table createTable(Database database, TableCreateDto data, Principal principal) throws ServiceException,
-            ServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException,
-            TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException {
+    public Table createTable(Database database, TableCreateDto data, Principal principal) throws DataServiceException,
+            DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException,
+            TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException,
+            OntologyNotFoundException, SemanticEntityNotFoundException {
         final User owner = userService.findByUsername(principal.getName());
         /* check */
         if (data.getConstraints().getPrimaryKey().isEmpty()) {
@@ -217,7 +218,7 @@ public class TableServiceImpl implements TableService {
 
     @Override
     @Transactional
-    public void deleteTable(Table table) throws ServiceException, ServiceConnectionException,
+    public void deleteTable(Table table) throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, TableNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         /* delete at data service */
@@ -232,8 +233,8 @@ public class TableServiceImpl implements TableService {
 
     @Override
     @Transactional
-    public TableColumn update(TableColumn column, ColumnSemanticsUpdateDto data) throws ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
+    public TableColumn update(TableColumn column, ColumnSemanticsUpdateDto data) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException, MalformedException, OntologyNotFoundException,
             SemanticEntityNotFoundException {
         /* assign */
@@ -288,7 +289,7 @@ public class TableServiceImpl implements TableService {
     @Transactional
     public void updateStatistics(Table table) throws SearchServiceException,
             DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException,
-            ServiceException, ServiceConnectionException {
+            DataServiceException, DataServiceConnectionException {
         final TableStatisticDto statistic = dataServiceGateway.getTableStatistics(table.getTdbid(), table.getId());
         table.setNumRows(statistic.getRows());
         for (Map.Entry<String, ColumnStatisticDto> entry : statistic.getColumns().entrySet()) {
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
index a91e03284403b63453f129467f6ce7adaf7c0f90..0826d9dcc88e344227f56550b2aebd6f42e3494e 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
@@ -70,7 +70,7 @@ public class ViewServiceImpl implements ViewService {
 
     @Override
     @Transactional
-    public void delete(View view) throws ServiceException, ServiceConnectionException, DatabaseNotFoundException,
+    public void delete(View view) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
             ViewNotFoundException, SearchServiceException, SearchServiceConnectionException {
         /* delete in data service */
         dataServiceGateway.deleteView(view.getDatabase().getId(), view.getId());
@@ -84,8 +84,8 @@ public class ViewServiceImpl implements ViewService {
 
     @Override
     @Transactional
-    public View create(Database database, User creator, ViewCreateDto data) throws MalformedException, ServiceException,
-            ServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
+    public View create(Database database, User creator, ViewCreateDto data) throws MalformedException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
         /* create in metadata database */
         final View view = View.builder()
                 .vdbid(database.getId())
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/utils/FileUtil.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/utils/FileUtil.java
deleted file mode 100644
index 6e8b749c5f0a4a6d2720b003d2e5561584f4e9fe..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/utils/FileUtil.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package at.tuwien.utils;
-
-import lombok.extern.log4j.Log4j2;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.LinkedList;
-import java.util.List;
-
-@Log4j2
-public class FileUtil {
-
-    /**
-     * Loads a resource from the resource path when the application is compiled into a .jar and during runtime.
-     *
-     * @param resourcePath The path to the resource.
-     * @return The text contents of the resource.
-     * @throws IOException The resource could not be loaded.
-     */
-    public static List<String> loadResource(String resourcePath) throws IOException {
-        final InputStream inputStream = FileUtil.class.getResourceAsStream(resourcePath);
-        if (inputStream == null) {
-            log.error("Failed to load query store input stream file {}", resourcePath);
-            throw new IOException("Failed to load query store input stream file");
-        }
-        final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
-        final List<String> lines = new LinkedList<>();
-        while(reader.ready()) {
-            lines.add(reader.readLine());
-        }
-        inputStream.close();
-        reader.close();
-        return lines;
-    }
-
-}
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
index 4a8a66f729b06ac2c5287a48dccd42d9769c4acf..173a3ba9f41ce3d617b99f996d0c4bc0c482a5e3 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
@@ -1,5 +1,6 @@
 package at.tuwien.test;
 
+import at.tuwien.ExportResourceDto;
 import at.tuwien.api.amqp.*;
 import at.tuwien.api.auth.LoginRequestDto;
 import at.tuwien.api.auth.SignupRequestDto;
@@ -75,6 +76,7 @@ import at.tuwien.entities.user.User;
 import at.tuwien.test.utils.ArrayUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.InputStreamResource;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -82,6 +84,7 @@ import org.springframework.security.core.userdetails.UserDetails;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.nio.charset.Charset;
@@ -453,6 +456,14 @@ public abstract class BaseTest {
             .credentials(List.of(USER_1_KEYCLOAK_CREDENTIAL_1))
             .build();
 
+    public final static UserCreateDto USER_1_KEYCLOAK_SYSTEM_SIGNUP_REQUEST = UserCreateDto.builder()
+            .username(USER_1_USERNAME)
+            .email(USER_1_EMAIL)
+            .enabled(USER_1_ENABLED)
+            .credentials(List.of(USER_1_KEYCLOAK_CREDENTIAL_1))
+            .groups(List.of("system"))
+            .build();
+
     public final static PrivilegedUserDto USER_1_PRIVILEGED_DTO = PrivilegedUserDto.builder()
             .id(USER_1_ID)
             .username(USER_1_USERNAME)
@@ -4145,7 +4156,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             TableColumn.builder()
-                    .id(64L)
+                    .id(65L)
                     .ordinalPosition(20)
                     .table(TABLE_5)
                     .name("Class Type")
@@ -4376,7 +4387,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             ColumnDto.builder()
-                    .id(64L)
+                    .id(65L)
                     .ordinalPosition(20)
                     .tableId(TABLE_5_ID)
                     .table(TABLE_5_DTO)
@@ -4525,7 +4536,7 @@ public abstract class BaseTest {
             .build();
 
     public final static List<TableColumn> TABLE_6_COLUMNS = List.of(TableColumn.builder()
-                    .id(66L)
+                    .id(67L)
                     .ordinalPosition(0)
                     .table(TABLE_6)
                     .name("id")
@@ -4535,7 +4546,7 @@ public abstract class BaseTest {
                     .autoGenerated(true)
                     .build(),
             TableColumn.builder()
-                    .id(67L)
+                    .id(68L)
                     .ordinalPosition(1)
                     .table(TABLE_6)
                     .name("firstname")
@@ -4545,7 +4556,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             TableColumn.builder()
-                    .id(68L)
+                    .id(69L)
                     .ordinalPosition(2)
                     .table(TABLE_6)
                     .name("lastname")
@@ -4555,7 +4566,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             TableColumn.builder()
-                    .id(69L)
+                    .id(70L)
                     .ordinalPosition(3)
                     .table(TABLE_6)
                     .name("birth")
@@ -4565,7 +4576,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             TableColumn.builder()
-                    .id(70L)
+                    .id(71L)
                     .ordinalPosition(4)
                     .table(TABLE_6)
                     .name("reminder")
@@ -4576,7 +4587,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             TableColumn.builder()
-                    .id(71L)
+                    .id(72L)
                     .ordinalPosition(5)
                     .table(TABLE_6)
                     .name("ref_id")
@@ -4594,7 +4605,7 @@ public abstract class BaseTest {
             .build();
 
     public final static List<ColumnDto> TABLE_6_COLUMNS_DTO = List.of(ColumnDto.builder()
-                    .id(66L)
+                    .id(67L)
                     .ordinalPosition(0)
                     .tableId(TABLE_6_ID)
                     .table(TABLE_6_DTO)
@@ -4605,7 +4616,7 @@ public abstract class BaseTest {
                     .autoGenerated(true)
                     .build(),
             ColumnDto.builder()
-                    .id(67L)
+                    .id(68L)
                     .ordinalPosition(1)
                     .tableId(TABLE_6_ID)
                     .table(TABLE_6_DTO)
@@ -4616,7 +4627,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             ColumnDto.builder()
-                    .id(68L)
+                    .id(69L)
                     .ordinalPosition(2)
                     .tableId(TABLE_6_ID)
                     .table(TABLE_6_DTO)
@@ -4627,7 +4638,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             ColumnDto.builder()
-                    .id(69L)
+                    .id(70L)
                     .ordinalPosition(3)
                     .tableId(TABLE_6_ID)
                     .table(TABLE_6_DTO)
@@ -4638,7 +4649,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             ColumnDto.builder()
-                    .id(70L)
+                    .id(71L)
                     .ordinalPosition(4)
                     .tableId(TABLE_6_ID)
                     .table(TABLE_6_DTO)
@@ -4650,7 +4661,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             ColumnDto.builder()
-                    .id(71L)
+                    .id(72L)
                     .ordinalPosition(5)
                     .tableId(TABLE_6_ID)
                     .table(TABLE_6_DTO)
@@ -4714,7 +4725,7 @@ public abstract class BaseTest {
             .build();
 
     public final static List<TableColumn> TABLE_7_COLUMNS = List.of(TableColumn.builder()
-                    .id(26L)
+                    .id(74L)
                     .ordinalPosition(0)
                     .table(TABLE_7)
                     .name("name_id")
@@ -4724,7 +4735,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             TableColumn.builder()
-                    .id(27L)
+                    .id(75L)
                     .ordinalPosition(1)
                     .table(TABLE_7)
                     .name("zoo_id")
@@ -4735,7 +4746,7 @@ public abstract class BaseTest {
                     .build());
 
     public final static List<ColumnDto> TABLE_7_COLUMNS_DTO = List.of(ColumnDto.builder()
-                    .id(26L)
+                    .id(74L)
                     .ordinalPosition(0)
                     .tableId(TABLE_7_ID)
                     .table(TABLE_7_DTO)
@@ -4746,7 +4757,7 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build(),
             ColumnDto.builder()
-                    .id(27L)
+                    .id(75L)
                     .ordinalPosition(1)
                     .tableId(TABLE_7_ID)
                     .table(TABLE_7_DTO)
@@ -5762,6 +5773,7 @@ public abstract class BaseTest {
             .build();
 
     public final static IdentifierSaveDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder()
+            .id(null)
             .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION)
             .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO)
             .language(IDENTIFIER_1_DESCRIPTION_1_LANG_DTO)
@@ -5807,6 +5819,7 @@ public abstract class BaseTest {
             .build();
 
     public final static CreatorSaveDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder()
+            .id(null)
             .firstname(IDENTIFIER_1_CREATOR_1_FIRSTNAME)
             .lastname(IDENTIFIER_1_CREATOR_1_LASTNAME)
             .creatorName(IDENTIFIER_1_CREATOR_1_NAME)
@@ -5990,6 +6003,7 @@ public abstract class BaseTest {
             .publicationMonth(IDENTIFIER_1_PUBLICATION_MONTH)
             .publisher(IDENTIFIER_1_PUBLISHER)
             .type(IDENTIFIER_1_TYPE_DTO)
+            .doi(IDENTIFIER_1_DOI)
             .licenses(List.of(LICENSE_1_DTO))
             .creators(List.of(IDENTIFIER_1_CREATOR_1_CREATE_DTO))
             .funders(List.of(IDENTIFIER_1_FUNDER_1_CREATE_DTO))
@@ -6116,6 +6130,7 @@ public abstract class BaseTest {
             .build();
 
     public final static IdentifierSaveDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder()
+            .id(null)
             .description(IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION)
             .language(IDENTIFIER_5_DESCRIPTION_1_LANG_DTO)
             .descriptionType(IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO)
@@ -6375,6 +6390,7 @@ public abstract class BaseTest {
             .build();
 
     public final static IdentifierSaveDescriptionDto IDENTIFIER_6_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder()
+            .id(null)
             .description(IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION_MODIFY)
             .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO)
             .build();
@@ -6562,6 +6578,15 @@ public abstract class BaseTest {
     public final static IdentifierStatusType IDENTIFIER_7_STATUS_TYPE = IdentifierStatusType.DRAFT;
     public final static IdentifierStatusTypeDto IDENTIFIER_7_STATUS_TYPE_DTO = IdentifierStatusTypeDto.DRAFT;
 
+    public final static DataCiteBody<DataCiteDoi> IDENTIFIER_7_DATA_CITE = DataCiteBody.<DataCiteDoi>builder()
+            .data(DataCiteData.<DataCiteDoi>builder()
+                    .type("dois")
+                    .attributes(DataCiteDoi.builder()
+                            .doi(IDENTIFIER_7_DOI)
+                            .build())
+                    .build())
+            .build();
+
     private final static Long IDENTIFIER_7_CREATOR_1_ID = 6L;
 
     public final static Creator IDENTIFIER_7_CREATOR_1 = Creator.builder()
@@ -7823,6 +7848,11 @@ public abstract class BaseTest {
                     .build())))
             .build();
 
+    public final static ExportResourceDto EXPORT_RESOURCE_DTO = ExportResourceDto.builder()
+            .filename("68b329da9893e34099c7d8ad5cb9c940")
+            .resource(new InputStreamResource(InputStream.nullInputStream()))
+            .build();
+
     public static void saveObservedMetrics(Map<String, String> observedMetrics) throws IOException {
         final int keySize = observedMetrics.keySet().stream().max(Comparator.comparingInt(String::length)).get().length();
         final int valueSize = observedMetrics.values().stream().max(Comparator.comparingInt(String::length)).get().length();
diff --git a/dbrepo-search-service/app.py b/dbrepo-search-service/app.py
index 47f1f0254caa7bc0f2446faffd9af98dd9630a45..9b2aba7f0294cb5eebd006ea58d89fa4201a3b79 100644
--- a/dbrepo-search-service/app.py
+++ b/dbrepo-search-service/app.py
@@ -199,8 +199,6 @@ app.config["JWT_PUBKEY"] = '-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKE
 app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://localhost/api/auth")
 app.config["AUTH_SERVICE_CLIENT"] = os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client")
 app.config["AUTH_SERVICE_CLIENT_SECRET"] = os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG")
-app.config["ADMIN_USERNAME"] = os.getenv('ADMIN_USERNAME', 'admin')
-app.config["ADMIN_PASSWORD"] = os.getenv('ADMIN_PASSWORD', 'admin')
 app.config["OPENSEARCH_HOST"] = os.getenv('OPENSEARCH_HOST', 'localhost')
 app.config["OPENSEARCH_PORT"] = os.getenv('OPENSEARCH_PORT', '9200')
 app.config["OPENSEARCH_USERNAME"] = os.getenv('OPENSEARCH_USERNAME', 'admin')
@@ -227,8 +225,6 @@ def verify_token(token: str):
 def verify_password(username: str, password: str) -> Any:
     if username is None or username == "" or password is None or password == "":
         return False
-    if username == app.config["ADMIN_USERNAME"] and password == app.config["ADMIN_PASSWORD"]:
-        return User(username=username, roles=["admin"])
     client = KeycloakClient()
     try:
         return client.verify_jwt(access_token=client.obtain_user_token(username=username, password=password))
@@ -374,7 +370,7 @@ def post_general_search(type):
     if t1 is not None and t2 is not None and "unit.uri" in req_body and "concept.uri" in req_body:
         response = OpenSearchClient().unit_independent_search(t1, t2, req_body)
     else:
-        response = OpenSearchClient().general_search(type, t1, t2, req_body)
+        response = OpenSearchClient().general_search(type, req_body)
     # filter by type
     if type == 'table':
         tmp = []
@@ -431,7 +427,7 @@ def post_general_search(type):
 @app.route("/api/search/database/<int:database_id>", methods=["PUT"], endpoint="search_put_database")
 @metrics.gauge(name='dbrepo_search_update_database',
                description='Time needed to update a database in the search database')
-@auth.login_required(role=['admin'])
+@auth.login_required(role=['update-search-index'])
 def update_database(database_id: int) -> Database | ApiError:
     logging.debug(f"updating database with id: {database_id}")
     try:
diff --git a/dbrepo-search-service/clients/opensearch_client.py b/dbrepo-search-service/clients/opensearch_client.py
index 0af31277932407df47a513ee498d4e356ba8364c..623da7c2a07ffa220e3555a41cebf25bfea67a02 100644
--- a/dbrepo-search-service/clients/opensearch_client.py
+++ b/dbrepo-search-service/clients/opensearch_client.py
@@ -171,91 +171,38 @@ class OpenSearchClient:
         logging.info(f"Found {len(response['hits']['hits'])} result(s)")
         return response
 
-    def general_search(self, type=None, t1=None, t2=None, field_value_pairs=None):
+    def general_search(self, type: str = None, field_value_pairs: dict = None):
         """
         Main method for searching stuff in the opensearch db
 
         all parameters are optional
 
         :param type: The index to be searched. Optional.
-        :param t1: The start range value. Optional.
-        :param t2: The end range value. Optional.
         :param field_value_pairs: The key-value pair of properties that need to match. Optional.
         :return: The object of results and HTTP status code. e.g. { "hits": { "hits": [] } }, 200
         """
         musts = []
         if field_value_pairs is not None and len(field_value_pairs) > 0:
             logging.debug(f'field_value_pairs present: {field_value_pairs}')
-            is_range_open_end = False
-            is_range_open_begin = False
-            is_range_query = False
-            if t1 is not None and t2 is None:
-                is_range_open_begin = True
-                logging.debug(f"query has only start value {t1} present")
-            if t1 is None and t2 is not None:
-                is_range_open_end = True
-                logging.debug(f"query has only end value {t2} present")
-            if t1 is not None and t2 is not None:
-                is_range_query = True
-                logging.debug(f"query has start value {t1} and end value {t2} present")
             for key, value in field_value_pairs.items():
                 if field_value_pairs[key] == None:
                     logging.debug(f"skip empty key: {key}")
                     continue
                 logging.debug(f"processing key: {key}")
-                if is_range_open_end and re.match(f"unit\.", key):
-                    logging.debug(f"omit key={key} because query type=open end range and key is somewhat unit")
-                    logging.info(f"add match-query for range ),{t2}]")
+                if '.' in key:
+                    logging.debug(f'key {key} is nested: use nested query')
                     musts.append({
-                        "range": {
-                            "val_max": {
-                                "lte": t2
-                            }
-                        }
-                    })
-                elif is_range_open_begin and re.match(f"unit\.", key):
-                    logging.debug(f"omit key={key} because query type=open begin range and key is somewhat unit")
-                    logging.info(f"add match-query for range [{t1},(")
-                    musts.append({
-                        "range": {
-                            "val_min": {
-                                "gte": t1
-                            }
-                        }
-                    })
-                elif is_range_query and re.match(f"unit\.", key):
-                    logging.debug(
-                        f"omit key={key} because query type=full range and key is somewhat unit")
-                    logging.info(f"add match-query for range [{t1},{t2}]")
-                    musts.append({
-                        "range": {
-                            "val_min": {
-                                "gte": t1
-                            }
+                        "match": {
+                            key: value
                         }
                     })
+                else:
+                    logging.debug(f'key {key} is flat: use bool query')
                     musts.append({
-                        "range": {
-                            "val_max": {
-                                "lte": t2
-                            }
+                        "match": {
+                            key: {"query": value, "minimum_should_match": "90%"}
                         }
                     })
-                else:
-                    if '.' in key:
-                        logging.debug(f'key {key} is nested: use nested query')
-                        musts.append({
-                            "match": {
-                                key: value
-                            }
-                        })
-                    else:
-                        logging.debug(f'key {key} is flat: use bool query')
-                        musts.append({
-                            "match": {
-                                key: {"query": value, "minimum_should_match": "90%"}
-                            }
-                        })
         body = {
             "query": {"bool": {"must": musts}}
         }
@@ -290,7 +237,7 @@ class OpenSearchClient:
             }
         }
         response = self._instance().search(
-            index="column",
+            index="database",
             body=dumps(body)
         )
         unit_uris = [hit["key"] for hit in response["aggregations"]["units"]["buckets"]]
diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py
index 906aae0ccc0862703abc740622d793ed8388192b..7fe079d0f9e9d3dadb9e8189f0bcf39f16f0dc80 100644
--- a/dbrepo-search-service/test/test_opensearch_client.py
+++ b/dbrepo-search-service/test/test_opensearch_client.py
@@ -3,49 +3,77 @@ import unittest
 
 import opensearchpy
 from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Column, ColumnType, Constraints, \
-    PrimaryKey, TableMinimal, ColumnMinimal
+    PrimaryKey, TableMinimal, ColumnMinimal, Concept, Unit
+
 from app import app
 
 from clients.opensearch_client import OpenSearchClient
 
+req = Database(id=1,
+               name="Test",
+               internal_name="test_tuw1",
+               creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
+                            username="foo",
+                            attributes=UserAttributes(theme="dark")),
+               owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
+                          username="foo",
+                          attributes=UserAttributes(theme="dark")),
+               contact=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
+                            username="foo",
+                            attributes=UserAttributes(theme="dark")),
+               created=datetime.datetime(2024, 3, 25, 16, tzinfo=datetime.timezone.utc),
+               exchange_name="dbrepo",
+               is_public=True,
+               container=Container(id=1,
+                                   name="MariaDB",
+                                   internal_name="mariadb",
+                                   host="data-db",
+                                   port="3306",
+                                   created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc),
+                                   sidecar_host="data-db-sidecar",
+                                   sidecar_port=3305,
+                                   image=Image(id=1,
+                                               registry="docker.io",
+                                               name="mariadb",
+                                               version="11.1.3",
+                                               dialect="org.hibernate.dialect.MariaDBDialect",
+                                               driver_class="org.mariadb.jdbc.Driver",
+                                               jdbc_method="mariadb",
+                                               default_port=3306)),
+               tables=[Table(id=1, database_id=1, name="Data", internal_name="data",
+                             creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
+                                          username="foo",
+                                          attributes=UserAttributes(theme="dark")),
+                             owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
+                                        username="foo",
+                                        attributes=UserAttributes(theme="dark")),
+                             created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc),
+                             constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=[]),
+                             is_versioned=False,
+                             created_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
+                             queue_name="dbrepo",
+                             routing_key="dbrepo.1.1",
+                             is_public=True,
+                             columns=[Column(id=1, database_id=1, table_id=1, name="ID", internal_name="id",
+                                             auto_generated=True, column_type=ColumnType.BIGINT, is_public=True,
+                                             is_null_allowed=False, size=20, d=0,
+                                             concept=Concept(id=1, uri="http://www.wikidata.org/entity/Q2221906",
+                                                             created=datetime.datetime(2024, 3, 1, 10,
+                                                                                       tzinfo=datetime.timezone.utc)),
+                                             unit=Unit(id=1,
+                                                       uri="http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius",
+                                                       created=datetime.datetime(2024, 3, 1, 10,
+                                                                                 tzinfo=datetime.timezone.utc)),
+                                             val_min=0,
+                                             val_max=10)]
+                             )])
+
 
 class OpenSearchClientTest(unittest.TestCase):
 
     def test_update_database_succeeds(self):
         with app.app_context():
             client = OpenSearchClient()
-            req = Database(id=1,
-                           name="Test",
-                           internal_name="test_tuw1",
-                           creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                      username="foo",
-                                      attributes=UserAttributes(theme="dark")),
-                           contact=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           created=datetime.datetime(2024, 3, 25, 16, tzinfo=datetime.timezone.utc),
-                           exchange_name="dbrepo",
-                           is_public=True,
-                           container=Container(id=1,
-                                               name="MariaDB",
-                                               internal_name="mariadb",
-                                               host="data-db",
-                                               port="3306",
-                                               created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc),
-                                               sidecar_host="data-db-sidecar",
-                                               sidecar_port=3305,
-                                               image=Image(id=1,
-                                                           registry="docker.io",
-                                                           name="mariadb",
-                                                           version="11.1.3",
-                                                           dialect="org.hibernate.dialect.MariaDBDialect",
-                                                           driver_class="org.mariadb.jdbc.Driver",
-                                                           jdbc_method="mariadb",
-                                                           default_port=3306)),
-                           tables=[])
             # mock
             client.update_database(database_id=1, data=req)
 
@@ -132,38 +160,6 @@ class OpenSearchClientTest(unittest.TestCase):
     def test_update_database_create_succeeds(self):
         with app.app_context():
             client = OpenSearchClient()
-            req = Database(id=1,
-                           name="Test",
-                           internal_name="test_tuw1",
-                           creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                      username="foo",
-                                      attributes=UserAttributes(theme="dark")),
-                           contact=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           created=datetime.datetime(2024, 3, 25, 16, tzinfo=datetime.timezone.utc),
-                           exchange_name="dbrepo",
-                           is_public=True,
-                           container=Container(id=1,
-                                               name="MariaDB",
-                                               internal_name="mariadb",
-                                               host="data-db",
-                                               port="3306",
-                                               created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc),
-                                               sidecar_host="data-db-sidecar",
-                                               sidecar_port=3305,
-                                               image=Image(id=1,
-                                                           registry="docker.io",
-                                                           name="mariadb",
-                                                           version="11.1.3",
-                                                           dialect="org.hibernate.dialect.MariaDBDialect",
-                                                           driver_class="org.mariadb.jdbc.Driver",
-                                                           jdbc_method="mariadb",
-                                                           default_port=3306)),
-                           tables=[])
 
             # test
             database = client.update_database(database_id=1, data=req)
@@ -186,7 +182,18 @@ class OpenSearchClientTest(unittest.TestCase):
             # ...
             self.assertEqual(1, database.container.image.id)
             # ...
-            self.assertEqual(0, len(database.tables))
+            self.assertEqual(1, len(database.tables))
+
+    def test_update_database_malformed_fails(self):
+        with app.app_context():
+            app.config['OPENSEARCH_USERNAME'] = 'i_do_not_exist'
+            client = OpenSearchClient()
+
+            # test
+            try:
+                database = client.update_database(database_id=1, data=req)
+            except opensearchpy.exceptions.TransportError:
+                pass
 
     def test_delete_database_fails(self):
         with app.app_context():
@@ -201,38 +208,6 @@ class OpenSearchClientTest(unittest.TestCase):
     def test_delete_database_succeeds(self):
         with app.app_context():
             client = OpenSearchClient()
-            req = Database(id=1,
-                           name="Test",
-                           internal_name="test_tuw1",
-                           creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                      username="foo",
-                                      attributes=UserAttributes(theme="dark")),
-                           contact=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           created=datetime.datetime(2024, 3, 25, 16, 0, tzinfo=datetime.timezone.utc),
-                           exchange_name="dbrepo",
-                           is_public=True,
-                           container=Container(id=1,
-                                               name="MariaDB",
-                                               internal_name="mariadb",
-                                               host="data-db",
-                                               port="3306",
-                                               created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc),
-                                               sidecar_host="data-db-sidecar",
-                                               sidecar_port=3305,
-                                               image=Image(id=1,
-                                                           registry="docker.io",
-                                                           name="mariadb",
-                                                           version="11.1.3",
-                                                           dialect="org.hibernate.dialect.MariaDBDialect",
-                                                           driver_class="org.mariadb.jdbc.Driver",
-                                                           jdbc_method="mariadb",
-                                                           default_port=3306)),
-                           tables=[])
 
             # mock
             client.update_database(database_id=req.id, data=req)
@@ -243,38 +218,6 @@ class OpenSearchClientTest(unittest.TestCase):
     def test_find_database_succeeds(self):
         with app.app_context():
             client = OpenSearchClient()
-            req = Database(id=1,
-                           name="Test",
-                           internal_name="test_tuw1",
-                           creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                      username="foo",
-                                      attributes=UserAttributes(theme="dark")),
-                           contact=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
-                                        username="foo",
-                                        attributes=UserAttributes(theme="dark")),
-                           created=datetime.datetime(2024, 3, 25, 16, tzinfo=datetime.timezone.utc),
-                           exchange_name="dbrepo",
-                           is_public=True,
-                           container=Container(id=1,
-                                               name="MariaDB",
-                                               internal_name="mariadb",
-                                               host="data-db",
-                                               port="3306",
-                                               created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc),
-                                               sidecar_host="data-db-sidecar",
-                                               sidecar_port=3305,
-                                               image=Image(id=1,
-                                                           registry="docker.io",
-                                                           name="mariadb",
-                                                           version="11.1.3",
-                                                           dialect="org.hibernate.dialect.MariaDBDialect",
-                                                           driver_class="org.mariadb.jdbc.Driver",
-                                                           jdbc_method="mariadb",
-                                                           default_port=3306)),
-                           tables=[])
 
             # mock
             client.update_database(database_id=req.id, data=req)
@@ -286,8 +229,83 @@ class OpenSearchClientTest(unittest.TestCase):
         with app.app_context():
             client = OpenSearchClient()
 
+            # mock
+            client.update_database(database_id=1, data=req)
+
             # test
             try:
                 client.get_database(database_id=1)
             except opensearchpy.exceptions.NotFoundError:
                 pass
+
+    def test_query_index_by_term_opensearch_contains_succeeds(self):
+        with app.app_context():
+            client = OpenSearchClient()
+
+            # mock
+            client.update_database(database_id=1, data=req)
+
+            # test
+            response = client.query_index_by_term_opensearch(term="test", mode="contains")
+            self.assertEqual(1, len(response))
+            self.assertEqual(1, response[0]['id'])
+            self.assertEqual('Test', response[0]['name'])
+
+    def test_query_index_by_term_opensearch_exact_succeeds(self):
+        with app.app_context():
+            client = OpenSearchClient()
+
+            # mock
+            client.update_database(database_id=1, data=req)
+
+            # test
+            response = client.query_index_by_term_opensearch(term="test", mode="exact")
+            self.assertEqual(1, len(response))
+            self.assertEqual(1, response[0]['id'])
+            self.assertEqual('Test', response[0]['name'])
+
+    def test_get_fields_for_index_database_succeeds(self):
+        with app.app_context():
+            client = OpenSearchClient()
+
+            # mock
+            client.update_database(database_id=1, data=req)
+
+            # test
+            response = client.get_fields_for_index(type="database")
+            self.assertTrue(len(response) > 0)
+
+    def test_get_fields_for_index_user_succeeds(self):
+        with app.app_context():
+            client = OpenSearchClient()
+
+            # mock
+            client.update_database(database_id=1, data=req)
+
+            # test
+            response = client.get_fields_for_index(type="user")
+            self.assertTrue(len(response) > 0)
+
+    def test_fuzzy_search_succeeds(self):
+        with app.app_context():
+            client = OpenSearchClient()
+
+            # mock
+            client.update_database(database_id=1, data=req)
+
+            # test
+            response = client.fuzzy_search(search_term="test")
+            self.assertTrue(len(response) > 0)
+
+    def test_general_search_succeeds(self):
+        with app.app_context():
+            client = OpenSearchClient()
+
+            # mock
+            client.update_database(database_id=1, data=req)
+
+            # test
+            response = client.general_search(type="database", field_value_pairs={"name": "Test",
+                                                                                 "id": None})
+            self.assertTrue(len(response) > 0)
+
diff --git a/dbrepo-ui/Dockerfile b/dbrepo-ui/Dockerfile
index 14f1e57c1ecdbe729040dd929b5842ced137e6b4..d7b63d8f89b577a05878eb591b40f171e9431e0e 100644
--- a/dbrepo-ui/Dockerfile
+++ b/dbrepo-ui/Dockerfile
@@ -1,10 +1,8 @@
-FROM oven/bun:1.0.26-alpine as build
-MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
+FROM oven/bun:1.0.26-alpine AS build
 
 WORKDIR /app
 
 COPY ./package.json ./package.json
-COPY ./bun.lockb ./bun.lockb
 
 RUN bun install
 
@@ -27,7 +25,6 @@ COPY ./nuxt.config.ts ./nuxt.config.ts
 RUN bun run build
 
 FROM oven/bun:1.0.26-alpine as runtime
-MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
 
 ARG APP_VERSION="latest"
 ARG COMMIT=""
@@ -36,7 +33,9 @@ USER 1000
 
 WORKDIR /app
 
-COPY --from=build --chown=1000:1000 /app/.output /app/.output
+COPY --from=build --chown=1000 /app/.output /app/.output
+
+RUN chmod -R 755 /app/.output
 
 ENV NUXT_PUBLIC_VERSION="${APP_VERSION:-}"
 ENV NUXT_PUBLIC_COMMIT="${COMMIT:-}"
diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb
deleted file mode 100755
index 2ae1649f86a2cfc2d75d6e45a0c9490ad434ae02..0000000000000000000000000000000000000000
Binary files a/dbrepo-ui/bun.lockb and /dev/null differ
diff --git a/dbrepo-ui/locales/de-AT.json b/dbrepo-ui/locales/de-AT.json
index 7c2b2a149f4cde28256e8a92410fd76527da4e96..e32fe38ee0f835e7bd9c000b1669e2de22d289be 100644
--- a/dbrepo-ui/locales/de-AT.json
+++ b/dbrepo-ui/locales/de-AT.json
@@ -1179,6 +1179,13 @@
       "create": "Ansicht konnte nicht erstellt werden",
       "missing": "Die Ansicht konnte in der Metadatendatenbank nicht gefunden werden",
       "invalid": "Die Ansichtsabfrage konnte den Spalten im Datendienst nicht zugeordnet werden"
+    },
+    "broker": {
+      "connection": "Es konnte keine Verbindung zum Vermittlungsdienst hergestellt werden",
+      "invalid": "Es konnten keine Metadaten im Metadatendienst abgerufen werden"
+    },
+    "external": {
+      "invalid": "Metadaten konnten nicht aus dem Datacite-System abgerufen werden"
     }
   },
   "success": {
diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json
index c914fd774cc3d552d6a721563774447abad279d1..edf6c66ca15a752e442ed3c807c4cb3d31a7c8ff 100644
--- a/dbrepo-ui/locales/en-US.json
+++ b/dbrepo-ui/locales/en-US.json
@@ -1182,6 +1182,13 @@
       "create": "Failed to create view",
       "missing": "Failed to find view in metadata database",
       "invalid": "Failed to map view query to columns in data service"
+    },
+    "broker": {
+      "connection": "Failed to contact broker service",
+      "invalid": "Failed to obtain metadata in the broker service"
+    },
+    "external": {
+      "invalid": "Failed to obtain metadata from the datacite system"
     }
   },
   "success": {
diff --git a/docker-compose.yml b/docker-compose.yml
index 43c3fbbfb133fe87b0d1138d2d7cbce46750a3c6..b67e23fc62ca4aec283723ce2d5495b79ea59803 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -39,6 +39,7 @@ services:
     hostname: data-db
     image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6
     volumes:
+      - ./dbrepo-data-db/enable_history_insert.cnf:/opt/bitnami/mariadb/conf.default/enable_history_insert.cnf
       - "${SHARED_VOLUME:-/tmp}:/tmp"
       - data-db-data:/bitnami/mariadb
     ports:
@@ -116,8 +117,6 @@ services:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
       ADMIN_EMAIL: "${ADMIN_EMAIL:-noreply@localhost}"
-      ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}"
-      ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
       ANALYSE_SERVICE_ENDPOINT: "${ANALYSE_SERVICE_ENDPOINT:-http://gateway-service}"
       AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin}
       AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin}
@@ -152,6 +151,8 @@ services:
       S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}"
       S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}"
       SPARQL_CONNECTION_TIMEOUT: "${SPARQL_CONNECTION_TIMEOUT:-10000}"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+      SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}"
     healthcheck:
       test: curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1
       interval: 10s
@@ -180,8 +181,6 @@ services:
     ports:
       - "5000:8080"
     environment:
-      ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}"
-      ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
       AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}
@@ -265,8 +264,6 @@ services:
     ports:
       - "4000:8080"
     environment:
-      ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}"
-      ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
       AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}
@@ -382,8 +379,8 @@ services:
     environment:
       LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}"
       LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}"
-      LDAP_USERS: "${ADMIN_USERNAME:-admin}"
-      LDAP_PASSWORDS: "${ADMIN_PASSWORD:-admin}"
+      LDAP_USERS: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}"
+      LDAP_PASSWORDS: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}"
       LDAP_GROUP: "${ADMIN_GROUP:-system}"
       LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}"
       LDAP_ADMIN_DN: "${IDENTITY_SERVICE_ADMIN_DN:-cn=admin,dc=dbrepo,dc=at}"
@@ -486,8 +483,6 @@ services:
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
-      ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}"
-      ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}"
       AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin}
       AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin}
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
@@ -519,6 +514,8 @@ services:
       S3_FILE_PATH: "${S3_FILE_PATH:-/tmp}"
       S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}"
       S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+      SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}"
     healthcheck:
       test: curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1
       interval: 10s
diff --git a/helm/dbrepo/Chart.yaml b/helm/dbrepo/Chart.yaml
index 0e708f4669f6debdef8ee7df236c2654de8c832c..28ce12c838d2b92e5e6d383fa0309eea8d72d59f 100644
--- a/helm/dbrepo/Chart.yaml
+++ b/helm/dbrepo/Chart.yaml
@@ -4,13 +4,13 @@ description: Helm Chart for installing DBRepo
 sources:
   - https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services
 type: application
-version: "1.4.4"
-appVersion: "1.4.4"
+version: "1.4.5"
+appVersion: "1.4.5"
 keywords:
   - dbrepo
 maintainers:
   - name: Martin Weise
-    email: martin.weise@tuwien.ac.a
+    email: martin.weise@tuwien.ac.at
 home: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/
 icon: https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/dbrepo-ui/public/favicon.png
 dependencies:
diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md
index 48848c588c1698d2f578a0b39543ba6610d0bc4e..b310705b11665d8906a4093a2cc1ff73376527fd 100644
--- a/helm/dbrepo/README.md
+++ b/helm/dbrepo/README.md
@@ -45,6 +45,13 @@ The command removes all the Kubernetes components associated with the chart and
 
 ## Parameters
 
+### Global parameters
+
+| Name                                                  | Description                                                                                                                                                                                                                                                                                                                                                         | Value  |
+| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
+| `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` |
+| `global.storageClass`                                 | Global StorageClass for Persistent Volume(s)                                                                                                                                                                                                                                                                                                                        | `""`   |
+
 ### Common parameters
 
 | Name            | Description                        | Value                 |
@@ -137,67 +144,121 @@ The command removes all the Kubernetes components associated with the chart and
 
 ### Analyse Service
 
-| Name                          | Description                                                 | Value                           |
-| ----------------------------- | ----------------------------------------------------------- | ------------------------------- |
-| `analyseservice.enabled`      | Enable the Broker Service.                                  | `true`                          |
-| `analyseservice.image.debug`  | Set the logging level to `trace`. Otherwise, set to `info`. | `false`                         |
-| `analyseservice.endpoint`     | The url of the endpoint.                                    | `http://analyse-service`        |
-| `analyseservice.s3.endpoint`  | The S3-capable endpoint the microservice connects to.       | `http://storageservice-s3:9000` |
-| `analyseservice.replicaCount` | The number of replicas.                                     | `2`                             |
+| Name                                                               | Description                                                 | Value                           |
+| ------------------------------------------------------------------ | ----------------------------------------------------------- | ------------------------------- |
+| `analyseservice.enabled`                                           | Enable the Broker Service.                                  | `true`                          |
+| `analyseservice.image.debug`                                       | Set the logging level to `trace`. Otherwise, set to `info`. | `false`                         |
+| `analyseservice.podSecurityContext.enabled`                        | Enable pods' Security Context                               | `true`                          |
+| `analyseservice.podSecurityContext.fsGroupChangePolicy`            | Set filesystem group change policy                          | `Always`                        |
+| `analyseservice.podSecurityContext.sysctls`                        | Set kernel settings using the sysctl interface              | `[]`                            |
+| `analyseservice.podSecurityContext.supplementalGroups`             | Set filesystem extra groups                                 | `[]`                            |
+| `analyseservice.podSecurityContext.fsGroup`                        | Set RabbitMQ pod's Security Context fsGroup                 | `1001`                          |
+| `analyseservice.containerSecurityContext.enabled`                  | Enabled containers' Security Context                        | `true`                          |
+| `analyseservice.containerSecurityContext.seLinuxOptions`           | Set SELinux options in container                            | `""`                            |
+| `analyseservice.containerSecurityContext.runAsUser`                | Set RabbitMQ containers' Security Context runAsUser         | `1001`                          |
+| `analyseservice.containerSecurityContext.runAsGroup`               | Set RabbitMQ containers' Security Context runAsGroup        | `1001`                          |
+| `analyseservice.containerSecurityContext.runAsNonRoot`             | Set RabbitMQ container's Security Context runAsNonRoot      | `true`                          |
+| `analyseservice.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation                        | `false`                         |
+| `analyseservice.containerSecurityContext.readOnlyRootFilesystem`   | Set container's Security Context readOnlyRootFilesystem     | `false`                         |
+| `analyseservice.containerSecurityContext.capabilities.drop`        | Set container's Security Context runAsNonRoot               | `["ALL"]`                       |
+| `analyseservice.containerSecurityContext.seccompProfile.type`      | Set container's Security Context seccomp profile            | `RuntimeDefault`                |
+| `analyseservice.endpoint`                                          | The url of the endpoint.                                    | `http://analyse-service`        |
+| `analyseservice.s3.endpoint`                                       | The S3-capable endpoint the microservice connects to.       | `http://storageservice-s3:9000` |
+| `analyseservice.replicaCount`                                      | The number of replicas.                                     | `2`                             |
 
 ### Metadata Service
 
-| Name                                       | Description                                                                        | Value                           |
-| ------------------------------------------ | ---------------------------------------------------------------------------------- | ------------------------------- |
-| `metadataservice.enabled`                  | Enable the Metadata Service.                                                       | `true`                          |
-| `metadataservice.image.debug`              | Set the logging level to `trace`. Otherwise, set to `info`.                        | `false`                         |
-| `metadataservice.endpoint`                 | The Metadata Service endpoint.                                                     | `http://metadata-service`       |
-| `metadataservice.admin.email`              | The OAI-PMH exposed e-mail for contacting the metadata records responsible person. | `noreply@example.com`           |
-| `metadataservice.deletedRecord`            | The OAI-PMH exposed delete policy.                                                 | `permanent`                     |
-| `metadataservice.repositoryName`           | The OAI-PMH exposed repository name.                                               | `Database Repository`           |
-| `metadataservice.granularity`              | The OAI-PMH exposed record granularity.                                            | `YYYY-MM-DDThh:mm:ssZ`          |
-| `metadataservice.datacite.enabled`         | If set to true, the service mints DOIs instead of local PIDs.                      | `false`                         |
-| `metadataservice.datacite.url`             | The DataCite api endpoint url.                                                     | `https://api.datacite.org`      |
-| `metadataservice.datacite.prefix`          | The DataCite prefix.                                                               | `""`                            |
-| `metadataservice.datacite.username`        | The DataCite api username.                                                         | `""`                            |
-| `metadataservice.datacite.password`        | The DataCite api user password.                                                    | `""`                            |
-| `metadataservice.sparql.connectionTimeout` | The connection timeout for sparql queries fetching remote data in ms.              | `10000`                         |
-| `metadataservice.s3.endpoint`              | The S3-capable endpoint the microservice connects to.                              | `http://storageservice-s3:9000` |
-| `metadataservice.s3.auth.username`         | The S3-capable endpoint username (or access key id).                               | `seaweedfsadmin`                |
-| `metadataservice.s3.auth.password`         | The S3-capable endpoint user password (or access key secret).                      | `seaweedfsadmin`                |
-| `metadataservice.replicaCount`             | The number of replicas.                                                            | `2`                             |
+| Name                                                                | Description                                                                        | Value                           |
+| ------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------- |
+| `metadataservice.enabled`                                           | Enable the Broker Service.                                                         | `true`                          |
+| `metadataservice.image.debug`                                       | Set the logging level to `trace`. Otherwise, set to `info`.                        | `false`                         |
+| `metadataservice.podSecurityContext.enabled`                        | Enable pods' Security Context                                                      | `true`                          |
+| `metadataservice.podSecurityContext.fsGroupChangePolicy`            | Set filesystem group change policy                                                 | `Always`                        |
+| `metadataservice.podSecurityContext.sysctls`                        | Set kernel settings using the sysctl interface                                     | `[]`                            |
+| `metadataservice.podSecurityContext.supplementalGroups`             | Set filesystem extra groups                                                        | `[]`                            |
+| `metadataservice.podSecurityContext.fsGroup`                        | Set RabbitMQ pod's Security Context fsGroup                                        | `1001`                          |
+| `metadataservice.containerSecurityContext.enabled`                  | Enabled containers' Security Context                                               | `true`                          |
+| `metadataservice.containerSecurityContext.seLinuxOptions`           | Set SELinux options in container                                                   | `""`                            |
+| `metadataservice.containerSecurityContext.runAsUser`                | Set RabbitMQ containers' Security Context runAsUser                                | `1001`                          |
+| `metadataservice.containerSecurityContext.runAsGroup`               | Set RabbitMQ containers' Security Context runAsGroup                               | `1001`                          |
+| `metadataservice.containerSecurityContext.runAsNonRoot`             | Set RabbitMQ container's Security Context runAsNonRoot                             | `true`                          |
+| `metadataservice.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation                                               | `false`                         |
+| `metadataservice.containerSecurityContext.readOnlyRootFilesystem`   | Set container's Security Context readOnlyRootFilesystem                            | `false`                         |
+| `metadataservice.containerSecurityContext.capabilities.drop`        | Set container's Security Context runAsNonRoot                                      | `["ALL"]`                       |
+| `metadataservice.containerSecurityContext.seccompProfile.type`      | Set container's Security Context seccomp profile                                   | `RuntimeDefault`                |
+| `metadataservice.endpoint`                                          | The Metadata Service endpoint.                                                     | `http://metadata-service`       |
+| `metadataservice.admin.email`                                       | The OAI-PMH exposed e-mail for contacting the metadata records responsible person. | `noreply@example.com`           |
+| `metadataservice.deletedRecord`                                     | The OAI-PMH exposed delete policy.                                                 | `permanent`                     |
+| `metadataservice.repositoryName`                                    | The OAI-PMH exposed repository name.                                               | `Database Repository`           |
+| `metadataservice.granularity`                                       | The OAI-PMH exposed record granularity.                                            | `YYYY-MM-DDThh:mm:ssZ`          |
+| `metadataservice.datacite.enabled`                                  | If set to true, the service mints DOIs instead of local PIDs.                      | `false`                         |
+| `metadataservice.datacite.url`                                      | The DataCite api endpoint url.                                                     | `https://api.datacite.org`      |
+| `metadataservice.datacite.prefix`                                   | The DataCite prefix.                                                               | `""`                            |
+| `metadataservice.datacite.username`                                 | The DataCite api username.                                                         | `""`                            |
+| `metadataservice.datacite.password`                                 | The DataCite api user password.                                                    | `""`                            |
+| `metadataservice.sparql.connectionTimeout`                          | The connection timeout for sparql queries fetching remote data in ms.              | `10000`                         |
+| `metadataservice.s3.endpoint`                                       | The S3-capable endpoint the microservice connects to.                              | `http://storageservice-s3:9000` |
+| `metadataservice.s3.auth.username`                                  | The S3-capable endpoint username (or access key id).                               | `seaweedfsadmin`                |
+| `metadataservice.s3.auth.password`                                  | The S3-capable endpoint user password (or access key secret).                      | `seaweedfsadmin`                |
+| `metadataservice.replicaCount`                                      | The number of replicas.                                                            | `2`                             |
 
 ### Data Service
 
-| Name                                         | Description                                                                                                                                      | Value                                                                                                                       |
-| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
-| `dataservice.enabled`                        | Enable the Metadata Service.                                                                                                                     | `true`                                                                                                                      |
-| `dataservice.endpoint`                       | The endpoint for the microservices.                                                                                                              | `http://data-service`                                                                                                       |
-| `dataservice.image.debug`                    | Set the logging level to `trace`. Otherwise, set to `info`.                                                                                      | `false`                                                                                                                     |
-| `dataservice.grant.read`                     | The default database permissions for users with read access.                                                                                     | `SELECT`                                                                                                                    |
-| `dataservice.grant.write`                    | The default database permissions for users with write access.                                                                                    | `SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE` |
-| `dataservice.default.date`                   | The default date format id for dates. Default: YYYY-MM-dd (e.g. 2024-06-15).                                                                     | `3`                                                                                                                         |
-| `dataservice.default.time`                   | The default date format id for times. Default: HH:mm:ss (e.g. 14:23:42).                                                                         | `4`                                                                                                                         |
-| `dataservice.default.timestamp`              | The default date format id for timestamps. Default: YYYY-MM-dd HH:mm:ss (e.g. 2024-06-15 14:23:42).                                              | `1`                                                                                                                         |
-| `dataservice.rabbitmq.consumerConcurrentMin` | The minimal number of RabbitMQ consumers.                                                                                                        | `2`                                                                                                                         |
-| `dataservice.rabbitmq.consumerConcurrentMax` | The maximal number of RabbitMQ consumers.                                                                                                        | `6`                                                                                                                         |
-| `dataservice.rabbitmq.requeueRejected`       | If set to true, rejected tuples will be re-queued.                                                                                               | `false`                                                                                                                     |
-| `dataservice.rabbitmq.consumer.username`     | The username for the consumer to read tuples from the broker service. In many cases this value is equal to `identityservice.users`.              | `admin`                                                                                                                     |
-| `dataservice.rabbitmq.consumer.password`     | The user password for the consumer to read tuples from the broker service. In many cases this value is equal to `identityservice.userPasswords`. | `admin`                                                                                                                     |
-| `dataservice.s3.endpoint`                    | The S3-capable endpoint the microservice connects to.                                                                                            | `http://storageservice-s3:9000`                                                                                             |
-| `dataservice.s3.auth.username`               | The S3-capable endpoint username (or access key id).                                                                                             | `seaweedfsadmin`                                                                                                            |
-| `dataservice.s3.auth.password`               | The S3-capable endpoint user password (or access key secret).                                                                                    | `seaweedfsadmin`                                                                                                            |
-| `dataservice.s3.filePath`                    | The local location to download/upload files from/to S3-capable endpoint.                                                                         | `/s3`                                                                                                                       |
-| `dataservice.replicaCount`                   | The number of replicas.                                                                                                                          | `2`                                                                                                                         |
+| Name                                                            | Description                                                                                                                                      | Value                                                                                                                       |
+| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
+| `dataservice.enabled`                                           | Enable the Broker Service.                                                                                                                       | `true`                                                                                                                      |
+| `dataservice.image.debug`                                       | Set the logging level to `trace`. Otherwise, set to `info`.                                                                                      | `false`                                                                                                                     |
+| `dataservice.podSecurityContext.enabled`                        | Enable pods' Security Context                                                                                                                    | `true`                                                                                                                      |
+| `dataservice.podSecurityContext.fsGroupChangePolicy`            | Set filesystem group change policy                                                                                                               | `Always`                                                                                                                    |
+| `dataservice.podSecurityContext.sysctls`                        | Set kernel settings using the sysctl interface                                                                                                   | `[]`                                                                                                                        |
+| `dataservice.podSecurityContext.supplementalGroups`             | Set filesystem extra groups                                                                                                                      | `[]`                                                                                                                        |
+| `dataservice.podSecurityContext.fsGroup`                        | Set RabbitMQ pod's Security Context fsGroup                                                                                                      | `1001`                                                                                                                      |
+| `dataservice.containerSecurityContext.enabled`                  | Enabled containers' Security Context                                                                                                             | `true`                                                                                                                      |
+| `dataservice.containerSecurityContext.seLinuxOptions`           | Set SELinux options in container                                                                                                                 | `""`                                                                                                                        |
+| `dataservice.containerSecurityContext.runAsUser`                | Set RabbitMQ containers' Security Context runAsUser                                                                                              | `1001`                                                                                                                      |
+| `dataservice.containerSecurityContext.runAsGroup`               | Set RabbitMQ containers' Security Context runAsGroup                                                                                             | `1001`                                                                                                                      |
+| `dataservice.containerSecurityContext.runAsNonRoot`             | Set RabbitMQ container's Security Context runAsNonRoot                                                                                           | `true`                                                                                                                      |
+| `dataservice.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation                                                                                                             | `false`                                                                                                                     |
+| `dataservice.containerSecurityContext.readOnlyRootFilesystem`   | Set container's Security Context readOnlyRootFilesystem                                                                                          | `false`                                                                                                                     |
+| `dataservice.containerSecurityContext.capabilities.drop`        | Set container's Security Context runAsNonRoot                                                                                                    | `["ALL"]`                                                                                                                   |
+| `dataservice.containerSecurityContext.seccompProfile.type`      | Set container's Security Context seccomp profile                                                                                                 | `RuntimeDefault`                                                                                                            |
+| `dataservice.grant.read`                                        | The default database permissions for users with read access.                                                                                     | `SELECT`                                                                                                                    |
+| `dataservice.grant.write`                                       | The default database permissions for users with write access.                                                                                    | `SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE` |
+| `dataservice.default.date`                                      | The default date format id for dates. Default: YYYY-MM-dd (e.g. 2024-06-15).                                                                     | `3`                                                                                                                         |
+| `dataservice.default.time`                                      | The default date format id for times. Default: HH:mm:ss (e.g. 14:23:42).                                                                         | `4`                                                                                                                         |
+| `dataservice.default.timestamp`                                 | The default date format id for timestamps. Default: YYYY-MM-dd HH:mm:ss (e.g. 2024-06-15 14:23:42).                                              | `1`                                                                                                                         |
+| `dataservice.rabbitmq.consumerConcurrentMin`                    | The minimal number of RabbitMQ consumers.                                                                                                        | `2`                                                                                                                         |
+| `dataservice.rabbitmq.consumerConcurrentMax`                    | The maximal number of RabbitMQ consumers.                                                                                                        | `6`                                                                                                                         |
+| `dataservice.rabbitmq.requeueRejected`                          | If set to true, rejected tuples will be re-queued.                                                                                               | `false`                                                                                                                     |
+| `dataservice.rabbitmq.consumer.username`                        | The username for the consumer to read tuples from the broker service. In many cases this value is equal to `identityservice.users`.              | `admin`                                                                                                                     |
+| `dataservice.rabbitmq.consumer.password`                        | The user password for the consumer to read tuples from the broker service. In many cases this value is equal to `identityservice.userPasswords`. | `admin`                                                                                                                     |
+| `dataservice.s3.endpoint`                                       | The S3-capable endpoint the microservice connects to.                                                                                            | `http://storageservice-s3:9000`                                                                                             |
+| `dataservice.s3.auth.username`                                  | The S3-capable endpoint username (or access key id).                                                                                             | `seaweedfsadmin`                                                                                                            |
+| `dataservice.s3.auth.password`                                  | The S3-capable endpoint user password (or access key secret).                                                                                    | `seaweedfsadmin`                                                                                                            |
+| `dataservice.s3.filePath`                                       | The local location to download/upload files from/to S3-capable endpoint.                                                                         | `/s3`                                                                                                                       |
+| `dataservice.replicaCount`                                      | The number of replicas.                                                                                                                          | `2`                                                                                                                         |
 
 ### Search Service
 
-| Name                         | Description                                                 | Value                   |
-| ---------------------------- | ----------------------------------------------------------- | ----------------------- |
-| `searchservice.enabled`      | Enable the Search Service.                                  | `true`                  |
-| `searchservice.endpoint`     | The endpoint for the microservices.                         | `http://search-service` |
-| `searchservice.image.debug`  | Set the logging level to `trace`. Otherwise, set to `info`. | `false`                 |
-| `searchservice.replicaCount` | The number of replicas.                                     | `2`                     |
+| Name                                                              | Description                                                 | Value            |
+| ----------------------------------------------------------------- | ----------------------------------------------------------- | ---------------- |
+| `searchservice.enabled`                                           | Enable the Broker Service.                                  | `true`           |
+| `searchservice.image.debug`                                       | Set the logging level to `trace`. Otherwise, set to `info`. | `false`          |
+| `searchservice.podSecurityContext.enabled`                        | Enable pods' Security Context                               | `true`           |
+| `searchservice.podSecurityContext.fsGroupChangePolicy`            | Set filesystem group change policy                          | `Always`         |
+| `searchservice.podSecurityContext.sysctls`                        | Set kernel settings using the sysctl interface              | `[]`             |
+| `searchservice.podSecurityContext.supplementalGroups`             | Set filesystem extra groups                                 | `[]`             |
+| `searchservice.podSecurityContext.fsGroup`                        | Set RabbitMQ pod's Security Context fsGroup                 | `1001`           |
+| `searchservice.containerSecurityContext.enabled`                  | Enabled containers' Security Context                        | `true`           |
+| `searchservice.containerSecurityContext.seLinuxOptions`           | Set SELinux options in container                            | `""`             |
+| `searchservice.containerSecurityContext.runAsUser`                | Set RabbitMQ containers' Security Context runAsUser         | `1001`           |
+| `searchservice.containerSecurityContext.runAsGroup`               | Set RabbitMQ containers' Security Context runAsGroup        | `1001`           |
+| `searchservice.containerSecurityContext.runAsNonRoot`             | Set RabbitMQ container's Security Context runAsNonRoot      | `true`           |
+| `searchservice.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation                        | `false`          |
+| `searchservice.containerSecurityContext.readOnlyRootFilesystem`   | Set container's Security Context readOnlyRootFilesystem     | `true`           |
+| `searchservice.containerSecurityContext.capabilities.drop`        | Set container's Security Context runAsNonRoot               | `["ALL"]`        |
+| `searchservice.containerSecurityContext.seccompProfile.type`      | Set container's Security Context seccomp profile            | `RuntimeDefault` |
+| `searchservice.replicaCount`                                      | The number of replicas.                                     | `2`              |
 
 ### Storage Service
 
@@ -222,25 +283,39 @@ The command removes all the Kubernetes components associated with the chart and
 
 ### User Interface
 
-| Name                              | Description                                                                  | Value                   |
-| --------------------------------- | ---------------------------------------------------------------------------- | ----------------------- |
-| `ui.enabled`                      | Enable the User Interface.                                                   | `true`                  |
-| `ui.image.debug`                  | Set the logging level to `trace`. Otherwise, set to `info`.                  | `false`                 |
-| `ui.public.api.client`            | The endpoint for the client api.                                             | `""`                    |
-| `ui.public.api.server`            | The endpoint for the server api.                                             | `""`                    |
-| `ui.public.title`                 | The user interface title.                                                    | `Database Repository`   |
-| `ui.public.logo`                  | The user interface logo.                                                     | `/logo.svg`             |
-| `ui.public.icon`                  | The user interface icon.                                                     | `/favicon.ico`          |
-| `ui.public.touch`                 | The user interface apple touch icon.                                         | `/apple-touch-icon.png` |
-| `ui.public.broker.host`           | The displayed broker hostname.                                               | `example.com`           |
-| `ui.public.broker.port.5671`      | Enable display of the broker 5671 port and mark it as secure (SSL/TLS).      | `true`                  |
-| `ui.public.broker.port.5672`      | Enable display of the broker 5672 port and mark it as insecure (no SSL/TLS). | `false`                 |
-| `ui.public.broker.extra`          | Extra metadata displayed.                                                    | `""`                    |
-| `ui.public.database.extra`        | Extra metadata displayed.                                                    | `128.130.0.0/15`        |
-| `ui.public.pid.default.publisher` | The default dataset publisher for persisted identifiers.                     | `Example University`    |
-| `ui.public.doi.enabled`           | Enable the display that DOIs are minted.                                     | `false`                 |
-| `ui.public.doi.endpoint`          | The DOI proxy.                                                               | `https://doi.org`       |
-| `ui.replicaCount`                 | The number of replicas.                                                      | `2`                     |
+| Name                                                   | Description                                                                  | Value                   |
+| ------------------------------------------------------ | ---------------------------------------------------------------------------- | ----------------------- |
+| `ui.enabled`                                           | Enable the Broker Service.                                                   | `true`                  |
+| `ui.image.debug`                                       | Set the logging level to `trace`. Otherwise, set to `info`.                  | `false`                 |
+| `ui.podSecurityContext.enabled`                        | Enable pods' Security Context                                                | `true`                  |
+| `ui.podSecurityContext.fsGroupChangePolicy`            | Set filesystem group change policy                                           | `Always`                |
+| `ui.podSecurityContext.sysctls`                        | Set kernel settings using the sysctl interface                               | `[]`                    |
+| `ui.podSecurityContext.supplementalGroups`             | Set filesystem extra groups                                                  | `[]`                    |
+| `ui.podSecurityContext.fsGroup`                        | Set RabbitMQ pod's Security Context fsGroup                                  | `1001`                  |
+| `ui.containerSecurityContext.enabled`                  | Enabled containers' Security Context                                         | `true`                  |
+| `ui.containerSecurityContext.seLinuxOptions`           | Set SELinux options in container                                             | `""`                    |
+| `ui.containerSecurityContext.runAsUser`                | Set RabbitMQ containers' Security Context runAsUser                          | `1001`                  |
+| `ui.containerSecurityContext.runAsGroup`               | Set RabbitMQ containers' Security Context runAsGroup                         | `1001`                  |
+| `ui.containerSecurityContext.runAsNonRoot`             | Set RabbitMQ container's Security Context runAsNonRoot                       | `true`                  |
+| `ui.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation                                         | `false`                 |
+| `ui.containerSecurityContext.readOnlyRootFilesystem`   | Set container's Security Context readOnlyRootFilesystem                      | `false`                 |
+| `ui.containerSecurityContext.capabilities.drop`        | Set container's Security Context runAsNonRoot                                | `["ALL"]`               |
+| `ui.containerSecurityContext.seccompProfile.type`      | Set container's Security Context seccomp profile                             | `RuntimeDefault`        |
+| `ui.public.api.client`                                 | The endpoint for the client api.                                             | `""`                    |
+| `ui.public.api.server`                                 | The endpoint for the server api.                                             | `""`                    |
+| `ui.public.title`                                      | The user interface title.                                                    | `Database Repository`   |
+| `ui.public.logo`                                       | The user interface logo.                                                     | `/logo.svg`             |
+| `ui.public.icon`                                       | The user interface icon.                                                     | `/favicon.ico`          |
+| `ui.public.touch`                                      | The user interface apple touch icon.                                         | `/apple-touch-icon.png` |
+| `ui.public.broker.host`                                | The displayed broker hostname.                                               | `example.com`           |
+| `ui.public.broker.port.5671`                           | Enable display of the broker 5671 port and mark it as secure (SSL/TLS).      | `true`                  |
+| `ui.public.broker.port.5672`                           | Enable display of the broker 5672 port and mark it as insecure (no SSL/TLS). | `false`                 |
+| `ui.public.broker.extra`                               | Extra metadata displayed.                                                    | `""`                    |
+| `ui.public.database.extra`                             | Extra metadata displayed.                                                    | `128.130.0.0/15`        |
+| `ui.public.pid.default.publisher`                      | The default dataset publisher for persisted identifiers.                     | `Example University`    |
+| `ui.public.doi.enabled`                                | Enable the display that DOIs are minted.                                     | `false`                 |
+| `ui.public.doi.endpoint`                               | The DOI proxy.                                                               | `https://doi.org`       |
+| `ui.replicaCount`                                      | The number of replicas.                                                      | `2`                     |
 
 ### Ingress
 
diff --git a/helm/dbrepo/templates/_compatibility.tpl b/helm/dbrepo/templates/_compatibility.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..6fc2aa8fa45e3bf7a8cfdb5312515aa2c27a0491
--- /dev/null
+++ b/helm/dbrepo/templates/_compatibility.tpl
@@ -0,0 +1,42 @@
+{{/*
+Copyright Broadcom, Inc. All Rights Reserved.
+SPDX-License-Identifier: APACHE-2.0
+*/}}
+
+{{/* vim: set filetype=mustache: */}}
+
+{{/*
+Return true if the detected platform is Openshift
+Usage:
+{{- include "common.compatibility.isOpenshift" . -}}
+*/}}
+{{- define "common.compatibility.isOpenshift" -}}
+{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}}
+{{- true -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC
+Usage:
+{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}}
+*/}}
+{{- define "common.compatibility.renderSecurityContext" -}}
+{{- $adaptedContext := .secContext -}}
+
+{{- if (((.context.Values.global).compatibility).openshift) -}}
+  {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}}
+    {{/* Remove incompatible user/group values that do not work in Openshift out of the box */}}
+    {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}}
+    {{- if not .secContext.seLinuxOptions -}}
+    {{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}}
+    {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}}
+    {{- end -}}
+  {{- end -}}
+{{- end -}}
+{{/* Remove fields that are disregarded when running the container in privileged mode */}}
+{{- if $adaptedContext.privileged -}}
+  {{- $adaptedContext = omit $adaptedContext "capabilities" "seLinuxOptions" -}}
+{{- end -}}
+{{- omit $adaptedContext "enabled" | toYaml -}}
+{{- end -}}
\ No newline at end of file
diff --git a/helm/dbrepo/templates/analyse-deployment.yaml b/helm/dbrepo/templates/analyse-deployment.yaml
index 0cdb067ef7218710509f5febdb900b611e6d9f45..68d43e9cee8cab5e4f2073c3e23965e87f9197fe 100644
--- a/helm/dbrepo/templates/analyse-deployment.yaml
+++ b/helm/dbrepo/templates/analyse-deployment.yaml
@@ -22,25 +22,16 @@ spec:
         app: analyse-service
         service: analyse-service
     spec:
-      securityContext:
-        runAsNonRoot: true
-        fsGroup: 1001
-        runAsUser: 1001
-        runAsGroup: 1001
+      {{- if .Values.analyseservice.podSecurityContext.enabled }}
+      securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.analyseservice.podSecurityContext "context" $) | nindent 8 }}
+      {{- end }}
       containers:
         - name: analyse-service
           image: {{ .Values.analyseservice.image.name }}
           imagePullPolicy: {{ .Values.analyseservice.image.pullPolicy | default "IfNotPresent" }}
-          securityContext:
-            allowPrivilegeEscalation: false
-            runAsNonRoot: true
-            runAsUser: 1001
-            runAsGroup: 1001
-            seccompProfile:
-              type: {{ .Values.analyseservice.profileType | default "RuntimeDefault" }}
-            capabilities:
-              drop:
-                - ALL
+          {{- if .Values.analyseservice.containerSecurityContext.enabled }}
+          securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.analyseservice.containerSecurityContext "context" $) | nindent 12 }}
+          {{- end }}
           ports:
             - containerPort: 8080
               protocol: TCP
@@ -63,4 +54,7 @@ spec:
                 - "curl -sSL localhost:8080/health | grep 'UP' || exit 1"
             initialDelaySeconds: 10
             periodSeconds: 30
+          {{- if .Values.analyseservice.resources }}
+          resources: {{- toYaml .Values.analyseservice.resources | nindent 12 }}
+          {{- end }}
 {{- end }}
diff --git a/helm/dbrepo/templates/data-deployment.yaml b/helm/dbrepo/templates/data-deployment.yaml
index cb8fda09915c05f9556717ea8de3e5e7f174fd70..1d9e2352bd080702d61f94cf32915cba841293ad 100644
--- a/helm/dbrepo/templates/data-deployment.yaml
+++ b/helm/dbrepo/templates/data-deployment.yaml
@@ -22,25 +22,16 @@ spec:
         app: data-service
         service: data-service
     spec:
-      securityContext:
-        runAsNonRoot: true
-        fsGroup: 65534
-        runAsUser: 65534
-        runAsGroup: 65534
+      {{- if .Values.dataservice.podSecurityContext.enabled }}
+      securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dataservice.podSecurityContext "context" $) | nindent 8 }}
+      {{- end }}
       containers:
         - name: data-service
           image: {{ .Values.dataservice.image.name }}
           imagePullPolicy: {{ .Values.dataservice.image.pullPolicy | default "IfNotPresent" }}
-          securityContext:
-            allowPrivilegeEscalation: false
-            runAsNonRoot: true
-            runAsUser: 65534
-            runAsGroup: 65534
-            seccompProfile:
-              type: {{ .Values.dataservice.profileType | default "RuntimeDefault" }}
-            capabilities:
-              drop:
-                - ALL
+          {{- if .Values.dataservice.containerSecurityContext.enabled }}
+          securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dataservice.containerSecurityContext "context" $) | nindent 12 }}
+          {{- end }}
           ports:
             - containerPort: 80
               protocol: TCP
@@ -63,6 +54,9 @@ spec:
                 - "curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1"
             initialDelaySeconds: 30
             periodSeconds: 30
+          {{- if .Values.dataservice.resources }}
+          resources: {{- toYaml .Values.dataservice.resources | nindent 12 }}
+          {{- end }}
           volumeMounts: []
       volumes: []
 {{- end }}
diff --git a/helm/dbrepo/templates/metadata-deployment.yaml b/helm/dbrepo/templates/metadata-deployment.yaml
index 7c78f853e68b9be83e704f06ccf8340a2b13fd03..4d16efb68bc6987c71b551311d83a2bffe819be5 100644
--- a/helm/dbrepo/templates/metadata-deployment.yaml
+++ b/helm/dbrepo/templates/metadata-deployment.yaml
@@ -22,25 +22,16 @@ spec:
         app: metadata-service
         service: metadata-service
     spec:
-      securityContext:
-        runAsNonRoot: true
-        fsGroup: 65534
-        runAsUser: 65534
-        runAsGroup: 65534
+      {{- if .Values.metadataservice.podSecurityContext.enabled }}
+      securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.metadataservice.podSecurityContext "context" $) | nindent 8 }}
+      {{- end }}
       containers:
         - name: metadata-service
           image: {{ .Values.metadataservice.image.name }}
           imagePullPolicy: {{ .Values.metadataservice.image.pullPolicy | default "IfNotPresent" }}
-          securityContext:
-            allowPrivilegeEscalation: false
-            runAsNonRoot: true
-            runAsUser: 65534
-            runAsGroup: 65534
-            seccompProfile:
-              type: {{ .Values.metadataservice.profileType | default "RuntimeDefault" }}
-            capabilities:
-              drop:
-                - ALL
+          {{- if .Values.metadataservice.containerSecurityContext.enabled }}
+          securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.metadataservice.containerSecurityContext "context" $) | nindent 12 }}
+          {{- end }}
           ports:
             - containerPort: 80
               protocol: TCP
@@ -63,4 +54,7 @@ spec:
                 - "curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1"
             initialDelaySeconds: 30
             periodSeconds: 30
+          {{- if .Values.metadataservice.resources }}
+          resources: {{- toYaml .Values.metadataservice.resources | nindent 12 }}
+          {{- end }}
 {{- end }}
diff --git a/helm/dbrepo/templates/search-deployment.yaml b/helm/dbrepo/templates/search-deployment.yaml
index bd937c6650a4b4ec1f2d8fb57c886b753d1a3468..6ba54abfcab317ab3d1a93ebf7589cdcbbcd81c4 100644
--- a/helm/dbrepo/templates/search-deployment.yaml
+++ b/helm/dbrepo/templates/search-deployment.yaml
@@ -22,25 +22,16 @@ spec:
         app: search-service
         service: search-service
     spec:
-      securityContext:
-        runAsNonRoot: true
-        fsGroup: 1001
-        runAsUser: 1001
-        runAsGroup: 1001
+      {{- if .Values.searchservice.podSecurityContext.enabled }}
+      securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.searchservice.podSecurityContext "context" $) | nindent 8 }}
+      {{- end }}
       initContainers:
         - name: init
           image: {{ .Values.searchservice.init.image.name }}
           imagePullPolicy: {{ .Values.searchservice.init.image.pullPolicy | default "IfNotPresent" }}
-          securityContext:
-            allowPrivilegeEscalation: false
-            runAsNonRoot: true
-            runAsUser: 1001
-            runAsGroup: 1001
-            seccompProfile:
-              type: {{ .Values.searchservice.profileType | default "RuntimeDefault" }}
-            capabilities:
-              drop:
-                - ALL
+          {{- if .Values.searchservice.containerSecurityContext.enabled }}
+          securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.searchservice.containerSecurityContext "context" $) | nindent 12 }}
+          {{- end }}
           envFrom:
             - secretRef:
                 name: search-service-secret
@@ -80,6 +71,9 @@ spec:
                 - "curl -sSL localhost:8080/health | grep 'UP' || exit 1"
             initialDelaySeconds: 10
             periodSeconds: 30
+          {{- if .Values.searchservice.resources }}
+          resources: {{- toYaml .Values.searchservice.resources | nindent 12 }}
+          {{- end }}
           volumeMounts: [ ]
       volumes: [ ]
 {{- end }}
diff --git a/helm/dbrepo/templates/ui-deployment.yaml b/helm/dbrepo/templates/ui-deployment.yaml
index 3f8c042579af608e2bae1b3586088b06e1bc1baa..64cea9bf103dd3c66446ba353528b9ddb96b42a7 100644
--- a/helm/dbrepo/templates/ui-deployment.yaml
+++ b/helm/dbrepo/templates/ui-deployment.yaml
@@ -22,22 +22,16 @@ spec:
         app: ui
         service: ui
     spec:
-      securityContext:
-        runAsNonRoot: true
-        fsGroup: 1000
-        runAsUser: 1000
-        runAsGroup: 1000
+      {{- if .Values.ui.podSecurityContext.enabled }}
+      securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.ui.podSecurityContext "context" $) | nindent 8 }}
+      {{- end }}
       containers:
         - name: ui
           image: {{ .Values.ui.image.name }}
           imagePullPolicy: {{ .Values.ui.image.pullPolicy | default "IfNotPresent" }}
-          securityContext:
-            allowPrivilegeEscalation: false
-            seccompProfile:
-              type: {{ .Values.ui.profileType | default "RuntimeDefault" }}
-            capabilities:
-              drop:
-                - ALL
+          {{- if .Values.ui.containerSecurityContext.enabled }}
+          securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.ui.containerSecurityContext "context" $) | nindent 12 }}
+          {{- end }}
           ports:
             - containerPort: 3000
               protocol: TCP
@@ -143,6 +137,9 @@ spec:
               port: 3000
             initialDelaySeconds: 30
             periodSeconds: 30
+          {{- if .Values.ui.resources }}
+          resources: {{- toYaml .Values.ui.resources | nindent 12 }}
+          {{- end }}
       volumes:
         {{- if .Values.ui.extraVolumes }}
         {{- .Values.ui.extraVolumes | toYaml | nindent 8 }}
diff --git a/helm/dbrepo/values.schema.json b/helm/dbrepo/values.schema.json
index 5872dd5e3a81b779cdf37c01cac04afa2d73e17a..0e1d72462caa8ecaa85d9eacd79822cb19f89dd1 100644
--- a/helm/dbrepo/values.schema.json
+++ b/helm/dbrepo/values.schema.json
@@ -3,6 +3,51 @@
     "properties": {
         "analyseservice": {
             "properties": {
+                "containerSecurityContext": {
+                    "properties": {
+                        "allowPrivilegeEscalation": {
+                            "type": "boolean"
+                        },
+                        "capabilities": {
+                            "properties": {
+                                "drop": {
+                                    "items": {
+                                        "type": "string"
+                                    },
+                                    "type": "array"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "readOnlyRootFilesystem": {
+                            "type": "boolean"
+                        },
+                        "runAsGroup": {
+                            "type": "integer"
+                        },
+                        "runAsNonRoot": {
+                            "type": "boolean"
+                        },
+                        "runAsUser": {
+                            "type": "integer"
+                        },
+                        "seLinuxOptions": {
+                            "type": "string"
+                        },
+                        "seccompProfile": {
+                            "properties": {
+                                "type": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "enabled": {
                     "type": "boolean"
                 },
@@ -23,9 +68,56 @@
                     },
                     "type": "object"
                 },
+                "podSecurityContext": {
+                    "properties": {
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "fsGroup": {
+                            "type": "integer"
+                        },
+                        "fsGroupChangePolicy": {
+                            "type": "string"
+                        },
+                        "supplementalGroups": {
+                            "type": "array"
+                        },
+                        "sysctls": {
+                            "type": "array"
+                        }
+                    },
+                    "type": "object"
+                },
                 "replicaCount": {
                     "type": "integer"
                 },
+                "resources": {
+                    "properties": {
+                        "limits": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "requests": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "s3": {
                     "properties": {
                         "endpoint": {
@@ -579,6 +671,51 @@
         },
         "dataservice": {
             "properties": {
+                "containerSecurityContext": {
+                    "properties": {
+                        "allowPrivilegeEscalation": {
+                            "type": "boolean"
+                        },
+                        "capabilities": {
+                            "properties": {
+                                "drop": {
+                                    "items": {
+                                        "type": "string"
+                                    },
+                                    "type": "array"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "readOnlyRootFilesystem": {
+                            "type": "boolean"
+                        },
+                        "runAsGroup": {
+                            "type": "integer"
+                        },
+                        "runAsNonRoot": {
+                            "type": "boolean"
+                        },
+                        "runAsUser": {
+                            "type": "integer"
+                        },
+                        "seLinuxOptions": {
+                            "type": "string"
+                        },
+                        "seccompProfile": {
+                            "properties": {
+                                "type": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "default": {
                     "properties": {
                         "date": {
@@ -596,9 +733,6 @@
                 "enabled": {
                     "type": "boolean"
                 },
-                "endpoint": {
-                    "type": "string"
-                },
                 "grant": {
                     "properties": {
                         "read": {
@@ -624,6 +758,26 @@
                     },
                     "type": "object"
                 },
+                "podSecurityContext": {
+                    "properties": {
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "fsGroup": {
+                            "type": "integer"
+                        },
+                        "fsGroupChangePolicy": {
+                            "type": "string"
+                        },
+                        "supplementalGroups": {
+                            "type": "array"
+                        },
+                        "sysctls": {
+                            "type": "array"
+                        }
+                    },
+                    "type": "object"
+                },
                 "rabbitmq": {
                     "properties": {
                         "consumer": {
@@ -691,6 +845,27 @@
         "gateway": {
             "type": "string"
         },
+        "global": {
+            "properties": {
+                "compatibility": {
+                    "properties": {
+                        "openshift": {
+                            "properties": {
+                                "adaptSecurityContext": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
+                "storageClass": {
+                    "type": "string"
+                }
+            },
+            "type": "object"
+        },
         "hostname": {
             "type": "string"
         },
@@ -930,6 +1105,51 @@
                     },
                     "type": "object"
                 },
+                "containerSecurityContext": {
+                    "properties": {
+                        "allowPrivilegeEscalation": {
+                            "type": "boolean"
+                        },
+                        "capabilities": {
+                            "properties": {
+                                "drop": {
+                                    "items": {
+                                        "type": "string"
+                                    },
+                                    "type": "array"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "readOnlyRootFilesystem": {
+                            "type": "boolean"
+                        },
+                        "runAsGroup": {
+                            "type": "integer"
+                        },
+                        "runAsNonRoot": {
+                            "type": "boolean"
+                        },
+                        "runAsUser": {
+                            "type": "integer"
+                        },
+                        "seLinuxOptions": {
+                            "type": "string"
+                        },
+                        "seccompProfile": {
+                            "properties": {
+                                "type": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "datacite": {
                     "properties": {
                         "enabled": {
@@ -976,12 +1196,59 @@
                     },
                     "type": "object"
                 },
+                "podSecurityContext": {
+                    "properties": {
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "fsGroup": {
+                            "type": "integer"
+                        },
+                        "fsGroupChangePolicy": {
+                            "type": "string"
+                        },
+                        "supplementalGroups": {
+                            "type": "array"
+                        },
+                        "sysctls": {
+                            "type": "array"
+                        }
+                    },
+                    "type": "object"
+                },
                 "replicaCount": {
                     "type": "integer"
                 },
                 "repositoryName": {
                     "type": "string"
                 },
+                "resources": {
+                    "properties": {
+                        "limits": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "requests": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "s3": {
                     "properties": {
                         "auth": {
@@ -1065,12 +1332,54 @@
         },
         "searchservice": {
             "properties": {
+                "containerSecurityContext": {
+                    "properties": {
+                        "allowPrivilegeEscalation": {
+                            "type": "boolean"
+                        },
+                        "capabilities": {
+                            "properties": {
+                                "drop": {
+                                    "items": {
+                                        "type": "string"
+                                    },
+                                    "type": "array"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "readOnlyRootFilesystem": {
+                            "type": "boolean"
+                        },
+                        "runAsGroup": {
+                            "type": "integer"
+                        },
+                        "runAsNonRoot": {
+                            "type": "boolean"
+                        },
+                        "runAsUser": {
+                            "type": "integer"
+                        },
+                        "seLinuxOptions": {
+                            "type": "string"
+                        },
+                        "seccompProfile": {
+                            "properties": {
+                                "type": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "enabled": {
                     "type": "boolean"
                 },
-                "endpoint": {
-                    "type": "string"
-                },
                 "image": {
                     "properties": {
                         "debug": {
@@ -1101,8 +1410,55 @@
                     },
                     "type": "object"
                 },
+                "podSecurityContext": {
+                    "properties": {
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "fsGroup": {
+                            "type": "integer"
+                        },
+                        "fsGroupChangePolicy": {
+                            "type": "string"
+                        },
+                        "supplementalGroups": {
+                            "type": "array"
+                        },
+                        "sysctls": {
+                            "type": "array"
+                        }
+                    },
+                    "type": "object"
+                },
                 "replicaCount": {
                     "type": "integer"
+                },
+                "resources": {
+                    "properties": {
+                        "limits": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "requests": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
                 }
             },
             "type": "object"
@@ -1238,6 +1594,51 @@
         },
         "ui": {
             "properties": {
+                "containerSecurityContext": {
+                    "properties": {
+                        "allowPrivilegeEscalation": {
+                            "type": "boolean"
+                        },
+                        "capabilities": {
+                            "properties": {
+                                "drop": {
+                                    "items": {
+                                        "type": "string"
+                                    },
+                                    "type": "array"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "readOnlyRootFilesystem": {
+                            "type": "boolean"
+                        },
+                        "runAsGroup": {
+                            "type": "integer"
+                        },
+                        "runAsNonRoot": {
+                            "type": "boolean"
+                        },
+                        "runAsUser": {
+                            "type": "integer"
+                        },
+                        "seLinuxOptions": {
+                            "type": "string"
+                        },
+                        "seccompProfile": {
+                            "properties": {
+                                "type": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
                 "enabled": {
                     "type": "boolean"
                 },
@@ -1261,6 +1662,26 @@
                     },
                     "type": "object"
                 },
+                "podSecurityContext": {
+                    "properties": {
+                        "enabled": {
+                            "type": "boolean"
+                        },
+                        "fsGroup": {
+                            "type": "integer"
+                        },
+                        "fsGroupChangePolicy": {
+                            "type": "string"
+                        },
+                        "supplementalGroups": {
+                            "type": "array"
+                        },
+                        "sysctls": {
+                            "type": "array"
+                        }
+                    },
+                    "type": "object"
+                },
                 "public": {
                     "properties": {
                         "api": {
@@ -1372,6 +1793,33 @@
                 },
                 "replicaCount": {
                     "type": "integer"
+                },
+                "resources": {
+                    "properties": {
+                        "limits": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "requests": {
+                            "properties": {
+                                "cpu": {
+                                    "type": "string"
+                                },
+                                "memory": {
+                                    "type": "string"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
                 }
             },
             "type": "object"
diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml
index ba86f30cb74b8fa1acb4105b90ba66ff75559f1a..d910ff084fb38d08dde46d4f06c69c68450dc38d 100644
--- a/helm/dbrepo/values.yaml
+++ b/helm/dbrepo/values.yaml
@@ -1,23 +1,29 @@
 # Copyright the DBRepo developers
 # SPDX-License-Identifier: APACHE-2.0
 
+## @section Global parameters
+
+global:
+  ## Compatibility adaptations for Kubernetes platforms
+  compatibility:
+    ##  Compatibility adaptations for Openshift
+    openshift:
+      ## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation)
+      adaptSecurityContext: auto
+  ## @param global.storageClass Global StorageClass for Persistent Volume(s)
+  storageClass: ""
+
 ## @section Common parameters
-##
 
 ## @param namespace The namespace to install the chart
-##
 namespace: dbrepo
 ## @param hostname The hostname.
-##
 hostname: example.com
 ## @param gateway The gateway endpoint.
-##
 gateway: https://example.com
 ## @param strategyType The image pull
-##
 strategyType: RollingUpdate
 ## @param clusterDomain The cluster domain.
-##
 clusterDomain: cluster.local
 
 ## @section Metadata Database
@@ -336,6 +342,48 @@ analyseservice:
     pullPolicy: Always
     ## @param analyseservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`.
     debug: false
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
+  podSecurityContext:
+    ## @param analyseservice.podSecurityContext.enabled Enable pods' Security Context
+    enabled: true
+    ## @param analyseservice.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy
+    fsGroupChangePolicy: Always
+    ## @param analyseservice.podSecurityContext.sysctls Set kernel settings using the sysctl interface
+    sysctls: [ ]
+    ## @param analyseservice.podSecurityContext.supplementalGroups Set filesystem extra groups
+    supplementalGroups: [ ]
+    ## @param analyseservice.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup
+    fsGroup: 1001
+  containerSecurityContext:
+    ## @param analyseservice.containerSecurityContext.enabled Enabled containers' Security Context
+    enabled: true
+    ## @param analyseservice.containerSecurityContext.seLinuxOptions Set SELinux options in container
+    seLinuxOptions: ""
+    ## @param analyseservice.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser
+    runAsUser: 1001
+    ## @param analyseservice.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup
+    runAsGroup: 1001
+    ## @param analyseservice.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot
+    runAsNonRoot: true
+    ## @param analyseservice.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation
+    allowPrivilegeEscalation: false
+    ## @param analyseservice.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem
+    readOnlyRootFilesystem: false
+    capabilities:
+      ## @param analyseservice.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot
+      drop: [ "ALL" ]
+    seccompProfile:
+      ## @param analyseservice.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile
+      type: "RuntimeDefault"
+  ## @skip analyseservice.resources
+  resources:
+    requests:
+      cpu: 250m
+      memory: 512Mi
+    limits:
+      cpu: 500m
+      memory: 2048Mi
+
   ## @param analyseservice.endpoint The url of the endpoint.
   endpoint: http://analyse-service
   s3:
@@ -347,7 +395,7 @@ analyseservice:
 ## @section Metadata Service
 
 metadataservice:
-  ## @param metadataservice.enabled Enable the Metadata Service.
+  ## @param metadataservice.enabled Enable the Broker Service.
   enabled: true
   image:
     ## @skip metadataservice.image.name
@@ -356,6 +404,47 @@ metadataservice:
     pullPolicy: Always
     ## @param metadataservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`.
     debug: false
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
+  podSecurityContext:
+    ## @param metadataservice.podSecurityContext.enabled Enable pods' Security Context
+    enabled: true
+    ## @param metadataservice.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy
+    fsGroupChangePolicy: Always
+    ## @param metadataservice.podSecurityContext.sysctls Set kernel settings using the sysctl interface
+    sysctls: [ ]
+    ## @param metadataservice.podSecurityContext.supplementalGroups Set filesystem extra groups
+    supplementalGroups: [ ]
+    ## @param metadataservice.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup
+    fsGroup: 1001
+  containerSecurityContext:
+    ## @param metadataservice.containerSecurityContext.enabled Enabled containers' Security Context
+    enabled: true
+    ## @param metadataservice.containerSecurityContext.seLinuxOptions Set SELinux options in container
+    seLinuxOptions: ""
+    ## @param metadataservice.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser
+    runAsUser: 1001
+    ## @param metadataservice.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup
+    runAsGroup: 1001
+    ## @param metadataservice.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot
+    runAsNonRoot: true
+    ## @param metadataservice.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation
+    allowPrivilegeEscalation: false
+    ## @param metadataservice.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem
+    readOnlyRootFilesystem: false
+    capabilities:
+      ## @param metadataservice.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot
+      drop: [ "ALL" ]
+    seccompProfile:
+      ## @param metadataservice.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile
+      type: "RuntimeDefault"
+  ## @skip metadataservice.resources
+  resources:
+    requests:
+      cpu: 250m
+      memory: 512Mi
+    limits:
+      cpu: 1000m
+      memory: 2048Mi
   ## @param metadataservice.endpoint The Metadata Service endpoint.
   endpoint: http://metadata-service
   admin:
@@ -399,10 +488,8 @@ metadataservice:
 ## @section Data Service
 
 dataservice:
-  ## @param dataservice.enabled Enable the Metadata Service.
+  ## @param dataservice.enabled Enable the Broker Service.
   enabled: true
-  ## @param dataservice.endpoint The endpoint for the microservices.
-  endpoint: http://data-service
   image:
     ## @skip dataservice.image.name
     name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.4.4
@@ -410,6 +497,40 @@ dataservice:
     pullPolicy: Always
     ## @param dataservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`.
     debug: false
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
+  podSecurityContext:
+    ## @param dataservice.podSecurityContext.enabled Enable pods' Security Context
+    enabled: true
+    ## @param dataservice.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy
+    fsGroupChangePolicy: Always
+    ## @param dataservice.podSecurityContext.sysctls Set kernel settings using the sysctl interface
+    sysctls: [ ]
+    ## @param dataservice.podSecurityContext.supplementalGroups Set filesystem extra groups
+    supplementalGroups: [ ]
+    ## @param dataservice.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup
+    fsGroup: 1001
+  containerSecurityContext:
+    ## @param dataservice.containerSecurityContext.enabled Enabled containers' Security Context
+    enabled: true
+    ## @param dataservice.containerSecurityContext.seLinuxOptions Set SELinux options in container
+    seLinuxOptions: ""
+    ## @param dataservice.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser
+    runAsUser: 1001
+    ## @param dataservice.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup
+    runAsGroup: 1001
+    ## @param dataservice.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot
+    runAsNonRoot: true
+    ## @param dataservice.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation
+    allowPrivilegeEscalation: false
+    ## @param dataservice.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem
+    readOnlyRootFilesystem: false
+    capabilities:
+      ## @param dataservice.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot
+      drop: [ "ALL" ]
+    seccompProfile:
+      ## @param dataservice.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile
+      type: "RuntimeDefault"
+  ## @skip dataservice.resources
   grant:
     ## @param dataservice.grant.read The default database permissions for users with read access.
     read: SELECT
@@ -454,10 +575,8 @@ dataservice:
 ## @section Search Service
 
 searchservice:
-  ## @param searchservice.enabled Enable the Search Service.
+  ## @param searchservice.enabled Enable the Broker Service.
   enabled: true
-  ## @param searchservice.endpoint The endpoint for the microservices.
-  endpoint: http://search-service
   image:
     ## @skip searchservice.image.name
     name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.4.4
@@ -465,6 +584,47 @@ searchservice:
     pullPolicy: Always
     ## @param searchservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`.
     debug: false
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
+  podSecurityContext:
+    ## @param searchservice.podSecurityContext.enabled Enable pods' Security Context
+    enabled: true
+    ## @param searchservice.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy
+    fsGroupChangePolicy: Always
+    ## @param searchservice.podSecurityContext.sysctls Set kernel settings using the sysctl interface
+    sysctls: [ ]
+    ## @param searchservice.podSecurityContext.supplementalGroups Set filesystem extra groups
+    supplementalGroups: [ ]
+    ## @param searchservice.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup
+    fsGroup: 1001
+  containerSecurityContext:
+    ## @param searchservice.containerSecurityContext.enabled Enabled containers' Security Context
+    enabled: true
+    ## @param searchservice.containerSecurityContext.seLinuxOptions Set SELinux options in container
+    seLinuxOptions: ""
+    ## @param searchservice.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser
+    runAsUser: 1001
+    ## @param searchservice.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup
+    runAsGroup: 1001
+    ## @param searchservice.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot
+    runAsNonRoot: true
+    ## @param searchservice.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation
+    allowPrivilegeEscalation: false
+    ## @param searchservice.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem
+    readOnlyRootFilesystem: true
+    capabilities:
+      ## @param searchservice.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot
+      drop: [ "ALL" ]
+    seccompProfile:
+      ## @param searchservice.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile
+      type: "RuntimeDefault"
+  ## @skip searchservice.resources
+  resources:
+    requests:
+      cpu: 250m
+      memory: 512Mi
+    limits:
+      cpu: 1000m
+      memory: 2048Mi
   ## @skip searchservice.init
   init:
     image:
@@ -574,7 +734,7 @@ identityservice:
 ## @section User Interface
 
 ui:
-  ## @param ui.enabled Enable the User Interface.
+  ## @param ui.enabled Enable the Broker Service.
   enabled: true
   image:
     ## @skip ui.image.name
@@ -583,6 +743,47 @@ ui:
     pullPolicy: Always
     ## @param ui.image.debug Set the logging level to `trace`. Otherwise, set to `info`.
     debug: false
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
+  podSecurityContext:
+    ## @param ui.podSecurityContext.enabled Enable pods' Security Context
+    enabled: true
+    ## @param ui.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy
+    fsGroupChangePolicy: Always
+    ## @param ui.podSecurityContext.sysctls Set kernel settings using the sysctl interface
+    sysctls: [ ]
+    ## @param ui.podSecurityContext.supplementalGroups Set filesystem extra groups
+    supplementalGroups: [ ]
+    ## @param ui.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup
+    fsGroup: 1001
+  containerSecurityContext:
+    ## @param ui.containerSecurityContext.enabled Enabled containers' Security Context
+    enabled: true
+    ## @param ui.containerSecurityContext.seLinuxOptions Set SELinux options in container
+    seLinuxOptions: ""
+    ## @param ui.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser
+    runAsUser: 1001
+    ## @param ui.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup
+    runAsGroup: 1001
+    ## @param ui.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot
+    runAsNonRoot: true
+    ## @param ui.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation
+    allowPrivilegeEscalation: false
+    ## @param ui.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem
+    readOnlyRootFilesystem: false
+    capabilities:
+      ## @param ui.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot
+      drop: [ "ALL" ]
+    seccompProfile:
+      ## @param ui.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile
+      type: "RuntimeDefault"
+  ## @skip ui.resources
+  resources:
+    requests:
+      cpu: 250m
+      memory: 512Mi
+    limits:
+      cpu: 1000m
+      memory: 2048Mi
   public:
     api:
       ## @param ui.public.api.client The endpoint for the client api.
diff --git a/make/gen.mk b/make/gen.mk
index 1f8e6fd45d1bc1b7451599bcd4722633038c17eb..b81d504213bdee6cae172d1edfc18db82f2ef65a 100644
--- a/make/gen.mk
+++ b/make/gen.mk
@@ -1,6 +1,6 @@
 ##@ Generate
 
-.PHONY: gen-swagger-doc-fe
+.PHONY: gen-swagger-doc
 gen-swagger-doc: build-images ## Generate Swagger documentation and fetch.
 	docker compose up -d
 	bash .docs/.swagger/swagger-generate.sh
diff --git a/make/test.mk b/make/test.mk
index 5760075a2956bf282b7243ff78993b5022aebc7f..c3d2cd8804831f25d7450d0f34914c69c6f53477 100644
--- a/make/test.mk
+++ b/make/test.mk
@@ -15,30 +15,3 @@ test-analyse-service: ## Test the Analyse Service.
 .PHONY: test-lib
 test-lib: ## Test the Python Library.
 	bash ./lib/python/test.sh
-
-.PHONY: scan-images
-scan-images: ## Scan the docker images for vulnerabilities.
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-analyse-service-report.json dbrepo-analyse-service:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-analyse-service:latest
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-authentication-service-report.json dbrepo-authentication-service:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-authentication-service:latest
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-broker-service-report.json bitnami/rabbitmq:3.10
-	trivy image --insecure --exit-code 1 --severity CRITICAL bitnami/rabbitmq:3.10
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-gateway-service-report.json "nginx:1.25.0-alpine-slim"
-	trivy image --insecure --exit-code 1 --severity CRITICAL "nginx:1.25.0-alpine-slim"
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-metadata-db-report.json dbrepo-metadata-db:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-metadata-db:latest
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-metadata-service-report.json dbrepo-metadata-service:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-metadata-service:latest
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-data-service-report.json dbrepo-data-service:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-data-service:latest
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-search-db-report.json "dbrepo-search-db"
-	trivy image --insecure --exit-code 1 --severity CRITICAL "dbrepo-search-db"
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-search-db-report.json "opensearchproject/opensearch-dashboards:2.10.0"
-	trivy image --insecure --exit-code 1 --severity CRITICAL "opensearchproject/opensearch-dashboards:2.10.0"
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-data-db-report.json "bitnami/mariadb:11.2.2-debian-11-r0"
-	trivy image --insecure --exit-code 1 --severity CRITICAL "bitnami/mariadb:11.2.2-debian-11-r0"
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-ui-report.json dbrepo-ui:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-ui:latest
-	trivy image --insecure --exit-code 0 --format template --template "@.trivy/gitlab.tpl" -o ./.trivy/trivy-search-service-report.json dbrepo-search-service:latest
-	trivy image --insecure --exit-code 1 --severity CRITICAL dbrepo-search-service:latest
\ No newline at end of file