diff --git a/.docs/api/ui.md b/.docs/api/ui.md
index 4ac5c7bad871284cc322bf7be0c8585942f63ea5..cfffcebc0f733e6569b88f8dc3a31b867cc745e5 100644
--- a/.docs/api/ui.md
+++ b/.docs/api/ui.md
@@ -20,26 +20,67 @@ image as well, in this example we want to mount a custom logo `my_logo.png` into
 <figcaption>Figure 1: Architecture of the UI microservice</figcaption>
 </figure>
 
-Text values like the version :material-numeric-2-circle-outline: and title :material-numeric-3-circle-outline: can be
-configured as well via the Nuxt runtime configuration through single environment variables or `.env` files
-
-```yaml title=".env"
-NUXT_PUBLIC_TITLE="My overriden title"
-NUXT_PUBLIC_LOGO="/app/.output/public/my_logo.png"
-...
-```
-
-To work, you need to mount the `my_logo.png` file into the `dbrepo-ui` container via the `docker-compose.yml` file (or
-if you use a Kubernetes deployment via ConfigMap and Volumes).
-
-```yaml title="docker-compose.yml"
-services:
-  dbrepo-ui:
-    image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.5
-    volumes:
-      - ./my_logo.png:/app/.output/public/my_logo.png
-  ...
-```
+=== "Docker Compose"
+
+    Text values like the version :material-numeric-2-circle-outline: and title :material-numeric-3-circle-outline: can be
+    configured as well via the Nuxt runtime configuration through single environment variables or `.env` files.
+    
+    ```yaml title=".env"
+    NUXT_PUBLIC_TITLE="My overriden title"
+    NUXT_PUBLIC_LOGO="/my_logo.png"
+    NUXT_PUBLIC_ICON="/favicon.ico"
+    ...
+    ```
+
+    To work, you need to mount the `my_logo.png` file into the `dbrepo-ui` container via the `docker-compose.yml` file.
+
+    ```yaml title="docker-compose.yml"
+    services:
+      dbrepo-ui:
+        image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.5
+        volumes:
+          - ./my_logo.png:/app/.output/public/my_logo.png
+          - ./favicon.ico:/app/.output/public/favicon.ico
+        environment:
+          ...
+      ...
+    ```
+
+    If you want to override more environment variables, extend the dictionary in `environment:`
+
+=== "Kubernetes"
+
+    Text values like the version :material-numeric-2-circle-outline: and title :material-numeric-3-circle-outline: can be
+    configured as well via the Nuxt runtime configuration through setting the variables in the `values.yaml` file.
+
+    ```yaml title="values.yaml"
+    ui:
+      public:
+        logo: "/my_logo.png"
+        icon: "/favicon.ico"
+      extraVolumes:
+        - name: images-map
+          configMap:
+            name: ui-config
+      extraVolumeMounts:
+        - name: images-map
+          mountPath: /static/
+    ```
+
+    To work, you need to mount the `my_logo.png` file into the dbrepo-ui deployment via a ConfigMap and Volumes. For this,
+    encode the files in base64 with `cat my_logo.png | base64`.
+
+    ```yaml title="dbrepo-ui-custom.yaml"
+    apiVersion: v1
+    kind: ConfigMap
+    metadata:
+      name: ui-config
+    binaryData:
+      my_logo.png: |
+        <base64>
+      favicon.ico: |
+        <base64>
+    ```
 
 ### Architecture
 
diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json
index a39f7de1b0ab0611057af4890ee281bb202609ca..2c6effa792933ab8d68cf8286a6d5417e5119bfe 100644
--- a/dbrepo-auth-service/dbrepo-realm.json
+++ b/dbrepo-auth-service/dbrepo-realm.json
@@ -2143,7 +2143,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2169,7 +2169,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper" ]
       }
     } ],
     "org.keycloak.storage.UserStorageProvider" : [ {
@@ -2209,8 +2209,8 @@
           "config" : {
             "ldap.attribute" : [ "cn" ],
             "is.mandatory.in.ldap" : [ "true" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "true" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "firstName" ]
           }
         }, {
@@ -2233,17 +2233,17 @@
           "config" : {
             "membership.attribute.type" : [ "DN" ],
             "group.name.ldap.attribute" : [ "cn" ],
-            "preserve.group.inheritance" : [ "false" ],
             "membership.user.ldap.attribute" : [ "uid" ],
+            "preserve.group.inheritance" : [ "false" ],
             "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
             "mode" : [ "LDAP_ONLY" ],
             "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
-            "membership.ldap.attribute" : [ "member" ],
             "ignore.missing.groups" : [ "false" ],
+            "membership.ldap.attribute" : [ "member" ],
             "group.object.classes" : [ "groupOfNames" ],
             "memberof.ldap.attribute" : [ "memberOf" ],
-            "groups.path" : [ "/" ],
-            "drop.non.existing.groups.during.sync" : [ "false" ]
+            "drop.non.existing.groups.during.sync" : [ "false" ],
+            "groups.path" : [ "/" ]
           }
         }, {
           "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb",
@@ -2267,31 +2267,31 @@
             "is.mandatory.in.ldap" : [ "true" ],
             "attribute.force.default" : [ "false" ],
             "is.binary.attribute" : [ "false" ],
-            "always.read.value.from.ldap" : [ "false" ],
             "read.only" : [ "false" ],
+            "always.read.value.from.ldap" : [ "false" ],
             "user.model.attribute" : [ "username" ]
           }
         } ]
       },
       "config" : {
-        "pagination" : [ "false" ],
         "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" ],
+        "changedSyncPeriod" : [ "-1" ],
         "usernameLDAPAttribute" : [ "uid" ],
-        "bindCredential" : [ "admin" ],
         "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
-        "changedSyncPeriod" : [ "-1" ],
+        "bindCredential" : [ "admin" ],
         "lastSync" : [ "1719252666" ],
         "vendor" : [ "other" ],
         "uuidLDAPAttribute" : [ "entryUUID" ],
-        "connectionUrl" : [ "ldap://identity-service:1389" ],
         "allowKerberosAuthentication" : [ "false" ],
+        "connectionUrl" : [ "ldap://identity-service:1389" ],
         "syncRegistrations" : [ "true" ],
         "authType" : [ "simple" ],
         "useTruststoreSpi" : [ "always" ],
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 60ebbf5de68ec59c4c66190d15ef60e1b11d8e96..507d9f33bd4ad66dba9094b2f6bf4311a761f0b0 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
@@ -38,6 +38,7 @@ import java.security.Principal;
 import java.sql.SQLException;
 import java.time.Instant;
 import java.util.List;
+import java.util.UUID;
 
 @Log4j2
 @RestController
@@ -193,9 +194,8 @@ public class SubsetEndpoint {
 
     @PostMapping
     @Observed(name = "dbrepo_subset_create")
-    @PreAuthorize("hasAuthority('execute-query')")
     @Operation(summary = "Create subset",
-            description = "Creates a subset in the query store of the data database. Requires role `execute-query`",
+            description = "Creates a subset in the query store of the data database. Requires role `execute-query` for private databases.",
             security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "201",
@@ -236,7 +236,7 @@ public class SubsetEndpoint {
     })
     public ResponseEntity<QueryResultDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                                  @Valid @RequestBody ExecuteStatementDto data,
-                                                 @NotNull Principal principal,
+                                                 Principal principal,
                                                  @RequestParam(required = false) Long page,
                                                  @RequestParam(required = false) Long size,
                                                  @RequestParam(required = false) Instant timestamp)
@@ -244,13 +244,19 @@ public class SubsetEndpoint {
             QueryNotFoundException, StorageUnavailableException, QueryMalformedException, SidecarExportException,
             StorageNotFoundException, QueryStoreInsertException, TableMalformedException, PaginationException,
             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,
+        log.debug("endpoint create subset in database, databaseId={}, data.statement={}, page={}, size={}, " +
+                        "timestamp={}", databaseId, data.getStatement(), page, size,
                 timestamp);
         /* check */
         endpointValidator.validateDataParams(page, size);
         endpointValidator.validateForbiddenStatements(data.getStatement());
         /* parameters */
+        final UUID userId;
+        if (principal == null) {
+            userId = metadataServiceGateway.getSystemUserId();
+        } else {
+            userId = UserUtil.getId(principal);
+        }
         if (page == null) {
             page = 0L;
             log.debug("page not set: default to {}", page);
@@ -267,8 +273,8 @@ public class SubsetEndpoint {
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         final QueryResultDto queryResult;
         try {
-            queryResult = subsetService.execute(database, data.getStatement(), timestamp, UserUtil.getId(principal),
-                    page, size, null, null);
+            queryResult = subsetService.execute(database, data.getStatement(), timestamp, userId, page, size, null,
+                    null);
         } catch (SQLException e) {
             log.error("Failed to establish connection to database: {}", e.getMessage());
             throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e);
@@ -343,9 +349,9 @@ public class SubsetEndpoint {
         }
         try {
             final QueryDto query = subsetService.findById(database, subsetId);
-            final HttpHeaders headers = new HttpHeaders();
-            headers.set("Access-Control-Expose-Headers", "X-Count");
             if (request.getMethod().equals("HEAD")) {
+                final HttpHeaders headers = new HttpHeaders();
+                headers.set("Access-Control-Expose-Headers", "X-Count");
                 final Long count = subsetService.reExecuteCount(database, query);
                 headers.set("X-Count", "" + count);
                 return ResponseEntity.ok()
@@ -356,7 +362,6 @@ public class SubsetEndpoint {
             result.setId(subsetId);
             log.trace("re-execute query resulted in result {}", result);
             return ResponseEntity.ok()
-                    .headers(headers)
                     .body(result);
         } catch (SQLException e) {
             log.error("Failed to establish connection to database: {}", e.getMessage());
@@ -410,8 +415,8 @@ public class SubsetEndpoint {
             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));
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
+        metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
         try {
             subsetService.persist(database, queryId, data.getPersist());
             final QueryDto dto = subsetService.findById(database, queryId);
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 e26a37b43aaa1b5307cf87d294e1dedc5cef87c4..4af577bed5771e66502ab48e78509c096666d151 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
@@ -99,6 +99,12 @@ public class TableEndpoint {
             RemoteUnavailableException, TableMalformedException, DatabaseUnavailableException, TableExistsException,
             TableNotFoundException, QueryMalformedException, MetadataServiceException {
         log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName());
+        /* check */
+        if (data.getConstraints().getPrimaryKey().isEmpty()) {
+            log.error("Table must have a primary key");
+            throw new TableMalformedException("Table must have a primary key");
+        }
+        /* create */
         final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId);
         try {
             return ResponseEntity.status(HttpStatus.CREATED)
@@ -218,13 +224,12 @@ public class TableEndpoint {
                 log.error("Failed find table data: authentication required");
                 throw new NotAllowedException("Failed to find table data: authentication required");
             }
-            final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
-            endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal));
+            metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
         }
-        final HttpHeaders headers = new HttpHeaders();
-        headers.set("Access-Control-Expose-Headers", "X-Count");
         try {
             if (request.getMethod().equals("HEAD")) {
+                final HttpHeaders headers = new HttpHeaders();
+                headers.set("Access-Control-Expose-Headers", "X-Count");
                 headers.set("X-Count", "" + tableService.getCount(table, timestamp));
                 return ResponseEntity.ok()
                         .headers(headers)
@@ -232,7 +237,6 @@ public class TableEndpoint {
             }
             final QueryResultDto dto = tableService.getData(table, timestamp, page, size);
             return ResponseEntity.ok()
-                    .headers(headers)
                     .body(dto);
         } catch (SQLException e) {
             log.error("Failed to establish connection to database: {}", e.getMessage());
@@ -542,10 +546,10 @@ public class TableEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<InputStreamResource> exportData(@NotBlank @PathVariable("databaseId") Long databaseId,
-                                                          @NotBlank @PathVariable("tableId") Long tableId,
-                                                          @RequestParam(required = false) Instant timestamp,
-                                                          Principal principal)
+    public ResponseEntity<InputStreamResource> exportDataset(@NotBlank @PathVariable("databaseId") Long databaseId,
+                                                             @NotBlank @PathVariable("tableId") Long tableId,
+                                                             @RequestParam(required = false) Instant timestamp,
+                                                             Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             NotAllowedException, StorageUnavailableException, QueryMalformedException, SidecarExportException,
             StorageNotFoundException, MetadataServiceException {
@@ -672,8 +676,7 @@ public class TableEndpoint {
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         table.setDatabase(metadataServiceGateway.getDatabaseById(databaseId));
         try {
-            final TableStatisticDto dto = tableService.getStatistics(table);
-            return ResponseEntity.ok(dto);
+            return ResponseEntity.ok(tableService.getStatistics(table));
         } catch (SQLException e) {
             log.error("Failed to establish connection to database: {}", e.getMessage());
             throw new DatabaseUnavailableException("Failed to establish connection to database", e);
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 e4ddab603685103027dcb6dfad936b882c987294..a4c07c3f55ff5ea2fab84b6293c7cc6a424c278c 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
@@ -264,9 +264,9 @@ public class ViewEndpoint {
             metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
         }
         try {
-            final HttpHeaders headers = new HttpHeaders();
-            headers.set("Access-Control-Expose-Headers", "X-Count");
             if (request.getMethod().equals("HEAD")) {
+                final HttpHeaders headers = new HttpHeaders();
+                headers.set("Access-Control-Expose-Headers", "X-Count");
                 headers.set("X-Count", "" + viewService.count(view, timestamp));
                 return ResponseEntity.ok()
                         .headers(headers)
@@ -275,7 +275,6 @@ public class ViewEndpoint {
             final QueryResultDto result = viewService.data(view, timestamp, page, size);
             log.trace("get view data resulted in result {}", result);
             return ResponseEntity.ok()
-                    .headers(headers)
                     .body(result);
         } catch (SQLException e) {
             log.error("Failed to establish connection to database: {}", e.getMessage());
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
index cbbb4c76b0c12e7846151746093728212a4d3b8d..b15254702a491908482663163defb530e5cbcf6a 100644
--- 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
@@ -21,7 +21,14 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
     @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
     @ExceptionHandler(AccessDeniedException.class)
     public ResponseEntity<ApiErrorDto> handle(AccessDeniedException e) {
-        return generic_handle(e.getClass(), e.getLocalizedMessage());
+        final HttpHeaders headers = new HttpHeaders();
+        headers.set("Content-Type", "application/problem+json");
+        final ApiErrorDto response = ApiErrorDto.builder()
+                .code("error.access.denied")
+                .message(e.getLocalizedMessage())
+                .status(HttpStatus.UNAUTHORIZED)
+                .build();
+        return new ResponseEntity<>(response, headers, HttpStatus.UNAUTHORIZED);
     }
 
     @Hidden
@@ -472,7 +479,7 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
         return generic_handle(e.getClass(), e.getLocalizedMessage());
     }
 
-    private ResponseEntity<ApiErrorDto> generic_handle(Class<?> exceptionClass, String message) {
+    public 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);
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
index cf868742400bc407c18d57c58984bcae7a7883ca..3cbb865293553e91a6730cfd731c62bbfc79c915 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
@@ -73,7 +73,7 @@ public class EndpointValidator {
             log.error("Failed to create table data: insufficient table write access");
             throw new NotAllowedException("Failed to create table data: insufficient table write access");
         }
-        log.trace("sufficient write access {}", access);
+        log.trace("sufficient write access {} for user {} and owner {}", access, user, owner);
     }
 
 
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 8f73fa1b53b41be7d8cbfbe71f25a27c94ccbb01..b0c332a63b5b87e786ca928daa7bc8bfa8a7ed3c 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
@@ -320,6 +320,27 @@ public class MariaDbConfig {
         return rows;
     }
 
+    public static List<Map<String, byte[]>> selectQueryByteArr(PrivilegedDatabaseDto database, String query, Set<String> columns)
+            throws SQLException {
+        final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
+        log.trace("connect to database {}", jdbc);
+        final List<Map<String, byte[]>> rows = new LinkedList<>();
+        try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
+            final Statement statement = connection.createStatement();
+            log.trace("execute query: {}", query);
+            final ResultSet result = statement.executeQuery(query);
+            log.trace("map result set to columns: {}", columns);
+            while (result.next()) {
+                final Map<String, byte[]> row = new HashMap<>();
+                for (String column : columns) {
+                    row.put(column, result.getBytes(column));
+                }
+                rows.add(row);
+            }
+        }
+        return rows;
+    }
+
     public static void execute(PrivilegedDatabaseDto database, String query)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java
index 62f095c82e79df65bd5a9407f735a432dedd502c..74da5a9eb13c6e541f67f660e09e98ea8986a2d0 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java
@@ -1,11 +1,15 @@
 package at.tuwien.config;
 
 import at.tuwien.test.BaseTest;
+import org.codehaus.plexus.util.FileUtils;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.testcontainers.containers.MariaDBContainer;
 import org.testcontainers.images.PullPolicy;
 
+import java.io.File;
+import java.io.IOException;
+
 /**
  * This class configures the MariaDB container for the integration tests.
  */
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 1dc008dbebffdd0a02ef0ffb12a12b9f6e8e6f08..3beb5626b3b8a2a001ac365a376cffea68b7b3ee 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
@@ -1,5 +1,6 @@
 package at.tuwien.endpoint;
 
+import at.tuwien.api.database.AccessTypeDto;
 import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.endpoints.AccessEndpoint;
@@ -73,6 +74,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_unavailable_fails() throws UserNotFoundException, DatabaseNotFoundException,
+            RemoteUnavailableException, MetadataServiceException, SQLException, DatabaseMalformedException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getPrivilegedUserById(USER_4_ID))
+                .thenReturn(USER_4_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(accessService)
+                .create(DATABASE_1_PRIVILEGED_DTO, USER_4_PRIVILEGED_DTO, AccessTypeDto.READ);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
@@ -125,13 +146,50 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getUserById(USER_1_ID))
+                .thenReturn(USER_1_DTO);
 
         /* test */
         accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO);
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void update_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException,
+            UserNotFoundException, DatabaseMalformedException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getUserById(USER_1_ID))
+                .thenReturn(USER_1_DTO);
+        doThrow(SQLException.class)
+                .when(accessService)
+                .update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void update_noAccess_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
+            UserNotFoundException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getUserById(USER_4_ID))
+                .thenReturn(USER_4_DTO);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            accessEndpoint.update(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void update_noRole_fails() {
@@ -195,6 +253,23 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID);
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void revoke_noAccess_fails() throws UserNotFoundException, DatabaseNotFoundException,
+            RemoteUnavailableException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getPrivilegedUserById(USER_4_ID))
+                .thenReturn(USER_4_PRIVILEGED_DTO);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            accessEndpoint.revoke(DATABASE_1_ID, USER_4_ID);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void revoke_noRole_fails() {
@@ -239,4 +314,24 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void revoke_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
+            UserNotFoundException, MetadataServiceException, SQLException, DatabaseMalformedException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getUserById(USER_1_ID))
+                .thenReturn(USER_1_DTO);
+        doThrow(SQLException.class)
+                .when(accessService)
+                .delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            accessEndpoint.revoke(DATABASE_1_ID, USER_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 c2b04d5aa914b86ef3edde0ebdf5d82f130c1e40..067687c2ed3762481d800c1d1126c074d99c2fe4 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
@@ -1,6 +1,7 @@
 package at.tuwien.endpoint;
 
 import at.tuwien.api.database.AccessTypeDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.user.PrivilegedUserDto;
 import at.tuwien.endpoints.DatabaseEndpoint;
 import at.tuwien.exception.*;
@@ -16,11 +17,14 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.sql.SQLException;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -54,10 +58,24 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException,
-            QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException, MetadataServiceException {
+            QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException,
+            MetadataServiceException, SQLException {
+
+        /* mock */
+        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
+                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
+        when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        doNothing()
+                .when(queryService)
+                .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+        doNothing()
+                .when(accessService)
+                .create(eq(DATABASE_1_PRIVILEGED_DTO), any(PrivilegedUserDto.class), any(AccessTypeDto.class));
 
         /* test */
-        databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL);
+        final ResponseEntity<DatabaseDto> response = databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL);
+        assertEquals(HttpStatus.CREATED, response.getStatusCode());
     }
 
     @Test
@@ -83,6 +101,24 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_unavailable_fails() throws RemoteUnavailableException, ContainerNotFoundException,
+            SQLException, DatabaseMalformedException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
+                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(databaseService)
+                .create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void create_containerNotFound_fails() throws RemoteUnavailableException, ContainerNotFoundException,
@@ -125,10 +161,32 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     public void update_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException,
             DatabaseMalformedException, DatabaseNotFoundException, MetadataServiceException {
 
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+
         /* test */
         databaseEndpoint.update(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void update_unavailable_fails() throws RemoteUnavailableException, DatabaseMalformedException,
+            DatabaseNotFoundException, MetadataServiceException, SQLException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(databaseService)
+                .update(DATABASE_1_PRIVILEGED_DTO, USER_1_UPDATE_PASSWORD_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            databaseEndpoint.update(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void update_noRole_fails() throws RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
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 6a0015b6f61e567fbf65f2e8f97f6c568fe142fa..1c54280a222f294be84bdf5c24b5b8ee4e0e6caf 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
@@ -46,7 +46,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     private SubsetEndpoint subsetEndpoint;
 
     @MockBean
-    private SubsetService queryService;
+    private SubsetService subsetService;
 
     @MockBean
     private HttpServletRequest httpServletRequest;
@@ -64,21 +64,43 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAllById_succeeds() throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException,
+    public void list_succeeds() throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException,
             DatabaseNotFoundException, RemoteUnavailableException, SQLException, MetadataServiceException {
 
+        /* mock */
+        when(subsetService.findAll(DATABASE_3_PRIVILEGED_DTO, null))
+                .thenReturn(List.of(QUERY_1_DTO, QUERY_2_DTO, QUERY_3_DTO, QUERY_4_DTO, QUERY_5_DTO, QUERY_6_DTO));
+
         /* test */
-        final List<QueryDto> response = generic_findAllById(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO);
+        final List<QueryDto> response = generic_list(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO);
         assertEquals(6, response.size());
     }
 
     @Test
     @WithAnonymousUser
-    public void findAllById_databaseNotFound_fails() {
+    public void list_databaseNotFound_fails() {
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
-            generic_findAllById(null, null);
+            generic_list(null, null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void list_unavailable_fails() throws NotAllowedException, SQLException, QueryNotFoundException,
+            DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(subsetService)
+                .findAll(DATABASE_3_PRIVILEGED_DTO, null);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            generic_list(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO);
         });
     }
 
@@ -92,9 +114,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+                .thenReturn(QUERY_5_DTO);
 
         /* test */
-        generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.APPLICATION_JSON, null);
+        generic_findById(QUERY_5_ID, MediaType.APPLICATION_JSON, null);
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void findById_format_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException,
+            UserNotFoundException, NotAllowedException, QueryNotFoundException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+                .thenReturn(QUERY_5_DTO);
+
+        /* test */
+        assertThrows(FormatNotAvailableException.class, () -> {
+            generic_findById(QUERY_5_ID, MediaType.APPLICATION_PDF, null);
+        });
     }
 
     @Test
@@ -111,11 +152,13 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(queryService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString()))
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+                .thenReturn(QUERY_5_DTO);
+        when(subsetService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString()))
                 .thenReturn(mock);
 
         /* test */
-        generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.parseMediaType("text/csv"), null);
+        generic_findById(QUERY_5_ID, MediaType.parseMediaType("text/csv"), null);
     }
 
     @Test
@@ -132,16 +175,18 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(queryService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString()))
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+                .thenReturn(QUERY_5_DTO);
+        when(subsetService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString()))
                 .thenReturn(mock);
 
         /* test */
-        generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.parseMediaType("text/csv"), Instant.now());
+        generic_findById(QUERY_5_ID, MediaType.parseMediaType("text/csv"), Instant.now());
     }
 
     @Test
     @WithAnonymousUser
-    public void findById_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException {
+    public void findById_notFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         doThrow(DatabaseNotFoundException.class)
@@ -150,7 +195,53 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
-            generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.APPLICATION_JSON, null);
+            generic_findById(QUERY_5_ID, MediaType.APPLICATION_JSON, null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void findById_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
+            MetadataServiceException, SQLException, UserNotFoundException, NotAllowedException, QueryNotFoundException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(subsetService)
+                .findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            generic_findById(QUERY_5_ID, MediaType.APPLICATION_JSON, null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void findById_unavailableExport_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
+            MetadataServiceException, SQLException, StorageUnavailableException, QueryMalformedException,
+            SidecarExportException, StorageNotFoundException, UserNotFoundException, NotAllowedException,
+            QueryNotFoundException {
+        final ExportResourceDto mock = ExportResourceDto.builder()
+                .filename("deadbeef")
+                .resource(new InputStreamResource(InputStream.nullInputStream()))
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+                .thenReturn(QUERY_5_DTO);
+        when(subsetService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString()))
+                .thenReturn(mock);
+        doThrow(SQLException.class)
+                .when(subsetService)
+                .export(eq(DATABASE_3_PRIVILEGED_DTO), eq(QUERY_5_DTO), any(Instant.class), anyString());
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            generic_findById(QUERY_5_ID, MediaType.parseMediaType("text/csv"), null);
         });
     }
 
@@ -168,7 +259,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(queryService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null)))
+        when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(QUERY_5_RESULT_DTO);
 
         /* test */
@@ -202,13 +293,35 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(queryService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null)))
+        when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(QUERY_5_RESULT_DTO);
 
         /* test */
         subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, null, null, null);
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
+    public void create_unavailable_succeeds() throws UserNotFoundException, QueryStoreInsertException,
+            TableMalformedException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException,
+            RemoteUnavailableException, SQLException, MetadataServiceException {
+        final ExecuteStatementDto request = ExecuteStatementDto.builder()
+                .statement(QUERY_5_STATEMENT)
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(subsetService)
+                .execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null));
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, null, null, null);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
     public void create_databaseNotFound_fails() throws RemoteUnavailableException,
@@ -230,15 +343,38 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_4_USERNAME)
-    public void create_noRole_fails() {
+    public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, SidecarExportException, QueryNotSupportedException, PaginationException, StorageNotFoundException {
         final ExecuteStatementDto request = ExecuteStatementDto.builder()
                 .statement(QUERY_5_STATEMENT)
                 .build();
 
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_4_ID), eq(0L), eq(10L), eq(null), eq(null)))
+                .thenReturn(QUERY_5_RESULT_DTO);
+
         /* test */
-        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            subsetEndpoint.create(DATABASE_3_ID, request, USER_4_PRINCIPAL, null, null, null);
-        });
+        subsetEndpoint.create(DATABASE_3_ID, request, USER_4_PRINCIPAL, null, null, null);
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void create_anonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, SidecarExportException, QueryNotSupportedException, PaginationException, StorageNotFoundException {
+        final ExecuteStatementDto request = ExecuteStatementDto.builder()
+                .statement(QUERY_5_STATEMENT)
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getSystemUserId())
+                .thenReturn(USER_LOCAL_ADMIN_ID);
+        when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_LOCAL_ADMIN_ID), eq(0L), eq(10L), eq(null), eq(null)))
+                .thenReturn(QUERY_5_RESULT_DTO);
+
+        /* test */
+        subsetEndpoint.create(DATABASE_3_ID, request, null, null, null, null);
     }
 
     @Test
@@ -249,11 +385,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
                 .thenReturn(QUERY_5_DTO);
-        when(queryService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO))
+        when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO))
                 .thenReturn(QUERY_5_RESULT_NUMBER);
-        when(queryService.reExecute(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO, 0L, 10L, null, null))
+        when(subsetService.reExecute(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO, 0L, 10L, null, null))
                 .thenReturn(QUERY_5_RESULT_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
@@ -261,23 +397,20 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* test */
         final ResponseEntity<QueryResultDto> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers"));
-        assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size());
-        assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0));
         assertNotNull(response.getBody());
     }
 
     @Test
-    public void getData_onlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
+    public void getData_head_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException,
             DatabaseUnavailableException, PaginationException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
                 .thenReturn(QUERY_5_DTO);
-        when(queryService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO))
+        when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO))
                 .thenReturn(QUERY_5_RESULT_NUMBER);
         when(httpServletRequest.getMethod())
                 .thenReturn("HEAD");
@@ -301,11 +434,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
-        when(queryService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
+        when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
                 .thenReturn(QUERY_1_DTO);
-        when(queryService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO))
+        when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO))
                 .thenReturn(QUERY_1_RESULT_NUMBER);
-        when(queryService.reExecute(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L, null, null))
+        when(subsetService.reExecute(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L, null, null))
                 .thenReturn(QUERY_1_RESULT_DTO);
 
         /* test */
@@ -349,16 +482,16 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void getData_privateOnlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
+    public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException,
             QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException {
 
         /* mock */
         when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(queryService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
+        when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
                 .thenReturn(QUERY_1_DTO);
-        when(queryService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO))
+        when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO))
                 .thenReturn(QUERY_1_RESULT_NUMBER);
         when(httpServletRequest.getMethod())
                 .thenReturn("HEAD");
@@ -371,6 +504,29 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         assertEquals(QUERY_1_RESULT_NUMBER, Long.parseLong(response.getHeaders().get("X-Count").get(0)));
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME)
+    public void getData_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException,
+            UserNotFoundException, NotAllowedException, TableMalformedException, QueryNotFoundException,
+            MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
+                .thenReturn(QUERY_1_DTO);
+        when(httpServletRequest.getMethod())
+                .thenReturn("GET");
+        doThrow(SQLException.class)
+                .when(subsetService)
+                .reExecute(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L, null, null);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"})
     public void persist_succeeds() throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException,
@@ -386,9 +542,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
         doNothing()
-                .when(queryService)
+                .when(subsetService)
                 .persist(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID, true);
-        when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
+        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
                 .thenReturn(QUERY_5_DTO);
 
         /* test */
@@ -447,16 +603,37 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
-    protected List<QueryDto> generic_findAllById(Long databaseId, PrivilegedDatabaseDto database)
-            throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException,
-            RemoteUnavailableException, SQLException, MetadataServiceException {
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"})
+    public void persist_unavailable_fails() throws NotAllowedException, RemoteUnavailableException,
+            MetadataServiceException, QueryStorePersistException, SQLException, DatabaseNotFoundException {
+        final QueryPersistDto request = QueryPersistDto.builder()
+                .persist(true)
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID))
+                .thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO);
+        doThrow(SQLException.class)
+                .when(subsetService)
+                .persist(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID, true);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            subsetEndpoint.persist(DATABASE_3_ID, QUERY_5_ID, request, USER_3_PRINCIPAL);
+        });
+    }
+
+    protected List<QueryDto> generic_list(Long databaseId, PrivilegedDatabaseDto database) throws NotAllowedException,
+            DatabaseUnavailableException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException,
+            MetadataServiceException {
 
         /* mock */
         if (database != null) {
             when(metadataServiceGateway.getDatabaseById(databaseId))
                     .thenReturn(database);
-            when(queryService.findAll(database, null))
-                    .thenReturn(List.of(QUERY_1_DTO, QUERY_2_DTO, QUERY_3_DTO, QUERY_4_DTO, QUERY_5_DTO, QUERY_6_DTO));
         } else {
             doThrow(DatabaseNotFoundException.class)
                     .when(metadataServiceGateway)
@@ -469,15 +646,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         return response.getBody();
     }
 
-    protected void generic_findById(Long subsetId, QueryDto subset, MediaType accept, Instant timestamp)
-            throws UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException,
-            NotAllowedException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException,
-            SidecarExportException, RemoteUnavailableException, FormatNotAvailableException, StorageNotFoundException,
-            SQLException, MetadataServiceException {
+    protected void generic_findById(Long subsetId, MediaType accept, Instant timestamp) throws UserNotFoundException,
+            DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException,
+            QueryNotFoundException, DatabaseNotFoundException, SidecarExportException, RemoteUnavailableException,
+            FormatNotAvailableException, StorageNotFoundException, MetadataServiceException {
 
         /* mock */
-        when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, subsetId))
-                .thenReturn(subset);
         when(mockHttpServletRequest.getHeader("Accept"))
                 .thenReturn(accept.toString());
 
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 76c34ef47cd2d13f698f3d552b9aebbbb4175492..f03f4c3f189c98013e6fa5d4bb01a5cfd4fe211f 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
@@ -1,9 +1,11 @@
 package at.tuwien.endpoint;
 
 import at.tuwien.ExportResourceDto;
+import at.tuwien.api.database.DatabaseAccessDto;
 import at.tuwien.api.database.query.ImportCsvDto;
 import at.tuwien.api.database.query.QueryResultDto;
 import at.tuwien.api.database.table.*;
+import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.endpoints.TableEndpoint;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
@@ -14,12 +16,16 @@ 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.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.core.io.InputStreamResource;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.test.context.support.WithAnonymousUser;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -29,6 +35,7 @@ import java.sql.SQLException;
 import java.time.Instant;
 import java.util.HashMap;
 import java.util.List;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -50,6 +57,22 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @MockBean
     private MetadataServiceGateway metadataServiceGateway;
 
+    public static Stream<Arguments> size_arguments() {
+        return Stream.of(
+                Arguments.arguments("zero", 0L),
+                Arguments.arguments("neg zero", -0L),
+                Arguments.arguments("negative", -1L)
+        );
+    }
+
+    public static Stream<Arguments> anyAccess_parameters() {
+        return Stream.of(
+                Arguments.arguments("read", DATABASE_1_USER_2_READ_ACCESS_DTO),
+                Arguments.arguments("write_own", DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO),
+                Arguments.arguments("write_all", DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO)
+        );
+    }
+
     @BeforeEach
     public void beforeEach() {
         genesis();
@@ -98,6 +121,85 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_unavailable_fails() throws TableMalformedException, DatabaseNotFoundException, SQLException,
+            TableExistsException, RemoteUnavailableException, TableNotFoundException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_missingPrimaryKey_fails() {
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            tableEndpoint.create(DATABASE_1_ID, TABLE_1_CREATE_INTERNAL_INVALID_DTO);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void statistic_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
+            TableMalformedException, DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException,
+            SQLException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(tableService.getStatistics(any(PrivilegedTableDto.class)))
+                .thenReturn(TABLE_8_STATISTIC_DTO);
+
+        /* test */
+        final ResponseEntity<TableStatisticDto> response = tableEndpoint.statistic(DATABASE_3_ID, TABLE_8_ID);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void statistic_unavailable_fails() throws TableNotFoundException, TableMalformedException,
+            RemoteUnavailableException, MetadataServiceException, SQLException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .getStatistics(any(PrivilegedTableDto.class));
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.statistic(DATABASE_3_ID, TABLE_8_ID);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void statistic_notFound_fails() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException {
+
+        /* mock */
+        doThrow(TableNotFoundException.class)
+                .when(metadataServiceGateway)
+                .getTableById(DATABASE_1_ID, TABLE_1_ID);
+
+        /* test */
+        assertThrows(TableNotFoundException.class, () -> {
+            tableEndpoint.statistic(DATABASE_1_ID, TABLE_1_ID);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void delete_succeeds() throws RemoteUnavailableException, DatabaseUnavailableException,
@@ -141,6 +243,24 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void delete_unavailable_fails() throws RemoteUnavailableException, TableNotFoundException, SQLException,
+            MetadataServiceException, QueryMalformedException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .delete(TABLE_1_PRIVILEGED_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.delete(DATABASE_1_ID, TABLE_1_ID);
+        });
+    }
+
     @Test
     @WithAnonymousUser
     public void getData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException,
@@ -150,18 +270,129 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
-        when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class)))
-                .thenReturn(TABLE_8_DATA_COUNT);
         when(tableService.getData(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L)))
                 .thenReturn(TABLE_8_DATA_DTO);
 
         /* test */
         final ResponseEntity<QueryResultDto> response = tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
+
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void getData_head_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException,
+            SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, MetadataServiceException,
+            NotAllowedException {
+        final HttpServletRequest mock = mock(HttpServletRequest.class);
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(mock.getMethod())
+                .thenReturn("HEAD");
+        when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class)))
+                .thenReturn(3L);
+        when(tableService.getData(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L)))
+                .thenReturn(TABLE_8_DATA_DTO);
+
+        /* test */
+        final ResponseEntity<QueryResultDto> response = tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, mock, null);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers"));
-        assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size());
         assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0));
+        assertNotNull(response.getHeaders().get("X-Count"));
+        assertEquals("3", response.getHeaders().get("X-Count").get(0));
+
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void getData_privateAnonymous_fails() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
 
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void getData_privateNoAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException, NotAllowedException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        doThrow(NotAllowedException.class)
+                .when(metadataServiceGateway)
+                .getAccess(DATABASE_1_ID, USER_2_ID);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void getData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException, TableMalformedException, SQLException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .getData(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L));
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void getData_privateAccessUnavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException, NotAllowedException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        doThrow(RemoteUnavailableException.class)
+                .when(metadataServiceGateway)
+                .getAccess(DATABASE_1_ID, USER_2_ID);
+
+        /* test */
+        assertThrows(RemoteUnavailableException.class, () -> {
+            tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL);
+        });
+    }
+
+    @ParameterizedTest
+    @WithMockUser(username = USER_2_USERNAME)
+    @MethodSource("anyAccess_parameters")
+    public void getData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException,
+            TableNotFoundException, TableMalformedException, SQLException, QueryMalformedException,
+            RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(access);
+        when(tableService.getData(eq(TABLE_1_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L)))
+                .thenReturn(TABLE_1_DATA_DTO);
+
+        /* test */
+        final ResponseEntity<QueryResultDto> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
     }
 
     @Test
@@ -182,7 +413,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
-    public void createTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
+    public void insertRawTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
             SQLException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
@@ -211,7 +442,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME)
-    public void createTuple_noRole_fails() {
+    public void insertRawTuple_noRole_fails() {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
                     put(COLUMN_8_1_INTERNAL_NAME, 7L);
@@ -227,7 +458,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void createTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
+    public void insertRawTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
             MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -249,7 +480,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void createTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
+    public void insertRawTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -270,9 +501,36 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
+    public void insertRawTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
+            NotAllowedException, MetadataServiceException, TableMalformedException, StorageUnavailableException,
+            SQLException, QueryMalformedException, StorageNotFoundException {
+        final TupleDto request = TupleDto.builder()
+                .data(new HashMap<>() {{
+                    put(COLUMN_8_1_INTERNAL_NAME, 7L);
+                    put(COLUMN_8_2_INTERNAL_NAME, 23.0);
+                }})
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_1_ID))
+                .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .createTuple(TABLE_8_PRIVILEGED_DTO, request);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
-    public void createTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+    public void insertRawTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
             StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
@@ -294,7 +552,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void createTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
+    public void insertRawTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -317,7 +575,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void createTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+    public void insertRawTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
             StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
         final TupleDto request = TupleDto.builder()
@@ -439,6 +697,35 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
+    public void updateTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException,
+            NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException {
+        final TupleUpdateDto request = TupleUpdateDto.builder()
+                .keys(new HashMap<>() {{
+                    put(COLUMN_8_1_INTERNAL_NAME, 6L);
+                }})
+                .data(new HashMap<>() {{
+                    put(COLUMN_8_1_INTERNAL_NAME, 6L);
+                    put(COLUMN_8_2_INTERNAL_NAME, 23.0);
+                }})
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID))
+                .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .updateTuple(TABLE_8_PRIVILEGED_DTO, request);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
     public void updateTuple_writeOwnAccess_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
@@ -615,6 +902,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
+    public void deleteTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException,
+            NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException {
+        final TupleDeleteDto request = TupleDeleteDto.builder()
+                .keys(new HashMap<>() {{
+                    put(COLUMN_8_1_INTERNAL_NAME, 6L);
+                }})
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_1_ID))
+                .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .deleteTuple(TABLE_8_PRIVILEGED_DTO, request);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
     public void deleteTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
@@ -724,6 +1036,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @ParameterizedTest
+    @MethodSource("size_arguments")
+    @WithAnonymousUser
+    public void getHistory_invalidSize_fails(String name, Long size) {
+
+        /* test */
+        assertThrows(PaginationException.class, () -> {
+            tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, size, null);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_4_USERNAME)
     public void getHistory_privateNoAccess_fails() throws NotAllowedException, RemoteUnavailableException,
@@ -742,6 +1065,42 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void getHistory_private_succeeds() throws NotAllowedException, RemoteUnavailableException, SQLException,
+            TableNotFoundException, MetadataServiceException, DatabaseUnavailableException, PaginationException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO);
+        when(tableService.history(TABLE_1_PRIVILEGED_DTO, 10L))
+                .thenReturn(List.of());
+
+        /* test */
+        final ResponseEntity<List<TableHistoryDto>> response = tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, null, USER_2_PRINCIPAL);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void getHistory_unavailable_succeeds() throws RemoteUnavailableException, SQLException,
+            TableNotFoundException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .history(TABLE_8_PRIVILEGED_DTO, 100L);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null, null);
+        });
+    }
+
     @Test
     @WithAnonymousUser
     public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
@@ -775,7 +1134,32 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(mock);
 
         /* test */
-        final ResponseEntity<InputStreamResource> response = tableEndpoint.exportData(DATABASE_3_ID, TABLE_8_ID, null, null);
+        final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_3_ID, TABLE_8_ID, null, null);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+
+    }
+
+    @ParameterizedTest
+    @WithMockUser(username = USER_2_USERNAME)
+    @MethodSource("anyAccess_parameters")
+    public void exportData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException, TableNotFoundException, NotAllowedException,
+            StorageUnavailableException, QueryMalformedException, SidecarExportException, RemoteUnavailableException,
+            StorageNotFoundException, SQLException, MetadataServiceException {
+        final ExportResourceDto mock = ExportResourceDto.builder()
+                .filename("deadbeef")
+                .resource(new InputStreamResource(InputStream.nullInputStream()))
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(access);
+        when(tableService.exportDataset(eq(TABLE_1_PRIVILEGED_DTO), any(Instant.class)))
+                .thenReturn(mock);
+
+        /* test */
+        final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
 
     }
@@ -794,19 +1178,92 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.exportData(DATABASE_1_ID, TABLE_1_ID, null, null);
+            tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME)
+    public void exportData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
+            MetadataServiceException, StorageUnavailableException, SQLException, QueryMalformedException,
+            SidecarExportException, StorageNotFoundException {
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .exportDataset(eq(TABLE_1_PRIVILEGED_DTO), any(Instant.class));
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL);
         });
+    }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"system"})
+    public void getSchema_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
+            RemoteUnavailableException, SQLException, MetadataServiceException, DatabaseNotFoundException,
+            DatabaseMalformedException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(tableService.getSchemas(DATABASE_3_PRIVILEGED_DTO))
+                .thenReturn(List.of(TABLE_8_DTO));
+
+        /* test */
+        final ResponseEntity<List<TableDto>> response = tableEndpoint.getSchema(DATABASE_3_ID);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void getSchema_anonymous_succeeds() {
+
+        /* test */
+        assertThrows(AccessDeniedException.class, () -> {
+            tableEndpoint.getSchema(DATABASE_3_ID);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_4_USERNAME)
+    public void getSchema_noRole_succeeds() {
+
+        /* test */
+        assertThrows(AccessDeniedException.class, () -> {
+            tableEndpoint.getSchema(DATABASE_3_ID);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"system"})
+    public void getSchema_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException,
+            MetadataServiceException, DatabaseNotFoundException, DatabaseMalformedException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .getSchemas(DATABASE_3_PRIVILEGED_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.getSchema(DATABASE_3_ID);
+        });
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
-    public void importData_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
+    public void importDataset_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             SidecarImportException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
             StorageNotFoundException, SQLException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
-                .lineTermination("\\n")
+                .lineTermination(null)
                 .location("deadbeef")
                 .build();
 
@@ -829,7 +1286,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_4_USERNAME)
-    public void importData_noRole_fails() {
+    public void importDataset_noRole_fails() {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
                 .lineTermination("\\n")
@@ -844,7 +1301,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void importData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
+    public void importDataset_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
             MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
@@ -865,7 +1322,59 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void importData_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
+    public void importDataset_unavailable_fails() throws RemoteUnavailableException, SidecarImportException,
+            SQLException, QueryMalformedException, StorageNotFoundException, TableNotFoundException,
+            MetadataServiceException, NotAllowedException {
+        final ImportCsvDto request = ImportCsvDto.builder()
+                .skipLines(1L)
+                .lineTermination("\\n")
+                .location("deadbeef")
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID))
+                .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .importDataset(any(PrivilegedTableDto.class), eq(request));
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
+    public void importDataset_writeOwnAccess_fails() throws RemoteUnavailableException, SidecarImportException,
+            SQLException, QueryMalformedException, StorageNotFoundException, TableNotFoundException,
+            MetadataServiceException, NotAllowedException {
+        final ImportCsvDto request = ImportCsvDto.builder()
+                .skipLines(1L)
+                .lineTermination("\\n")
+                .location("deadbeef")
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID))
+                .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
+        doThrow(SQLException.class)
+                .when(tableService)
+                .importDataset(any(PrivilegedTableDto.class), eq(request));
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
+    public void importDataset_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
@@ -887,7 +1396,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
-    public void importData_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+    public void importDataset_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException,
             StorageNotFoundException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
@@ -908,7 +1417,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void importData_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
+    public void importDataset_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
                 .skipLines(1L)
@@ -930,7 +1439,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
-    public void importData_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+    public void importDataset_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException,
             StorageNotFoundException, MetadataServiceException {
         final ImportCsvDto request = ImportCsvDto.builder()
@@ -949,4 +1458,90 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
     }
 
+    @Test
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
+    public void importDataset_privateForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+            NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException,
+            StorageNotFoundException, MetadataServiceException {
+        final ImportCsvDto request = ImportCsvDto.builder()
+                .skipLines(1L)
+                .lineTermination("\\n")
+                .location("deadbeef")
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO);
+
+        /* test */
+        tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, request, USER_2_PRINCIPAL);
+    }
+
+    @Test
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
+    public void importDataset_private_succeeds() throws TableNotFoundException, RemoteUnavailableException,
+            NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException,
+            StorageNotFoundException, MetadataServiceException {
+        final ImportCsvDto request = ImportCsvDto.builder()
+                .skipLines(1L)
+                .lineTermination("\\n")
+                .location("deadbeef")
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_2_ID))
+                .thenReturn(TABLE_2_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO);
+
+        /* test */
+        tableEndpoint.importDataset(DATABASE_1_ID, TABLE_2_ID, request, USER_2_PRINCIPAL);
+    }
+
+    @Test
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
+    public void importDataset_privateForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
+            NotAllowedException, MetadataServiceException {
+        final ImportCsvDto request = ImportCsvDto.builder()
+                .skipLines(1L)
+                .lineTermination("\\n")
+                .location("deadbeef")
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+                .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, request, USER_2_PRINCIPAL);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
+    public void importDataset_privateReadAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
+            NotAllowedException, MetadataServiceException {
+        final ImportCsvDto request = ImportCsvDto.builder()
+                .skipLines(1L)
+                .lineTermination("\\n")
+                .location("deadbeef")
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_2_ID))
+                .thenReturn(TABLE_2_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID))
+                .thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            tableEndpoint.importDataset(DATABASE_1_ID, TABLE_2_ID, request, USER_2_PRINCIPAL);
+        });
+    }
+
 }
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 543b4a5cf299d48a8a4594f95e8586752d4278cc..fd1030c17bee1f169c01d33da8af86f339feecbe 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
@@ -17,11 +17,14 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.test.context.support.WithAnonymousUser;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.sql.SQLException;
 import java.time.Instant;
+import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -64,6 +67,24 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         assertEquals(HttpStatus.CREATED, response.getStatusCode());
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException,
+            ViewMalformedException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(viewService)
+                .create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            viewEndpoint.create(DATABASE_1_ID, VIEW_1_CREATE_DTO);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
@@ -97,6 +118,76 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void getSchema_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException,
+            DatabaseMalformedException, DatabaseUnavailableException, ViewNotFoundException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(viewService.getSchemas(DATABASE_1_PRIVILEGED_DTO))
+                .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO));
+
+        /* test */
+        final ResponseEntity<List<ViewDto>> response = viewEndpoint.getSchema(DATABASE_1_ID);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void getSchema_anonymous_fails() {
+
+        /* test */
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            viewEndpoint.getSchema(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void getSchema_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
+            MetadataServiceException {
+
+        /* mock */
+        doThrow(DatabaseNotFoundException.class)
+                .when(metadataServiceGateway)
+                .getDatabaseById(DATABASE_1_ID);
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            viewEndpoint.getSchema(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void getSchema_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
+            SQLException, DatabaseMalformedException, ViewNotFoundException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(viewService)
+                .getSchemas(DATABASE_1_PRIVILEGED_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            viewEndpoint.getSchema(DATABASE_1_ID);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void delete_anonymous_fails() {
+
+        /* test */
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
     public void delete_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
@@ -114,6 +205,24 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
+    @Test
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void delete_unavailable_fails() throws RemoteUnavailableException, ViewMalformedException, SQLException,
+            MetadataServiceException, ViewNotFoundException {
+
+        /* mock */
+        when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
+        doThrow(SQLException.class)
+                .when(viewService)
+                .delete(VIEW_1_PRIVILEGED_DTO);
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
     public void delete_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
@@ -150,7 +259,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
-    public void getData_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException,
+    public void getData_private_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException,
             SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException,
             NotAllowedException, MetadataServiceException {
 
@@ -167,40 +276,79 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         /* test */
         final ResponseEntity<QueryResultDto> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers"));
-        assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size());
-        assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0));
         assertNotNull(response.getBody());
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
-    public void getData_onlyHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
+    public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
             ViewMalformedException, SQLException, DatabaseUnavailableException, QueryMalformedException,
             PaginationException, NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID))
-                .thenReturn(VIEW_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_3_ID))
+                .thenReturn(VIEW_3_PRIVILEGED_DTO);
         when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID))
                 .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("HEAD");
-        when(viewService.count(eq(VIEW_1_PRIVILEGED_DTO), any(Instant.class)))
-                .thenReturn(VIEW_1_DATA_COUNT);
+        when(viewService.count(eq(VIEW_3_PRIVILEGED_DTO), any(Instant.class)))
+                .thenReturn(VIEW_3_DATA_COUNT);
 
         /* test */
-        final ResponseEntity<QueryResultDto> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
+        final ResponseEntity<QueryResultDto> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getHeaders().get("X-Count"));
         assertEquals(1, response.getHeaders().get("X-Count").size());
-        assertEquals(VIEW_1_DATA_COUNT, Long.parseLong(response.getHeaders().get("X-Count").get(0)));
+        assertEquals(VIEW_3_DATA_COUNT, Long.parseLong(response.getHeaders().get("X-Count").get(0)));
         assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers"));
         assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size());
         assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0));
         assertNull(response.getBody());
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
+    public void getData_unavailable_fails() throws RemoteUnavailableException, ViewNotFoundException, SQLException,
+            ViewMalformedException, NotAllowedException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID))
+                .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO);
+        when(httpServletRequest.getMethod())
+                .thenReturn("GET");
+        doThrow(SQLException.class)
+                .when(viewService)
+                .data(eq(VIEW_1_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L));
+
+        /* test */
+        assertThrows(DatabaseUnavailableException.class, () -> {
+            viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
+    public void getData_privateNoAccess_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
+            NotAllowedException, MetadataServiceException {
+
+        /* mock */
+        when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_3_ID))
+                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(httpServletRequest.getMethod())
+                .thenReturn("GET");
+        doThrow(NotAllowedException.class)
+                .when(metadataServiceGateway)
+                .getAccess(DATABASE_1_ID, USER_1_ID);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
     public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException,
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
new file mode 100644
index 0000000000000000000000000000000000000000..ce56ce82da975f8f41d7233b0a017143044457ed
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java
@@ -0,0 +1,1232 @@
+package at.tuwien.handlers;
+
+import at.tuwien.api.error.ApiErrorDto;
+import at.tuwien.exception.*;
+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.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.AccessDeniedException;
+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;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class ApiExceptionHandlerTest extends AbstractUnitTest {
+
+    @Autowired
+    private ApiExceptionHandler apiExceptionHandler;
+
+    @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 */
+            assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).code());
+            Assertions.assertNotEquals(exception.getDeclaredAnnotation(ResponseStatus.class).code(), HttpStatus.INTERNAL_SERVER_ERROR);
+            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());
+        }
+    }
+
+    @Test
+    public void generic_handle_succeeds() {
+
+        /* test */
+        apiExceptionHandler.generic_handle(DatabaseNotFoundException.class, "msg");
+    }
+
+    @Test
+    public void handle_AccessDeniedException_succeeds() {
+        final AccessDeniedException request = new AccessDeniedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        Assertions.assertNotEquals(response.getStatusCode(), HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertEquals("error.access.denied", response.getBody().getCode());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_AccessNotFoundException_succeeds() {
+        final AccessNotFoundException request = new AccessNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_AccountNotSetupException_succeeds() {
+        final AccountNotSetupException request = new AccountNotSetupException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_AuthServiceConnectionException_succeeds() {
+        final AuthServiceConnectionException request = new AuthServiceConnectionException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_AuthServiceException_succeeds() {
+        final AuthServiceException request = new AuthServiceException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_BrokerServiceConnectionException_succeeds() {
+        final BrokerServiceConnectionException request = new BrokerServiceConnectionException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_BrokerServiceException_succeeds() {
+        final BrokerServiceException request = new BrokerServiceException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ConceptNotFoundException_succeeds() {
+        final ConceptNotFoundException request = new ConceptNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ContainerAlreadyExistsException_succeeds() {
+        final ContainerAlreadyExistsException request = new ContainerAlreadyExistsException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ContainerNotFoundException_succeeds() {
+        final ContainerNotFoundException request = new ContainerNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_CredentialsInvalidException_succeeds() {
+        final CredentialsInvalidException request = new CredentialsInvalidException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_DatabaseMalformedException_succeeds() {
+        final DatabaseMalformedException request = new DatabaseMalformedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_DatabaseNotFoundException_succeeds() {
+        final DatabaseNotFoundException request = new DatabaseNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_DatabaseUnavailableException_succeeds() {
+        final DatabaseUnavailableException request = new DatabaseUnavailableException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_DoiNotFoundException_succeeds() {
+        final DoiNotFoundException request = new DoiNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_EmailExistsException_succeeds() {
+        final EmailExistsException request = new EmailExistsException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ExchangeNotFoundException_succeeds() {
+        final ExchangeNotFoundException request = new ExchangeNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ExternalServiceException_succeeds() {
+        final ExternalServiceException request = new ExternalServiceException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_FilterBadRequestException_succeeds() {
+        final FilterBadRequestException request = new FilterBadRequestException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_FormatNotAvailableException_succeeds() {
+        final FormatNotAvailableException request = new FormatNotAvailableException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_IdentifierNotFoundException_succeeds() {
+        final IdentifierNotFoundException request = new IdentifierNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_IdentifierNotSupportedException_succeeds() {
+        final IdentifierNotSupportedException request = new IdentifierNotSupportedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ImageAlreadyExistsException_succeeds() {
+        final ImageAlreadyExistsException request = new ImageAlreadyExistsException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ImageInvalidException_succeeds() {
+        final ImageInvalidException request = new ImageInvalidException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ImageNotFoundException_succeeds() {
+        final ImageNotFoundException request = new ImageNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_LicenseNotFoundException_succeeds() {
+        final LicenseNotFoundException request = new LicenseNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_MalformedException_succeeds() {
+        final MalformedException request = new MalformedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_MessageNotFoundException_succeeds() {
+        final MessageNotFoundException request = new MessageNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_MetadataServiceConnectionException_succeeds() {
+        final MetadataServiceConnectionException request = new MetadataServiceConnectionException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_MetadataServiceException_succeeds() {
+        final MetadataServiceException request = new MetadataServiceException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_NotAllowedException_succeeds() {
+        final NotAllowedException request = new NotAllowedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_OntologyNotFoundException_succeeds() {
+        final OntologyNotFoundException request = new OntologyNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_OrcidNotFoundException_succeeds() {
+        final OrcidNotFoundException request = new OrcidNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_PaginationException_succeeds() {
+        final PaginationException request = new PaginationException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryMalformedException_succeeds() {
+        final QueryMalformedException request = new QueryMalformedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryNotFoundException_succeeds() {
+        final QueryNotFoundException request = new QueryNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryNotSupportedException_succeeds() {
+        final QueryNotSupportedException request = new QueryNotSupportedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueueNotFoundException_succeeds() {
+        final QueueNotFoundException request = new QueueNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryStoreCreateException_succeeds() {
+        final QueryStoreCreateException request = new QueryStoreCreateException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryStoreGCException_succeeds() {
+        final QueryStoreGCException request = new QueryStoreGCException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryStoreInsertException_succeeds() {
+        final QueryStoreInsertException request = new QueryStoreInsertException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_QueryStorePersistException_succeeds() {
+        final QueryStorePersistException request = new QueryStorePersistException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_RemoteUnavailableException_succeeds() {
+        final RemoteUnavailableException request = new RemoteUnavailableException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_RorNotFoundException_succeeds() {
+        final RorNotFoundException request = new RorNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_SearchServiceConnectionException_succeeds() {
+        final SearchServiceConnectionException request = new SearchServiceConnectionException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_SearchServiceException_succeeds() {
+        final SearchServiceException request = new SearchServiceException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_SemanticEntityNotFoundException_succeeds() {
+        final SemanticEntityNotFoundException request = new SemanticEntityNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_DataServiceConnectionException_succeeds() {
+        final DataServiceConnectionException request = new DataServiceConnectionException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_DataServiceException_succeeds() {
+        final DataServiceException request = new DataServiceException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_SidecarExportException_succeeds() {
+        final SidecarExportException request = new SidecarExportException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_SidecarImportException_succeeds() {
+        final SidecarImportException request = new SidecarImportException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_SortException_succeeds() {
+        final SortException request = new SortException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_StorageNotFoundException_succeeds() {
+        final StorageNotFoundException request = new StorageNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_StorageUnavailableException_succeeds() {
+        final StorageUnavailableException request = new StorageUnavailableException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_TableExistsException_succeeds() {
+        final TableExistsException request = new TableExistsException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_TableMalformedException_succeeds() {
+        final TableMalformedException request = new TableMalformedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_TableSchemaException_succeeds() {
+        final TableSchemaException request = new TableSchemaException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_TableNotFoundException_succeeds() {
+        final TableNotFoundException request = new TableNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_UnitNotFoundException_succeeds() {
+        final UnitNotFoundException request = new UnitNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_UriMalformedException_succeeds() {
+        final UriMalformedException request = new UriMalformedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_UserExistsException_succeeds() {
+        final UserExistsException request = new UserExistsException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_UserNotFoundException_succeeds() {
+        final UserNotFoundException request = new UserNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ViewMalformedException_succeeds() {
+        final ViewMalformedException request = new ViewMalformedException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ViewNotFoundException_succeeds() {
+        final ViewNotFoundException request = new ViewNotFoundException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+
+    @Test
+    public void handle_ViewSchemaException_succeeds() {
+        final ViewSchemaException request = new ViewSchemaException("msg");
+
+        /* test */
+        final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request);
+        assertNotNull(response);
+        assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code());
+        final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code();
+        Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR);
+        assertEquals(httpStatus, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertNotNull(response.getBody().getCode());
+        assertEquals(httpStatus, response.getBody().getStatus());
+        assertEquals("msg", response.getBody().getMessage());
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
index 5898372633b0d63c5b256f6b567f8a8869583ab7..b331a03fa60915290380b5ff233fd51a0996ee36 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
@@ -196,12 +196,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            tableEndpoint.exportData(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL);
-        } catch (Exception e) {
-            /* ignore */
-        }
-        try {
-            tableEndpoint.exportData(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL);
+            tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL);
         } catch (Exception e) {
             /* ignore */
         }
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 aeaae0ecf2626ff88027a210bd8e24a5c66d4ede..b33a76506c15b77df3e0243754ca57b6dfcd9ed4 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
@@ -11,9 +11,10 @@ import at.tuwien.exception.*;
 import at.tuwien.gateway.DataDatabaseSidecarGateway;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.test.AbstractUnitTest;
+import at.tuwien.utils.FileUtils;
 import com.google.common.hash.Hashing;
 import lombok.extern.log4j.Log4j2;
-import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.RandomUtils;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
@@ -387,13 +388,13 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
     protected void export_generic() throws StorageUnavailableException, SQLException,
             QueryMalformedException, SidecarExportException, MetadataServiceException, RemoteUnavailableException,
             StorageNotFoundException, IOException, InterruptedException {
-        final String filename = "68b329da9893e34099c7d8ad5cb9c940";
+        final String filename = RandomStringUtils.randomAlphanumeric(40).toLowerCase() + ".tmp";
+        EXPORT_RESOURCE_DTO.setFilename(filename);
 
         /* 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));
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 e12b5bdc75962076ab52466b6c12493d109ccf64..4ebaba4931327a80ba319ae6407e3dc3547e1dc7 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
@@ -18,6 +18,8 @@ import at.tuwien.api.database.table.constraints.unique.UniqueDto;
 import at.tuwien.api.database.table.internal.TableCreateDto;
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.config.QueryConfig;
+import at.tuwien.config.S3Config;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataDatabaseSidecarGateway;
 import at.tuwien.gateway.MetadataServiceGateway;
@@ -43,6 +45,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermissions;
 import java.sql.SQLException;
 import java.time.Instant;
 import java.util.*;
@@ -63,6 +68,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     @Autowired
     private TableService tableService;
 
+    @Autowired
+    private QueryConfig queryConfig;
+
     @MockBean
     private MetadataServiceGateway metadataServiceGateway;
 
@@ -86,7 +94,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
         /* metadata database */
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME);
+        MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_INTERNALNAME);
         MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_DTO);
     }
 
     @Test
@@ -252,6 +262,35 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
         assertEquals("0.2", result.get(0).get("rainfall"));
     }
 
+    @Test
+    public void createTuple_autogeneratedBlob_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
+            TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException,
+            StorageNotFoundException, MetadataServiceException {
+        final String s3key = "2eec905f-17ed-41de-b12f-283c0aa3e4f9";
+        final byte[] s3data = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+        /* add row with primary key */
+        final TupleDto request = TupleDto.builder()
+                .data(new HashMap<>() {{
+                    put("value", "24.3");
+                    put("raw", s3key);
+                }})
+                .build();
+
+        /* mock */
+        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
+                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
+        when(storageService.getBytes(s3key))
+                .thenReturn(s3data);
+        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_PRIVILEGED_DTO);
+
+        /* test */
+        tableService.createTuple(TABLE_8_PRIVILEGED_DTO, request);
+        final List<Map<String, byte[]>> result = MariaDbConfig.selectQueryByteArr(DATABASE_3_PRIVILEGED_DTO, "SELECT raw FROM mfcc WHERE raw IS NOT NULL", Set.of("raw"));
+        assertNotNull(result.get(0).get("raw"));
+        assertArrayEquals(s3data, result.get(0).get("raw"));
+    }
+
     @Test
     public void createTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException,
             ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
@@ -468,7 +507,16 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
         final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO);
         assertEquals(TABLE_4_NAME, response.getName());
         assertEquals(TABLE_4_INTERNALNAME, response.getInternalName());
-        assertEquals(TABLE_4_COLUMNS.size(), response.getColumns().size());
+        final List<ColumnDto> columns = response.getColumns();
+        assertEquals(TABLE_4_COLUMNS.size(), columns.size());
+        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "timestamp", "timestamp", ColumnTypeDto.TIMESTAMP, null, null, false, queryConfig.getDefaultTimestampFormatId(), null);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "value", "value", ColumnTypeDto.DECIMAL, 10L, 10L, true, null, null);
+        final ConstraintsDto constraints = response.getConstraints();
+        assertNotNull(constraints);
+        final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey();
+        Assertions.assertEquals(1, primaryKey.size());
+        final Set<String> checks = constraints.getChecks();
+        Assertions.assertEquals(0, checks.size());
     }
 
     @Test
@@ -532,6 +580,66 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    public void create_compositePrimaryKey_fails() throws TableNotFoundException, TableMalformedException, SQLException,
+            TableExistsException {
+        final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder()
+                .name("composite_primary_key")
+                .columns(List.of(ColumnCreateDto.builder()
+                                .name("name")
+                                .type(ColumnTypeDto.VARCHAR)
+                                .size(255L)
+                                .nullAllowed(false)
+                                .build(),
+                        ColumnCreateDto.builder()
+                                .name("lat")
+                                .type(ColumnTypeDto.DECIMAL)
+                                .size(10L)
+                                .d(10L)
+                                .nullAllowed(false)
+                                .build(),
+                        ColumnCreateDto.builder()
+                                .name("lng")
+                                .type(ColumnTypeDto.DECIMAL)
+                                .size(10L)
+                                .d(10L)
+                                .nullAllowed(false)
+                                .build()))
+                .constraints(ConstraintsCreateDto.builder()
+                        .primaryKey(Set.of("lat", "lng"))
+                        .foreignKeys(List.of())
+                        .checks(Set.of())
+                        .uniques(List.of())
+                        .build())
+                .build();
+
+        /* test */
+        final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, request);
+        assertEquals("composite_primary_key", response.getName());
+        assertEquals("composite_primary_key", response.getInternalName());
+        final List<ColumnDto> columns = response.getColumns();
+        assertEquals(3, columns.size());
+        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "name", "name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "lat", "lat", ColumnTypeDto.DECIMAL, 10L, 10L, false, null, null);
+        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "lng", "lng", ColumnTypeDto.DECIMAL, 10L, 10L, false, null, null);
+        final ConstraintsDto constraints = response.getConstraints();
+        assertNotNull(constraints);
+        final Set<String> checks = constraints.getChecks();
+        assertNotNull(checks);
+        assertEquals(0, checks.size());
+        final List<PrimaryKeyDto> primaryKeys = new LinkedList<>(constraints.getPrimaryKey());
+        assertNotNull(primaryKeys);
+        assertEquals(2, primaryKeys.size());
+        assertEquals("lat", primaryKeys.get(0).getColumn().getInternalName());
+        assertEquals("lng", primaryKeys.get(1).getColumn().getInternalName());
+        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
+        assertNotNull(foreignKeys);
+        assertEquals(0, foreignKeys.size());
+        final List<UniqueDto> uniques = constraints.getUniques();
+        assertNotNull(uniques);
+        assertEquals(0, uniques.size());
+    }
+
     @Test
     public void create_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException,
             TableExistsException {
@@ -672,7 +780,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
 
         /* mock */
         final File source = new File("src/test/resources/csv/weather_aus.csv");
-        final File target = new File("/tmp/weather_aus.csv");
+        final File target = new File("/tmp/weather_aus.csv") /* must be /tmp */;
         log.trace("copy dataset from {} to {}", source.toPath().toAbsolutePath(), target.toPath().toAbsolutePath());
         FileUtils.copyFile(source, target);
         doNothing()
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/FileUtils.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/FileUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..5746d8dfcfa1de0be7bd707e1c8b3cabf3e82d30
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/FileUtils.java
@@ -0,0 +1,14 @@
+package at.tuwien.utils;
+
+import java.io.File;
+import java.io.IOException;
+
+public class FileUtils {
+
+    public static void delete(File file) throws IOException {
+        if (file.exists()) {
+            org.apache.commons.io.FileUtils.forceDelete(file);
+        }
+    }
+
+}
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
index 13806e93ddd1cbeb7a8e1c0ab4e0fe38db0830ad..13ddfce8d3c171b79096d2e0d1d05948848a8c86 100644
--- 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
@@ -8,6 +8,13 @@ import static org.junit.jupiter.api.Assertions.*;
 
 public class UserUtilTest extends BaseTest {
 
+    @Test
+    public void constructor_succeeds() {
+
+        /* test */
+        new UserUtil();
+    }
+
     @Test
     public void hasRole_succeeds() {
         assertTrue(UserUtil.hasRole(USER_1_PRINCIPAL, "find-container"));
diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql b/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql
index 4d2c8deb43ede5de84cd321a302e97ef84038508..a2fc3f2b313cdd536e8ccba075bf7353be2b1438 100644
--- a/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql
+++ b/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql
@@ -6,7 +6,8 @@ CREATE SEQUENCE seq_mfcc;
 CREATE TABLE mfcc
 (
     id    BIGINT PRIMARY KEY NOT NULL DEFAULT nextval(`seq_mfcc`),
-    value DECIMAL            NOT NULL
+    value DECIMAL            NOT NULL,
+    raw   LONGBLOB           NULL
 ) WITH SYSTEM VERSIONING;
 
 INSERT INTO `mfcc` (`value`)
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 e0d7d0321513387f1e1c9c235c1c4b51e309be1d..cc6960ba39be294a61e059f3a3f45ecfc8e820fd 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
@@ -1,12 +1,8 @@
 package at.tuwien.config;
 
-import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 @Getter
 @Configuration
@@ -26,13 +22,4 @@ public class KeycloakConfig {
 
     @Value("${dbrepo.keycloak.clientSecret}")
     private String keycloakClientSecret;
-
-    @Bean("keycloakRestTemplate")
-    public RestTemplate brokerRestTemplate() {
-        final RestTemplate restTemplate = new RestTemplate();
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
-        restTemplate.getInterceptors()
-                .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 1560c14b7aaa6272c76515a734a1ad99f7075222..e1f763b3b7924748fe80f4485bbef2d3b05cfa23 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
@@ -54,7 +54,8 @@ public class WebSecurityConfig {
         );
         final OrRequestMatcher publicEndpoints = new OrRequestMatcher(
                 new AntPathRequestMatcher("/api/**", "GET"),
-                new AntPathRequestMatcher("/api/**", "HEAD")
+                new AntPathRequestMatcher("/api/**", "HEAD"),
+                new AntPathRequestMatcher("/api/database/**/subset", "POST")
         );
         /* enable CORS and disable CSRF */
         http = http.cors().and().csrf().disable();
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 d16c8c8eba81efd22a64757a6dd1eb51dc56318f..282e7d593feec58991dc9f4530e3314fa208eb29 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
@@ -8,6 +8,7 @@ import at.tuwien.api.database.table.TableStatisticDto;
 import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.PrivilegedUserDto;
+import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.*;
 import jakarta.validation.constraints.NotNull;
@@ -22,9 +23,9 @@ public interface MetadataServiceGateway {
      *
      * @param containerId The container id
      * @return The container with privileged connection information, if successful.
-     * @throws ContainerNotFoundException  The table was not found in the metadata service.
+     * @throws ContainerNotFoundException The table was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
             ContainerNotFoundException, MetadataServiceException;
@@ -36,7 +37,7 @@ 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 MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
             MetadataServiceException;
@@ -48,7 +49,7 @@ 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 MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException,
             RemoteUnavailableException, MetadataServiceException;
@@ -61,19 +62,20 @@ 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 MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException,
             MetadataServiceException;
 
     /**
      * Get a view with given database id and view id from the metadata service.
+     *
      * @param databaseId The database id.
      * @param id         The view id.
      * @return The view, if successful.
-     * @throws ViewNotFoundException     The view was not found in the metadata service.
+     * @throws ViewNotFoundException      The view was not found in the metadata service.
      * @throws RemoteUnavailableException The remote service is not available.
-     * @throws MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException,
             MetadataServiceException;
@@ -85,10 +87,21 @@ 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 MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException;
 
+    /**
+     * Get a user with given username from the metadata service.
+     *
+     * @return The user, if successful. Otherwise empty list.
+     * @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 MetadataServiceException   The remote service returned invalid data.
+     */
+    UUID getSystemUserId() throws RemoteUnavailableException, UserNotFoundException,
+            MetadataServiceException;
+
     /**
      * Get a user with given user id from the metadata service.
      *
@@ -96,42 +109,45 @@ 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 MetadataServiceException The remote service returned invalid data.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
             MetadataServiceException;
 
     /**
      * Get database access for a given user and database id from the metadata service.
+     *
      * @param databaseId The database id.
-     * @param userId The user id.
+     * @param userId     The user id.
      * @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 MetadataServiceException The remote service returned invalid data.
+     * @throws NotAllowedException        The access to this database is denied for the given user.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, NotAllowedException,
             MetadataServiceException;
 
     /**
      * Get a list of identifiers for a given database id and optional subset id.
+     *
      * @param databaseId The database id.
-     * @param subsetId The subset id. Optional.
+     * @param subsetId   The subset id. Optional.
      * @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 MetadataServiceException The remote service returned invalid data.
+     * @throws DatabaseNotFoundException  The database was not found.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws MetadataServiceException,
             RemoteUnavailableException, DatabaseNotFoundException;
 
     /**
      * Update the table statistics in the metadata service.
+     *
      * @param databaseId The database id.
-     * @param tableId The table id.
+     * @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 MetadataServiceException The remote service returned invalid data.
+     * @throws TableNotFoundException     The table was not found.
+     * @throws MetadataServiceException   The remote service returned invalid data.
      */
     void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, MetadataServiceException, RemoteUnavailableException;
 }
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 b4cb2ff5043c46e1e5ece49a45690ef04782bd3c..640ef7172ac2b750815e17a0bdf11b02b5ed997b 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
@@ -10,7 +10,9 @@ import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.PrivilegedUserDto;
+import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
+import at.tuwien.config.GatewayConfig;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.mapper.MetadataMapper;
@@ -35,11 +37,14 @@ import java.util.UUID;
 public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
     private final RestTemplate restTemplate;
+    private final GatewayConfig gatewayConfig;
     private final MetadataMapper metadataMapper;
 
     @Autowired
-    public MetadataServiceGatewayImpl(RestTemplate restTemplate, MetadataMapper metadataMapper) {
+    public MetadataServiceGatewayImpl(RestTemplate restTemplate, GatewayConfig gatewayConfig,
+                                      MetadataMapper metadataMapper) {
         this.restTemplate = restTemplate;
+        this.gatewayConfig = gatewayConfig;
         this.metadataMapper = metadataMapper;
     }
 
@@ -226,6 +231,34 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         return response.getBody();
     }
 
+    @Override
+    public UUID getSystemUserId() throws RemoteUnavailableException, UserNotFoundException,
+            MetadataServiceException {
+        final ResponseEntity<UserBriefDto[]> response;
+        try {
+            response = restTemplate.exchange("/api/user?username=" + gatewayConfig.getSystemUsername(), HttpMethod.GET, HttpEntity.EMPTY, UserBriefDto[].class);
+        } catch (ResourceAccessException | HttpServerErrorException e) {
+            log.error("Failed to find user with username {}: {}", gatewayConfig.getSystemUsername(), e.getMessage());
+            throw new RemoteUnavailableException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": " + e.getMessage(), e);
+        } catch (HttpClientErrorException.NotFound e) {
+            log.error("Failed to find user with username {}: not found: {}", gatewayConfig.getSystemUsername(), e.getMessage());
+            throw new UserNotFoundException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": " + e.getMessage(), e);
+        }
+        if (!response.getStatusCode().equals(HttpStatus.OK)) {
+            log.error("Failed to find user with username {}: service responded unsuccessful: {}", gatewayConfig.getSystemUsername(), response.getStatusCode());
+            throw new MetadataServiceException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": service responded unsuccessful: " + response.getStatusCode());
+        }
+        if (response.getBody() == null) {
+            log.error("Failed to find user with username {}: body is empty", gatewayConfig.getSystemUsername());
+            throw new MetadataServiceException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": body is empty");
+        }
+        if (response.getBody().length != 1) {
+            log.error("Failed to find system user: expected exactly one result but got {}", response.getBody().length);
+            throw new MetadataServiceException("Failed to find system user: expected exactly one result but got " + response.getBody().length);
+        }
+        return response.getBody()[0].getId();
+    }
+
     @Override
     public PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
             MetadataServiceException {
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java b/dbrepo-data-service/services/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java
deleted file mode 100644
index 78fb5adc61fd2420cfc62e72cb4aa4c700c3b82b..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package at.tuwien.interceptor;
-
-import at.tuwien.api.keycloak.TokenDto;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.http.*;
-import org.springframework.http.client.ClientHttpRequestExecution;
-import org.springframework.http.client.ClientHttpRequestInterceptor;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.ResourceAccessException;
-import org.springframework.web.client.RestTemplate;
-
-import java.io.IOException;
-
-@Log4j2
-public class KeycloakInterceptor implements ClientHttpRequestInterceptor {
-
-    private final String adminUsername;
-    private final String adminPassword;
-    private final String keycloakEndpoint;
-
-    public KeycloakInterceptor(String adminUsername, String adminPassword, String keycloakEndpoint) {
-        this.adminUsername = adminUsername;
-        this.adminPassword = adminPassword;
-        this.keycloakEndpoint = keycloakEndpoint;
-    }
-
-    @Override
-    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
-            throws IOException {
-        final RestTemplate restTemplate = new RestTemplate();
-        final HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
-        final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
-        payload.add("username", adminUsername);
-        payload.add("password", adminPassword);
-        payload.add("grant_type", "password");
-        payload.add("client_id", "admin-cli");
-        final ResponseEntity<TokenDto> response;
-        try {
-            response = restTemplate.exchange(keycloakEndpoint + "/realms/master/protocol/openid-connect/token",
-                    HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
-        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
-            log.error("Failed to obtain admin token: {}", e.getMessage());
-            return execution.execute(request, body);
-        }
-        if (response.getBody() == null) {
-            return execution.execute(request, body);
-        }
-        request.getHeaders().set("Authorization", "Bearer " + response.getBody().getAccessToken());
-        return execution.execute(request, body);
-    }
-}
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 56888cde6421d176940e72fc24c4fdd44796ef2f..d870215771628283ddb9e115a755c176d7f69240 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
@@ -837,17 +837,8 @@ public interface MariaDbMapper {
                     statement.setNull(idx, Types.BLOB);
                     break;
                 }
-                try {
-                    final ByteArrayOutputStream boas = new ByteArrayOutputStream();
-                    try (ObjectOutputStream ois = new ObjectOutputStream(boas)) {
-                        ois.writeObject(value);
-                        statement.setBlob(idx, new ByteArrayInputStream(boas.toByteArray()));
-                    }
-
-                } catch (IOException e) {
-                    log.error("Failed to set blob/tinyblob/mediumblob/longblob: {}", e.getMessage());
-                    throw new SQLException("Failed to set blob: " + e.getMessage(), e);
-                }
+                final byte[] data = (byte[]) value;
+                statement.setBlob(idx, new ByteArrayInputStream(data));
                 break;
             case TEXT, CHAR, VARCHAR, TINYTEXT, MEDIUMTEXT, LONGTEXT, ENUM, SET:
                 if (value == null) {
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java
index e03878b8c19197e4347897c555a91d985c10fb72..c1f546ce4462d60eb08b1f34683efd7f05dca0f9 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java
@@ -15,6 +15,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 key was not found in the Storage Service.
      */
     InputStream getObject(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException;
 
@@ -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 key was not 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 key was not found in the Storage Service.
      */
     byte[] getBytes(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException;
 
@@ -43,6 +46,7 @@ public interface StorageService {
      * @param key The object key.
      * @return The export resource, if successful.
      * @throws StorageUnavailableException The object failed to be loaded from the Storage Service.
+     * @throws StorageNotFoundException    The key was not found in the Storage Service.
      */
     ExportResourceDto getResource(String key) throws StorageUnavailableException, StorageNotFoundException;
 
@@ -53,6 +57,7 @@ public interface StorageService {
      * @param key    The object key.
      * @return The export resource, if successful.
      * @throws StorageUnavailableException The object failed to be loaded from the Storage Service.
+     * @throws StorageNotFoundException    The key was not found in the Storage Service.
      */
     ExportResourceDto getResource(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException;
 
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 3c3ff101fead4b51caadc8c207848d2b962f98eb..56250a2917f2083d53bbeec51f6e3b1dae0e0cd1 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
@@ -26,16 +26,60 @@ public interface SubsetService {
     void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException,
             QueryStoreCreateException;
 
+    /**
+     * Creates a subset from the given statement at given time in the given database.
+     *
+     * @param database      The database.
+     * @param statement     The subset statement.
+     * @param timestamp     The timestamp as of which the data is queried. If smaller than <now>, historic data is queried.
+     * @param userId        The user id of the creating user.
+     * @param page          The page number. Optional but requires size to be set too.
+     * @param size          The page size. Optional but requires page to be set too.
+     * @param sortDirection The sort direction.
+     * @param sortColumn    The column that is sorted.
+     * @return The query result.
+     * @throws QueryStoreInsertException  The query store refused to insert the query.
+     * @throws SQLException               The connection to the database could not be established.
+     * @throws QueryNotFoundException     The query was not found for re-execution.
+     * @throws TableMalformedException    The table is malformed.
+     * @throws UserNotFoundException      The user was not found.
+     * @throws NotAllowedException        The operation is not allowed.
+     * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service.
+     * @throws DatabaseNotFoundException  The database was not found in the Metadata Service.
+     * @throws MetadataServiceException   The Metadata Service responded unexpected.
+     */
     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, DatabaseNotFoundException,
             MetadataServiceException;
 
+    /**
+     * Re-executes the query of a given subset in the given database.
+     *
+     * @param database      The database.
+     * @param query         The subset.
+     * @param page          The page number. Optional but requires size to be set too.
+     * @param size          The page size. Optional but requires page to be set too.
+     * @param sortDirection The sort direction.
+     * @param sortColumn    The column that is sorted.
+     * @return The query result.
+     * @throws TableMalformedException The table is malformed.
+     * @throws SQLException            The connection to the database could not be established.
+     */
     QueryResultDto reExecute(PrivilegedDatabaseDto database, QueryDto query, Long page, Long size,
                              SortTypeDto sortDirection, String sortColumn) throws TableMalformedException,
             SQLException;
 
+    /**
+     * Counts the subset row count of a query of a given subset in the given database.
+     *
+     * @param database The database.
+     * @param query    The subset.
+     * @return The row count.
+     * @throws TableMalformedException The table is malformed.
+     * @throws SQLException            The connection to the database could not be established.
+     */
     Long reExecuteCount(PrivilegedDatabaseDto database, QueryDto query) throws TableMalformedException,
             SQLException, QueryMalformedException;
 
@@ -45,15 +89,45 @@ public interface SubsetService {
      * @param database        The database.
      * @param filterPersisted Optional filter to only display persisted queries, or non-persisted queries.
      * @return The list of queries.
+     * @throws SQLException               The connection to the database could not be established.
+     * @throws QueryNotFoundException     The query was not found for re-execution.
+     * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service.
+     * @throws DatabaseNotFoundException  The database was not found in the Metadata Service.
+     * @throws MetadataServiceException   The Metadata Service responded unexpected.
      */
     List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException,
-            QueryNotFoundException, NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException,
-            MetadataServiceException;
+            QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException;
 
+    /**
+     * Exports a subset by re-executing the query in a given database with given timestamp to a given filename.
+     *
+     * @param database  The database.
+     * @param query     The query.
+     * @param timestamp The timestamp.
+     * @param filename  The filename.
+     * @return The exported subset.
+     * @throws SQLException                The connection to the database could not be established.
+     * @throws QueryMalformedException     The mapped export query produced a database error.
+     * @throws SidecarExportException      The sidecar of the given database failed to communicate.
+     * @throws StorageNotFoundException    The exported subset was not found from the key provided by the sidecar in the Storage Service.
+     * @throws StorageUnavailableException The communication to the Storage Service failed.
+     * @throws RemoteUnavailableException  The privileged database information could not be found in the Metadata Service.
+     */
     ExportResourceDto export(PrivilegedDatabaseDto database, QueryDto query, Instant timestamp, String filename)
             throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException,
-            StorageUnavailableException, MetadataServiceException, RemoteUnavailableException;
+            StorageUnavailableException, RemoteUnavailableException;
 
+    /**
+     * Executes a subset query without saving it.
+     *
+     * @param database  The database.
+     * @param statement The subset query.
+     * @param timestamp The timestamp.
+     * @return The row count.
+     * @throws SQLException            The connection to the database could not be established.
+     * @throws QueryMalformedException The mapped query produced a database error.
+     * @throws TableMalformedException The database table is malformed.
+     */
     Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp)
             throws SQLException, QueryMalformedException, TableMalformedException;
 
@@ -63,11 +137,15 @@ public interface SubsetService {
      * @param database The database.
      * @param queryId  The query id.
      * @return The query.
-     * @throws QueryNotFoundException The query store did not return a query
+     * @throws QueryNotFoundException     The query store did not return a query.
+     * @throws SQLException               The connection to the database could not be established.
+     * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service.
+     * @throws UserNotFoundException      The user that created the query was not found in the Metadata Service.
+     * @throws DatabaseNotFoundException  The database metadata was not found in the Metadata Service.
+     * @throws MetadataServiceException   Communication with the Metadata Service failed.
      */
     QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException,
-            NotAllowedException, RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException,
-            MetadataServiceException;
+            RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException, MetadataServiceException;
 
     /**
      * Inserts a query and metadata to the query store of a given database id.
@@ -75,7 +153,9 @@ public interface SubsetService {
      * @param database The database.
      * @param query    The query statement.
      * @param userId   The user id.
-     * @return The stored query on success
+     * @return The stored query id on success.
+     * @throws SQLException              The connection to the database could not be established.
+     * @throws QueryStoreInsertException The query store failed to insert the query.
      */
     Long storeQuery(PrivilegedDatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException,
             QueryStoreInsertException;
@@ -83,15 +163,21 @@ public interface SubsetService {
     /**
      * Persists a query to be displayed in the frontend.
      *
-     * @param database The database id.
+     * @param database The database.
      * @param queryId  The query id.
      * @param persist  If true, the query is retained in the query store, ephemeral otherwise.
+     * @throws SQLException               The connection to the database could not be established.
+     * @throws QueryStorePersistException The query store failed to persist/unpersist the query.
      */
     void persist(PrivilegedDatabaseDto database, Long queryId, Boolean persist) throws SQLException,
             QueryStorePersistException;
 
     /**
      * Deletes the stale queries that have not been persisted within 24 hours.
+     *
+     * @param database The database.
+     * @throws SQLException          The connection to the database could not be established.
+     * @throws QueryStoreGCException The query store failed to delete stale queries.
      */
     void deleteStaleQueries(PrivilegedDatabaseDto database) throws SQLException, QueryStoreGCException;
 }
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 53d93d35dfaa11d4ec40ef5e00b73050ebea91c5..7ebd403b6903737c07f2197593ab6229851c32e3 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
@@ -28,7 +28,6 @@ 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;
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 557d1e49aba58b799f3dfa65fea8c4d0a8f7cf4c..fe267fe35ab4c1b7f2cd7e658baa4b765d4d28e2 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
@@ -749,6 +749,8 @@ public interface MetadataMapper {
     })
     UserDetailsDto userDtoToUserDetailsDto(UserDto data);
 
+    User userDtoToUser(at.tuwien.api.keycloak.UserDto data);
+
     /* keep */
     @Mappings({
             @Mapping(target = "name", expression = "java(userToFullName(data))"),
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 4be54d5edd1ed39168b97a00177d87d09a7a87ee..b81a8142f727972c95ce0ea5573b99e3d1e59be9 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
@@ -68,13 +68,21 @@ public class UserEndpoint {
                             mediaType = "application/json",
                             array = @ArraySchema(schema = @Schema(implementation = UserBriefDto.class)))}),
     })
-    public ResponseEntity<List<UserBriefDto>> findAll() {
-        log.debug("endpoint find all users");
-        final List<UserBriefDto> users = userService.findAll()
-                .stream()
-                .map(userMapper::userToUserBriefDto)
-                .toList();
-        return ResponseEntity.ok(users);
+    public ResponseEntity<List<UserBriefDto>> findAll(@RequestParam(required = false) String username) {
+        log.debug("endpoint find all users, username={}", username);
+        if (username == null) {
+            return ResponseEntity.ok(userService.findAll()
+                    .stream()
+                    .map(userMapper::userToUserBriefDto)
+                    .toList());
+        }
+        try {
+            log.trace("filter by username: {}", username);
+            return ResponseEntity.ok(List.of(userMapper.userToUserBriefDto(userService.findByUsername(username))));
+        } catch (UserNotFoundException e) {
+            log.trace("filter by username {} failed: return empty list", username);
+            return ResponseEntity.ok(List.of());
+        }
     }
 
     @PostMapping
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 f5e413e0e9de10192bca89d4fe823db02924712d..ad4cef5bbea6cb262607ebbad44f6ec8148b6f9b 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
@@ -45,18 +45,37 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_anonymous_succeeds() {
+    public void findAll_anonymous_succeeds() throws UserNotFoundException {
 
         /* test */
-        findAll_generic();
+        final List<UserBriefDto> response = findAll_generic(null, null);
+        assertEquals(2, response.size());
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void findAll_noRole_succeeds() {
+    public void findAll_noRole_succeeds() throws UserNotFoundException {
 
         /* test */
-        findAll_generic();
+        final List<UserBriefDto> response = findAll_generic(null, null);
+        assertEquals(2, response.size());
+    }
+
+    @Test
+    public void findAll_filterUsername_succeeds() throws UserNotFoundException {
+
+        /* test */
+        final List<UserBriefDto> response = findAll_generic(USER_2_USERNAME, USER_2);
+        assertEquals(1, response.size());
+        assertEquals(USER_2_ID, response.get(0).getId());
+    }
+
+    @Test
+    public void findAll_filterUsername_fails() throws UserNotFoundException {
+
+        /* test */
+        final List<UserBriefDto> response = findAll_generic(USER_5_USERNAME, null);
+        assertEquals(0, response.size());
     }
 
     @Test
@@ -100,7 +119,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void find_self_succeeds() throws NotAllowedException, UserNotFoundException{
+    public void find_self_succeeds() throws NotAllowedException, UserNotFoundException {
 
         /* test */
         find_generic(USER_1_ID, USER_1, USER_1_PRINCIPAL);
@@ -231,18 +250,29 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
-    protected void findAll_generic() {
+    protected List<UserBriefDto> findAll_generic(String username, User user) throws UserNotFoundException {
 
         /* mock */
-        when(userService.findAll())
-                .thenReturn(List.of(USER_1, USER_2));
+        if (username != null) {
+            if (user != null) {
+                when(userService.findByUsername(username))
+                        .thenReturn(user);
+            } else {
+                doThrow(UserNotFoundException.class)
+                        .when(userService)
+                        .findByUsername(username);
+            }
+        } else {
+            when(userService.findAll())
+                    .thenReturn(List.of(USER_1, USER_2));
+        }
 
         /* test */
-        final ResponseEntity<List<UserBriefDto>> response = userEndpoint.findAll();
+        final ResponseEntity<List<UserBriefDto>> response = userEndpoint.findAll(username);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final List<UserBriefDto> body = response.getBody();
         assertNotNull(body);
-        assertEquals(2, body.size());
+        return response.getBody();
     }
 
     protected void create_generic(SignupRequestDto data, User user, at.tuwien.api.keycloak.UserDto userDto, UUID id)
@@ -265,7 +295,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected void find_generic(UUID id, User user, Principal principal) throws NotAllowedException,
-            UserNotFoundException{
+            UserNotFoundException {
 
         /* mock */
         if (user != null) {
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 8183ea90808ea6c7e48e1530ea2a88a62a34df9b..698f7ed524c13bbb3d9fbe5fca37003419f51a4c 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
@@ -1103,7 +1103,7 @@ public class DataServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void getTableStatistics_emptyBody_fails() {
+    public void getTableStatistics_emptyBody_fails() throws TableNotFoundException, DataServiceException, DataServiceConnectionException {
 
         /* mock */
         when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class)))
@@ -1111,9 +1111,7 @@ public class DataServiceGatewayUnitTest extends AbstractUnitTest {
                         .build());
 
         /* test */
-        assertThrows(DataServiceException.class, () -> {
-            dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
-        });
+        dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID);
     }
 
 }
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 d3f75d70602ffb2dad2a6b2adc8797eb7636135c..0b804dbdeab1fe3777614fafc7e4b790249bf569 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
@@ -566,7 +566,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
 
         /* mock */
         try {
-            userEndpoint.findAll();
+            userEndpoint.findAll(null);
         } catch (Exception e) {
             /* ignore */
         }
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 886911d9f4a770fe8c620d7cc882cd7b4da05c55..0c11de442957cbc6deee1d20d7f51b865017a90b 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
@@ -372,7 +372,8 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
     }
 
     @Override
-    public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws DataServiceConnectionException, DataServiceException, TableNotFoundException {
+    public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws DataServiceConnectionException,
+            DataServiceException, TableNotFoundException {
         final ResponseEntity<TableStatisticDto> response;
         final String path = "/api/database/" + databaseId + "/table/" + tableId + "/statistic";
         log.trace("get table statistics at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path);
@@ -392,10 +393,6 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
             log.error("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 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/init/InitHandler.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/init/InitHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f7c8ced0a84bf4dc37f41b36b46408a68aa42df
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/init/InitHandler.java
@@ -0,0 +1,59 @@
+package at.tuwien.init;
+
+import at.tuwien.api.keycloak.UserDto;
+import at.tuwien.config.GatewayConfig;
+import at.tuwien.config.MetadataConfig;
+import at.tuwien.entities.user.User;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.repository.UserRepository;
+import at.tuwien.service.UserService;
+import jakarta.annotation.PostConstruct;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+
+@Log4j2
+@Component
+@Profile("!junit")
+public class InitHandler {
+
+    private final UserService userService;
+    private final GatewayConfig gatewayConfig;
+    private final MetadataConfig metadataConfig;
+    private final UserRepository userRepository;
+    private final KeycloakGateway keycloakGateway;
+
+    @Autowired
+    public InitHandler(UserService userService, GatewayConfig gatewayConfig, MetadataConfig metadataConfig,
+                       UserRepository userRepository, KeycloakGateway keycloakGateway) {
+        this.userService = userService;
+        this.gatewayConfig = gatewayConfig;
+        this.metadataConfig = metadataConfig;
+        this.userRepository = userRepository;
+        this.keycloakGateway = keycloakGateway;
+    }
+
+    @PostConstruct
+    public void init() throws UserNotFoundException, AuthServiceException, AuthServiceConnectionException {
+        try {
+            userService.findByUsername(gatewayConfig.getSystemUsername());
+        } catch (UserNotFoundException e) {
+            log.warn("Failed to find system user with username {} in metadata database", gatewayConfig.getSystemUsername());
+            final UserDto user = keycloakGateway.findByUsername(gatewayConfig.getSystemUsername());
+            final User entity = User.builder()
+                    .id(user.getId())
+                    .username(user.getUsername())
+                    .email(metadataConfig.getAdminEmail())
+                    .theme("light")
+                    .mariadbPassword(userService.getMariaDbPassword(gatewayConfig.getSystemPassword()))
+                    .language("en")
+                    .build();
+            userRepository.save(entity);
+            log.info("Saved system user with username: {}", gatewayConfig.getSystemUsername());
+        }
+    }
+}
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java
index 92e0bc37ee2b58eddc9faa86f08d4748caf662f5..8e7c715ad06d434bfdb947136546f686e91835ad 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java
@@ -76,4 +76,6 @@ public interface UserService {
      * @throws EmailExistsException The user with this email already exists.
      */
     void validateEmailNotExists(String email) throws EmailExistsException;
+
+    String getMariaDbPassword(String password);
 }
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 7ca855974e86b23a5a2ec8abcbc124f97a0e8ab7..f88ba5c28f4d928757a501d8ed1a3f4effb018d8 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
@@ -270,6 +270,9 @@ public class TableServiceImpl implements TableService {
             DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException,
             DataServiceException, DataServiceConnectionException {
         final TableStatisticDto statistic = dataServiceGateway.getTableStatistics(table.getTdbid(), table.getId());
+        if (statistic == null) {
+            return;
+        }
         table.setNumRows(statistic.getRows());
         table.setDataLength(statistic.getDataLength());
         table.setAvgRowLength(statistic.getAvgRowLength());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
index 547a01c2fab73cf410673778747f0545c40907de..7e07b68d1c965ed42261ab508273770be50a6454 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
@@ -105,6 +105,7 @@ public class UserServiceImpl implements UserService {
         }
     }
 
+    @Override
     public String getMariaDbPassword(String password) {
         final byte[] utf8 = password.getBytes(StandardCharsets.UTF_8);
         return "*" + DigestUtils.sha1Hex(DigestUtils.sha1(utf8)).toUpperCase();
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java
index 156563a041c833376f850465032f28b69602e020..23ba450312b224d76e729613c005489fb7cc8826 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java
@@ -83,6 +83,7 @@ public abstract class AbstractUnitTest extends BaseTest {
         TABLE_5.setColumns(new LinkedList<>(TABLE_5_COLUMNS));
         TABLE_5.setConstraints(TABLE_5_CONSTRAINTS);
         TABLE_5_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO));
+        TABLE_5_PRIVILEGED_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO);
         TABLE_5_PRIVILEGED_DTO.setDatabase(DATABASE_2_PRIVILEGED_DTO);
         TABLE_5_DTO.setColumns(TABLE_5_COLUMNS_DTO);
         TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO);
@@ -113,6 +114,7 @@ public abstract class AbstractUnitTest extends BaseTest {
         TABLE_8_DTO.setConstraints(TABLE_8_CONSTRAINTS_DTO);
         TABLE_8_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_8_COLUMNS_DTO));
         TABLE_8_PRIVILEGED_DTO.setConstraints(TABLE_8_CONSTRAINTS_DTO);
+        TABLE_8_PRIVILEGED_DTO.setDatabase(DATABASE_3_PRIVILEGED_DTO);
         VIEW_5.setDatabase(DATABASE_3);
         VIEW_5.setColumns(VIEW_5_COLUMNS);
         IDENTIFIER_6.setDatabase(DATABASE_3);
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 0341a7a5dfad8f3a218dd195631ff956289b6b15..dfaf58d995e8e57ef8fcc017c551ff0720bc8a4a 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
@@ -90,6 +90,8 @@ import java.math.BigInteger;
 import java.nio.charset.Charset;
 import java.security.Principal;
 import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -380,6 +382,7 @@ public abstract class BaseTest {
     public final static String USER_BROKER_USERNAME = "guest";
     public final static String USER_BROKER_PASSWORD = "guest";
 
+    public final static UUID USER_LOCAL_ADMIN_ID = UUID.fromString("a54dcb2e-a644-4e82-87e7-05a96413983d");
     public final static String USER_LOCAL_ADMIN_USERNAME = "admin";
     public final static String USER_LOCAL_ADMIN_PASSWORD = "admin";
 
@@ -1679,6 +1682,40 @@ public abstract class BaseTest {
             .owner(USER_1_BRIEF_DTO)
             .build();
 
+    public final static Long TABLE_1_DATA_COUNT = 3L;
+    public final static QueryResultDto TABLE_1_DATA_DTO = QueryResultDto.builder()
+            .headers(new LinkedList<>(List.of(new HashMap<>() {{
+                put("id", 0);
+                put("date", 1);
+                put("location", 2);
+                put("mintemp", 3);
+                put("rainfall", 4);
+            }})))
+            .result(new LinkedList<>(List.of(
+                    new HashMap<>() {{
+                        put("id", BigInteger.valueOf(1L));
+                        put("date", LocalDate.of(2008, 12, 1).atStartOfDay().toInstant(ZoneOffset.UTC));
+                        put("location", "Albury");
+                        put("mintemp", 13.4);
+                        put("rainfall", 0.6);
+                    }},
+                    new HashMap<>() {{
+                        put("id", BigInteger.valueOf(2L));
+                        put("date", LocalDate.of(2008, 12, 2).atStartOfDay().toInstant(ZoneOffset.UTC));
+                        put("location", "Albury");
+                        put("mintemp", 7.4);
+                        put("rainfall", 0);
+                    }},
+                    new HashMap<>() {{
+                        put("id", BigInteger.valueOf(3L));
+                        put("date", LocalDate.of(2008, 12, 3).atStartOfDay().toInstant(ZoneOffset.UTC));
+                        put("location", "Albury");
+                        put("mintemp", 12.9);
+                        put("rainfall", 0);
+                    }}
+            )))
+            .build();
+
     public final static Long TABLE_2_ID = 2L;
     public final static String TABLE_2_NAME = "Weather Location";
     public final static String TABLE_2_INTERNALNAME = "weather_location";
@@ -1846,6 +1883,8 @@ public abstract class BaseTest {
             .build();
 
     public final static ConstraintsCreateDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = ConstraintsCreateDto.builder()
+            .checks(new LinkedHashSet<>())
+            .primaryKey(new LinkedHashSet<>()) // <<<<
             .uniques(new LinkedList<>())
             .foreignKeys(List.of(ForeignKeyCreateDto.builder()
                     .referencedTable("weather_location")
@@ -2169,7 +2208,7 @@ public abstract class BaseTest {
 
     public final static ConstraintsCreateDto TABLE_4_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder()
             .checks(new LinkedHashSet<>())
-            .primaryKey(new LinkedHashSet<>())
+            .primaryKey(new LinkedHashSet<>(Set.of("Timestamp")))
             .foreignKeys(new LinkedList<>())
             .uniques(List.of(List.of("Timestamp")))
             .build();
@@ -2404,37 +2443,32 @@ public abstract class BaseTest {
 
     public final static Long COLUMN_8_1_ID = 72L;
     public final static Integer COLUMN_8_1_ORDINALPOS = 0;
-    public final static Boolean COLUMN_8_1_PRIMARY = true;
     public final static String COLUMN_8_1_NAME = "ID";
     public final static String COLUMN_8_1_INTERNAL_NAME = "id";
     public final static TableColumnType COLUMN_8_1_TYPE = TableColumnType.BIGINT;
     public final static ColumnTypeDto COLUMN_8_1_TYPE_DTO = ColumnTypeDto.BIGINT;
-    public final static Long COLUMN_8_1_DATE_FORMAT = null;
     public final static Boolean COLUMN_8_1_NULL = false;
     public final static Boolean COLUMN_8_1_AUTO_GENERATED = true;
-    public final static String COLUMN_8_1_FOREIGN_KEY = null;
-    public final static String COLUMN_8_1_CHECK = null;
-    public final static List<String> COLUMN_8_1_ENUM_VALUES = null;
-    public final static List<String> COLUMN_8_1_ENUM_VALUES_DTO = null;
-    public final static List<String> COLUMN_8_1_SET_VALUES = null;
-    public final static List<String> COLUMN_8_1_SET_VALUES_DTO = null;
 
     public final static Long COLUMN_8_2_ID = 73L;
     public final static Integer COLUMN_8_2_ORDINALPOS = 1;
-    public final static Boolean COLUMN_8_2_PRIMARY = true;
     public final static String COLUMN_8_2_NAME = "Value";
     public final static String COLUMN_8_2_INTERNAL_NAME = "value";
-    public final static TableColumnType COLUMN_8_2_TYPE = TableColumnType.INT;
-    public final static ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.INT;
-    public final static Long COLUMN_8_2_DATE_FORMAT = null;
-    public final static Boolean COLUMN_8_2_NULL = true;
+    public final static TableColumnType COLUMN_8_2_TYPE = TableColumnType.DECIMAL;
+    public final static ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.DECIMAL;
+    public final static Long COLUMN_8_2_SIZE = 10L;
+    public final static Long COLUMN_8_2_D = 10L;
+    public final static Boolean COLUMN_8_2_NULL = false;
     public final static Boolean COLUMN_8_2_AUTO_GENERATED = false;
-    public final static String COLUMN_8_2_FOREIGN_KEY = null;
-    public final static String COLUMN_8_2_CHECK = null;
-    public final static List<String> COLUMN_8_2_ENUM_VALUES = null;
-    public final static List<String> COLUMN_8_2_ENUM_VALUES_DTO = null;
-    public final static List<String> COLUMN_8_2_SET_VALUES = null;
-    public final static List<String> COLUMN_8_2_SET_VALUES_DTO = null;
+
+    public final static Long COLUMN_8_3_ID = 74L;
+    public final static Integer COLUMN_8_3_ORDINALPOS = 2;
+    public final static String COLUMN_8_3_NAME = "raw";
+    public final static String COLUMN_8_3_INTERNAL_NAME = "raw";
+    public final static TableColumnType COLUMN_8_3_TYPE = TableColumnType.LONGBLOB;
+    public final static ColumnTypeDto COLUMN_8_3_TYPE_DTO = ColumnTypeDto.LONGBLOB;
+    public final static Boolean COLUMN_8_3_NULL = true;
+    public final static Boolean COLUMN_8_3_AUTO_GENERATED = false;
 
     public final static ColumnBriefDto TABLE_8_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
             .id(COLUMN_8_1_ID)
@@ -2462,6 +2496,18 @@ public abstract class BaseTest {
                     .columnType(COLUMN_8_2_TYPE)
                     .isNullAllowed(COLUMN_8_2_NULL)
                     .autoGenerated(COLUMN_8_2_AUTO_GENERATED)
+                    .size(COLUMN_8_2_SIZE)
+                    .d(COLUMN_8_2_D)
+                    .build(),
+            TableColumn.builder()
+                    .id(COLUMN_8_3_ID)
+                    .ordinalPosition(COLUMN_8_3_ORDINALPOS)
+                    .table(TABLE_8)
+                    .name(COLUMN_8_3_NAME)
+                    .internalName(COLUMN_8_3_INTERNAL_NAME)
+                    .columnType(COLUMN_8_3_TYPE)
+                    .isNullAllowed(COLUMN_8_3_NULL)
+                    .autoGenerated(COLUMN_8_3_AUTO_GENERATED)
                     .build());
 
     public final static List<ColumnDto> TABLE_8_COLUMNS_DTO = List.of(ColumnDto.builder()
@@ -2483,6 +2529,16 @@ public abstract class BaseTest {
                     .columnType(COLUMN_8_2_TYPE_DTO)
                     .isNullAllowed(COLUMN_8_2_NULL)
                     .autoGenerated(COLUMN_8_2_AUTO_GENERATED)
+                    .build(),
+            ColumnDto.builder()
+                    .id(COLUMN_8_3_ID)
+                    .ordinalPosition(COLUMN_8_3_ORDINALPOS)
+                    .table(TABLE_8_DTO)
+                    .name(COLUMN_8_3_NAME)
+                    .internalName(COLUMN_8_3_INTERNAL_NAME)
+                    .columnType(COLUMN_8_3_TYPE_DTO)
+                    .isNullAllowed(COLUMN_8_3_NULL)
+                    .autoGenerated(COLUMN_8_3_AUTO_GENERATED)
                     .build());
 
     public final static Long TABLE_8_DATA_COUNT = 6L;
@@ -2492,12 +2548,36 @@ public abstract class BaseTest {
                 put(COLUMN_8_2_INTERNAL_NAME, 1);
             }})))
             .result(new LinkedList<>(List.of(
-                    Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(1L), COLUMN_8_2_INTERNAL_NAME, 11.2),
-                    Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(2L), COLUMN_8_2_INTERNAL_NAME, 11.3),
-                    Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(3L), COLUMN_8_2_INTERNAL_NAME, 11.4),
-                    Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(4L), COLUMN_8_2_INTERNAL_NAME, 11.9),
-                    Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(5L), COLUMN_8_2_INTERNAL_NAME, 12.3),
-                    Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(6L), COLUMN_8_2_INTERNAL_NAME, 23.1)
+                    new HashMap<>() {{
+                        put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(1L));
+                        put(COLUMN_8_2_INTERNAL_NAME, 11.2);
+                        put(COLUMN_8_3_INTERNAL_NAME, null);
+                    }},
+                    new HashMap<>() {{
+                        put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(2L));
+                        put(COLUMN_8_2_INTERNAL_NAME, 11.3);
+                        put(COLUMN_8_3_INTERNAL_NAME, null);
+                    }},
+                    new HashMap<>() {{
+                        put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(3L));
+                        put(COLUMN_8_2_INTERNAL_NAME, 11.4);
+                        put(COLUMN_8_3_INTERNAL_NAME, null);
+                    }},
+                    new HashMap<>() {{
+                        put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(4L));
+                        put(COLUMN_8_2_INTERNAL_NAME, 11.9);
+                        put(COLUMN_8_3_INTERNAL_NAME, null);
+                    }},
+                    new HashMap<>() {{
+                        put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(5L));
+                        put(COLUMN_8_2_INTERNAL_NAME, 12.3);
+                        put(COLUMN_8_3_INTERNAL_NAME, null);
+                    }},
+                    new HashMap<>() {{
+                        put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(6L));
+                        put(COLUMN_8_2_INTERNAL_NAME, 23.1);
+                        put(COLUMN_8_3_INTERNAL_NAME, null);
+                    }}
             )))
             .build();
 
@@ -2876,6 +2956,13 @@ public abstract class BaseTest {
             .uniques(List.of(List.of("date")))
             .build();
 
+    public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = ConstraintsCreateDto.builder()
+            .checks(new LinkedHashSet<>())
+            .primaryKey(new LinkedHashSet<>())
+            .foreignKeys(new LinkedList<>())
+            .uniques(List.of(List.of("date")))
+            .build();
+
     public final static TableCreateDto TABLE_1_CREATE_DTO = TableCreateDto.builder()
             .name(TABLE_1_NAME)
             .description(TABLE_1_DESCRIPTION)
@@ -2890,6 +2977,13 @@ public abstract class BaseTest {
             .constraints(TABLE_1_CONSTRAINTS_CREATE_DTO)
             .build();
 
+    public final static at.tuwien.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_INVALID_DTO = at.tuwien.api.database.table.internal.TableCreateDto.builder()
+            .name(TABLE_1_NAME)
+            .description(TABLE_1_DESCRIPTION)
+            .columns(TABLE_1_COLUMNS_CREATE_DTO)
+            .constraints(TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO)
+            .build();
+
     public final static List<TableColumn> TABLE_2_COLUMNS = List.of(TableColumn.builder()
                     .id(6L)
                     .ordinalPosition(0)
@@ -5105,6 +5199,8 @@ public abstract class BaseTest {
     public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location` and m.`date` = w.`date`";
     public final static String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255";
 
+    public final static Long VIEW_3_DATA_COUNT = 3L;
+
     public final static List<ViewColumnDto> VIEW_3_COLUMNS_DTO = List.of(
             ViewColumnDto.builder()
                     .id(8L)
@@ -7118,6 +7214,13 @@ public abstract class BaseTest {
             .user(USER_2)
             .build();
 
+    public final static DatabaseAccessDto DATABASE_1_USER_2_READ_ACCESS_DTO = DatabaseAccessDto.builder()
+            .type(AccessTypeDto.READ)
+            .hdbid(DATABASE_1_ID)
+            .huserid(USER_2_ID)
+            .user(USER_2_DTO)
+            .build();
+
     public final static DatabaseAccess DATABASE_1_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder()
             .type(AccessType.WRITE_OWN)
             .hdbid(DATABASE_1_ID)
@@ -7141,6 +7244,13 @@ public abstract class BaseTest {
             .user(USER_2)
             .build();
 
+    public final static DatabaseAccessDto DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder()
+            .type(AccessTypeDto.WRITE_ALL)
+            .hdbid(DATABASE_1_ID)
+            .huserid(USER_2_ID)
+            .user(USER_2_DTO)
+            .build();
+
     public final static DatabaseAccess DATABASE_1_USER_3_READ_ACCESS = DatabaseAccess.builder()
             .type(AccessType.READ)
             .hdbid(DATABASE_1_ID)
diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue
index 0c87e5599c688b3c4feebfbadb09a8868071d54d..741252475c31ef841260266d3d4fcb459b35cd64 100644
--- a/dbrepo-ui/components/database/DatabaseToolbar.vue
+++ b/dbrepo-ui/components/database/DatabaseToolbar.vue
@@ -135,6 +135,12 @@ export default {
       }
       return this.access.type === 'write_all' || this.access.type === 'write_own'
     },
+    hasReadAccess () {
+      if (!this.access) {
+        return false
+      }
+      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    },
     canImportCsv () {
       if (!this.user || !this.hasWriteAccess) {
         return false
@@ -142,10 +148,13 @@ export default {
       return this.roles.includes('insert-table-data')
     },
     canCreateSubset () {
-      if (!this.user) {
+      if (!this.database) {
         return false
       }
-      return this.roles.includes('execute-query')
+      if (this.database.is_public) {
+        return true
+      }
+      return this.hasReadAccess
     },
     canCreateView () {
       if (!this.user || !this.isOwner) {
diff --git a/dbrepo-ui/components/table/TableImport.vue b/dbrepo-ui/components/table/TableImport.vue
index 2451a7c3acb18722e8e4b0ebdb9fe10effcd554d..e55db4130e893810d22bf93ea4308c6e97a2b060 100644
--- a/dbrepo-ui/components/table/TableImport.vue
+++ b/dbrepo-ui/components/table/TableImport.vue
@@ -149,7 +149,8 @@
             <v-row
               v-if="step > 1 && suggestedAnalyseSeparator && providedSeparator !== analysedSeparator"
               dense>
-              <v-col>
+              <v-col
+                md="8">
                 <v-alert
                   border="start"
                   color="warning">
@@ -164,7 +165,8 @@
             <v-row
               v-if="step > 1 && suggestedAnalyseLineTerminator && providedTerminator !== analysedTerminator"
               dense>
-              <v-col>
+              <v-col
+                md="8">
                 <v-alert
                   border="start"
                   color="warning">
@@ -261,23 +263,20 @@
       direction="vertical">
       <v-container>
         <v-row
-          v-if="rowCount"
           dense>
           <v-col
             md="8">
             <v-alert
               border="start"
               color="success">
-              <span v-text="$t(`pages.table.subpages.import.summary.prefix`)"/>
-              <strong>&nbsp;{{ rowCount }}&nbsp;</strong>
-              <span v-text="$t('pages.table.subpages.import.summary.suffix')"/>
+              <span v-text="$t(`pages.table.subpages.import.summary.text`)"/>
             </v-alert>
           </v-col>
         </v-row>
         <v-row>
           <v-col>
             <v-btn
-              v-if="rowCount !== null"
+              v-if="step === 3"
               color="secondary"
               :disabled="step !== 3 || disabled"
               size="small"
@@ -457,10 +456,6 @@ export default {
           const toast = useToastInstance()
           toast.success(this.$t('success.import.dataset'))
           this.cacheStore.reloadDatabase()
-          tableService.getCount(this.$route.params.database_id, this.tableId, null)
-            .then((rowCount) => {
-              this.rowCount = rowCount
-            })
           this.step = 3
           this.validStep3 = true
           this.loadingImport = false
@@ -542,7 +537,7 @@ export default {
           this.$emit('analyse', {
             columns: this.columns,
             filename,
-            line_termination,
+            line_termination: line_termination === '\\n' ? '\n' : JSON.stringify(line_termination).replaceAll('"', ''),
             separator: this.tableImport.separator,
             skip_lines: this.tableImport.skip_lines,
             quote: this.tableImport.quote,
diff --git a/dbrepo-ui/components/table/TableSchema.vue b/dbrepo-ui/components/table/TableSchema.vue
index 25c4f66cb55993ff6e5f482b4bf63749021ec155..da30905fa30a9327ca90266bd2ee4088fab46c70 100644
--- a/dbrepo-ui/components/table/TableSchema.vue
+++ b/dbrepo-ui/components/table/TableSchema.vue
@@ -176,7 +176,7 @@
             variant="flat"
             size="small"
             :loading="loading"
-            :disabled="disabled || !valid || this.columns.length === 0"
+            :disabled="disabled || !valid || showPrimaryKeyWarning || this.columns.length === 0"
             :text="submitText"
             @click="submit" />
         </v-col>
diff --git a/dbrepo-ui/composables/query-service.ts b/dbrepo-ui/composables/query-service.ts
index abcd928b66d0350fd855ae380b959a33818b8f3d..f5d805b958f27676f7f1031bfe56af16721b4378 100644
--- a/dbrepo-ui/composables/query-service.ts
+++ b/dbrepo-ui/composables/query-service.ts
@@ -206,15 +206,15 @@ export const useQueryService = (): any => {
       {value: 'char', text: 'CHAR(size)', defaultSize: 1, defaultD: null, quoted: true, isBuildable: true},
       {value: 'date', text: 'DATE', defaultSize: null, defaultD: null, quoted: true, isBuildable: true},
       {value: 'datetime', text: 'DATETIME(fsp)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true},
-      {value: 'decimal', text: 'DECIMAL(size, d)', defaultSize: 10, defaultD: 4, quoted: false, isBuildable: true},
-      {value: 'double', text: 'DOUBLE(size, d)', defaultSize: 25, defaultD: 4, quoted: false, isBuildable: true},
+      {value: 'decimal', text: 'DECIMAL(size, d)', defaultSize: 40, defaultD: 10, quoted: false, isBuildable: true},
+      {value: 'double', text: 'DOUBLE(size, d)', defaultSize: 40, defaultD: 10, quoted: false, isBuildable: true},
       {value: 'enum', text: 'ENUM(val1,val2,...)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true},
       {value: 'float', text: 'FLOAT(p)', defaultSize: 24, defaultD: null, quoted: false, isBuildable: true},
       {value: 'int', text: 'INT(size)', defaultSize: 255, defaultD: null, quoted: false, isBuildable: true},
       {value: 'longblob', text: 'LONGBLOB', defaultSize: null, defaultD: null, quoted: false, isBuildable: false},
       {value: 'longtext', text: 'LONGTEXT', defaultSize: null, defaultD: null, quoted: true, isBuildable: true},
       {value: 'mediumblob', text: 'MEDIUMBLOB', defaultSize: null, defaultD: null, quoted: false, isBuildable: false},
-      {value: 'mediumint', text: 'MEDIUMINT(size)', defaultSize: 10, defaultD: null, quoted: false, isBuildable: true},
+      {value: 'mediumint', text: 'MEDIUMINT(size)', defaultSize: 40, defaultD: null, quoted: false, isBuildable: true},
       {value: 'mediumtext', text: 'MEDIUMTEXT', defaultSize: null, defaultD: null, quoted: true, isBuildable: true},
       {value: 'set', text: 'SET(val1,val2,...)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true},
       {value: 'smallint', text: 'SMALLINT(size)', defaultSize: 10, defaultD: null, quoted: false, isBuildable: true},
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index 41620761c58257affb380be4be741489c8f77ce8..fb4c40266b6dcc1f6f15a340cd400b8d4a0b3cd4 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -225,25 +225,21 @@ export default {
     },
   },
   watch: {
-    '$route.params.database_id': {
-      handler (newId, oldId) {
-        if (newId === oldId) {
+    '$route.params': {
+      handler (newObj, oldObj) {
+        if (!newObj.database_id) {
           return
         }
-        this.cacheStore.setRouteDatabase(newId)
+        /* load database and optional access */
+        this.cacheStore.setRouteDatabase(newObj.database_id)
         if (this.user) {
-          this.userStore.setRouteAccess(newId)
+          this.userStore.setRouteAccess(newObj.database_id)
         }
-      },
-      deep: true,
-      immediate: true
-    },
-    '$route.params.table_id': {
-      handler (newId, oldId) {
-        if (newId === oldId) {
+        if (!newObj.table_id) {
           return
         }
-        this.cacheStore.setRouteTable(this.$route.params.database_id, newId)
+        /* load table */
+        this.cacheStore.setRouteTable(newObj.database_id, newObj.table_id)
       },
       deep: true,
       immediate: true
diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json
index be8ddfcc2317d441d3a8b6edacd4b3f5a663c6af..c07ee7ac48b99bcd3ce0a9055fc1846c686c5789 100644
--- a/dbrepo-ui/locales/en-US.json
+++ b/dbrepo-ui/locales/en-US.json
@@ -332,7 +332,7 @@
             "title": "Dataset Structure",
             "text": "the table schema manually.",
             "primary": {
-              "warn": "No primary key column(s) selected. Please select a column that uniquely identifies data entries."
+              "warn": "No primary key column(s) selected. Please select one or more column(s) that uniquely identify data entries."
             }
           },
           "dataset": {
@@ -403,8 +403,7 @@
           },
           "summary": {
             "title": "Summary",
-            "prefix": "Imported",
-            "suffix": "rows from dataset"
+            "text": "Successfully imported dataset"
           },
           "analyse": {
             "text": "Upload & Analyse"
@@ -448,7 +447,7 @@
           }
         },
         "schema": {
-          "title": "System Versioned",
+          "title": "Schema",
           "subtitle": "Table Constraints",
           "bullet": "●",
           "assign": "Assign",
diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts
index 454cadf9090d23f92198c63e033ba7061221a29c..dc65c7ac3aca83cc1493bf69d20447273219c677 100644
--- a/dbrepo-ui/nuxt.config.ts
+++ b/dbrepo-ui/nuxt.config.ts
@@ -2,6 +2,7 @@ import { transformAssetUrls } from 'vite-plugin-vuetify'
 
 const proxy : any = {}
 
+/* proxies the backend calls, >>NOT<< the frontend calls (clicking) */
 if (process.env.NODE_ENV === 'development') {
   const api = 'http://localhost'
   proxy['/api'] = api
@@ -12,7 +13,7 @@ if (process.env.NODE_ENV === 'development') {
       '^/pid': '/pid'
     }
   }
-  process.env.NUXT_PUBLIC_API_SERVER = 'http://localhost'
+  process.env.NUXT_PUBLIC_API_SERVER = api
 }
 
 /**
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
index 62241db5050a1aebe1924cf6154d585fb1eb85e9..5202bc633626e135e263056fa39b5022676c1575 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
@@ -1,5 +1,5 @@
 <template>
-  <div v-if="canExecuteQuery">
+  <div v-if="canCreateSubset">
     <Builder />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
@@ -8,6 +8,7 @@
 <script>
 import { useUserStore } from '@/stores/user'
 import Builder from '@/components/subset/Builder.vue'
+import {useCacheStore} from "~/stores/cache.js";
 
 export default {
   components: {
@@ -34,6 +35,7 @@ export default {
           disabled: true
         }
       ],
+      cacheStore: useCacheStore(),
       userStore: useUserStore()
     }
   },
@@ -44,14 +46,26 @@ export default {
     roles () {
       return this.userStore.getRoles
     },
+    database () {
+      return this.cacheStore.getDatabase
+    },
     access () {
       return this.userStore.getAccess
     },
-    canExecuteQuery () {
-      if (!this.roles) {
+    hasReadAccess () {
+      if (!this.access) {
         return false
       }
-      return this.roles.includes('execute-query')
+      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    },
+    canCreateSubset () {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_public) {
+        return true
+      }
+      return this.hasReadAccess
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
index b60de5df3045d3f51bcbb2c203afdff18be87699..6642e89bf41e31326a42b5bae1e1100e0f04f5fb 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
@@ -20,6 +20,7 @@
           <v-stepper-header>
             <v-stepper-item
               :title="$t('pages.table.subpages.create.information.title')"
+              :complete="valid"
               :value="1" />
           </v-stepper-header>
           <v-stepper-window
diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js
index c733e8d48a4a3d77f4fce9eb9b1558db59d0306e..5004b1beb0170862f5062627656fcf6e8844dd7a 100644
--- a/dbrepo-ui/stores/cache.js
+++ b/dbrepo-ui/stores/cache.js
@@ -78,6 +78,7 @@ export const useCacheStore = defineStore('cache', {
     setRouteTable (databaseId, tableId) {
       if (!databaseId || !tableId) {
         this.table = null
+        console.error('Cannot set route table: missing database id', databaseId, 'or table id', tableId)
         return
       }
       const tableService = useTableService()
diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py
index fdae96e4904bab0a3b2142a4f45a9a5707cd37fc..7db044958a045c70568268b01eb7b1bccd901cd7 100644
--- a/lib/python/dbrepo/RestClient.py
+++ b/lib/python/dbrepo/RestClient.py
@@ -1588,7 +1588,7 @@ class RestClient:
         else:
             if timestamp is not None:
                 url += f'?timestamp={timestamp.strftime("%Y-%m-%dT%H:%M:%SZ")}'
-        response = self._wrapper(method="post", url=url, force_auth=True, headers={"Accept": "application/json"},
+        response = self._wrapper(method="post", url=url, headers={"Accept": "application/json"},
                                  payload=ExecuteQuery(statement=query))
         if response.status_code == 201:
             body = response.json()
diff --git a/lib/python/tests/test_unit_query.py b/lib/python/tests/test_unit_query.py
index d2de6f8278bc33a123cf38525493ec93532ce87a..e5448c8a3774e4625c9992ce9c09ff79a18b83a0 100644
--- a/lib/python/tests/test_unit_query.py
+++ b/lib/python/tests/test_unit_query.py
@@ -64,16 +64,19 @@ class QueryUnitTest(unittest.TestCase):
             except NotExistsError:
                 pass
 
-    def test_create_subset_not_auth_fails(self):
+    def test_create_subset_not_auth_succeeds(self):
         with requests_mock.Mocker() as mock:
+            exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
+                         headers=[{'id': 0, 'username': 1}],
+                         id=None)
             # mock
-            mock.post('/api/database/1/subset', status_code=417)
+            mock.post('/api/database/1/subset', json=exp.model_dump(), status_code=201)
             # test
-            try:
-                response = RestClient().create_subset(database_id=1,
-                                                      query="SELECT id, username FROM some_table WHERE id IN (1,2)")
-            except AuthenticationError:
-                pass
+
+            client = RestClient()
+            response = client.create_subset(database_id=1, page=0, size=10,
+                                            query="SELECT id, username FROM some_table WHERE id IN (1,2)")
+            self.assertEqual(exp, response)
 
     def test_find_query_succeeds(self):
         with requests_mock.Mocker() as mock: